tempest-react-sdk 0.78.0 → 0.79.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 (1585) hide show
  1. package/README.md +6 -6
  2. package/bin/lib/openapi/generate.mjs +168 -64
  3. package/bin/lib/openapi/generate.pagination.test.mjs +3 -2
  4. package/bin/lib/openapi/generate.test.mjs +263 -1
  5. package/dist/access/Can.cjs.map +1 -1
  6. package/dist/access/Can.js.map +1 -1
  7. package/dist/access/access-control-context.cjs.map +1 -1
  8. package/dist/access/access-control-context.js.map +1 -1
  9. package/dist/access/create-role-access-control.cjs.map +1 -1
  10. package/dist/access/create-role-access-control.js.map +1 -1
  11. package/dist/access/permissions-from-token.cjs.map +1 -1
  12. package/dist/access/permissions-from-token.js.map +1 -1
  13. package/dist/access/use-can.cjs.map +1 -1
  14. package/dist/access/use-can.js.map +1 -1
  15. package/dist/app/AppProviders.cjs.map +1 -1
  16. package/dist/app/AppProviders.js.map +1 -1
  17. package/dist/audio/audio-bus.cjs.map +1 -1
  18. package/dist/audio/audio-bus.js.map +1 -1
  19. package/dist/audio/audio-output.cjs.map +1 -1
  20. package/dist/audio/audio-output.js.map +1 -1
  21. package/dist/audio/audio-player.cjs.map +1 -1
  22. package/dist/audio/audio-player.js.map +1 -1
  23. package/dist/audio/audio-recorder.cjs.map +1 -1
  24. package/dist/audio/audio-recorder.js.map +1 -1
  25. package/dist/audio/duration.cjs.map +1 -1
  26. package/dist/audio/duration.js.map +1 -1
  27. package/dist/audio/level-meter.cjs.map +1 -1
  28. package/dist/audio/level-meter.js.map +1 -1
  29. package/dist/audio/media-access.cjs.map +1 -1
  30. package/dist/audio/media-access.js.map +1 -1
  31. package/dist/audio/noise-floor.cjs.map +1 -1
  32. package/dist/audio/noise-floor.js.map +1 -1
  33. package/dist/audio/sfx-pool.cjs.map +1 -1
  34. package/dist/audio/sfx-pool.js.map +1 -1
  35. package/dist/audio/use-audio-bus.cjs.map +1 -1
  36. package/dist/audio/use-audio-bus.js.map +1 -1
  37. package/dist/audio/use-audio-recorder.cjs.map +1 -1
  38. package/dist/audio/use-audio-recorder.js.map +1 -1
  39. package/dist/audio/use-audio.cjs.map +1 -1
  40. package/dist/audio/use-audio.js.map +1 -1
  41. package/dist/audio/use-microphone.cjs +1 -1
  42. package/dist/audio/use-microphone.cjs.map +1 -1
  43. package/dist/audio/use-microphone.js +1 -5
  44. package/dist/audio/use-microphone.js.map +1 -1
  45. package/dist/audio/use-sfx-pool.cjs.map +1 -1
  46. package/dist/audio/use-sfx-pool.js.map +1 -1
  47. package/dist/audio/voice-activity.cjs.map +1 -1
  48. package/dist/audio/voice-activity.js.map +1 -1
  49. package/dist/audio/voice-chain-stages.cjs.map +1 -1
  50. package/dist/audio/voice-chain-stages.js.map +1 -1
  51. package/dist/audio/voice-chain.cjs.map +1 -1
  52. package/dist/audio/voice-chain.js.map +1 -1
  53. package/dist/audio/wav.cjs.map +1 -1
  54. package/dist/audio/wav.js.map +1 -1
  55. package/dist/auth/AuthGuard.cjs.map +1 -1
  56. package/dist/auth/AuthGuard.js.map +1 -1
  57. package/dist/auth/create-auth-store.cjs.map +1 -1
  58. package/dist/auth/create-auth-store.js.map +1 -1
  59. package/dist/auth/create-tempest-auth.cjs +1 -1
  60. package/dist/auth/create-tempest-auth.cjs.map +1 -1
  61. package/dist/auth/create-tempest-auth.js +1 -3
  62. package/dist/auth/create-tempest-auth.js.map +1 -1
  63. package/dist/auth/jwt.cjs.map +1 -1
  64. package/dist/auth/jwt.js.map +1 -1
  65. package/dist/auth/lazy-with-retry.cjs.map +1 -1
  66. package/dist/auth/lazy-with-retry.js.map +1 -1
  67. package/dist/auth/passkey.cjs.map +1 -1
  68. package/dist/auth/passkey.js.map +1 -1
  69. package/dist/auth/refresh-queue.cjs.map +1 -1
  70. package/dist/auth/refresh-queue.js.map +1 -1
  71. package/dist/auth/use-passkey.cjs +1 -1
  72. package/dist/auth/use-passkey.cjs.map +1 -1
  73. package/dist/auth/use-passkey.js +1 -1
  74. package/dist/auth/use-passkey.js.map +1 -1
  75. package/dist/br/BrazilMap.cjs.map +1 -1
  76. package/dist/br/BrazilMap.js.map +1 -1
  77. package/dist/br/BrazilMap.module.cjs.map +1 -1
  78. package/dist/br/BrazilMap.module.js.map +1 -1
  79. package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
  80. package/dist/br/BrazilStateCitySelect.js.map +1 -1
  81. package/dist/br/BrazilStateMap.cjs.map +1 -1
  82. package/dist/br/BrazilStateMap.js.map +1 -1
  83. package/dist/br/MapLegend.cjs.map +1 -1
  84. package/dist/br/MapLegend.js.map +1 -1
  85. package/dist/br/MapLegend.module.cjs.map +1 -1
  86. package/dist/br/MapLegend.module.js.map +1 -1
  87. package/dist/br/MapMarkers.cjs.map +1 -1
  88. package/dist/br/MapMarkers.js.map +1 -1
  89. package/dist/br/MapTooltip.cjs.map +1 -1
  90. package/dist/br/MapTooltip.js.map +1 -1
  91. package/dist/br/MunicipalitySearch.cjs +1 -1
  92. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  93. package/dist/br/MunicipalitySearch.js +2 -5
  94. package/dist/br/MunicipalitySearch.js.map +1 -1
  95. package/dist/br/MunicipalitySearch.module.cjs.map +1 -1
  96. package/dist/br/MunicipalitySearch.module.js.map +1 -1
  97. package/dist/br/PixQRCode.cjs.map +1 -1
  98. package/dist/br/PixQRCode.js.map +1 -1
  99. package/dist/br/PixQRCode.module.cjs.map +1 -1
  100. package/dist/br/PixQRCode.module.js.map +1 -1
  101. package/dist/br/boleto.cjs.map +1 -1
  102. package/dist/br/boleto.js.map +1 -1
  103. package/dist/br/br-geo.cjs.map +1 -1
  104. package/dist/br/br-geo.js.map +1 -1
  105. package/dist/br/data/br-centroids.cjs.map +1 -1
  106. package/dist/br/data/br-centroids.js.map +1 -1
  107. package/dist/br/data/br-locations.cjs.map +1 -1
  108. package/dist/br/data/br-locations.js.map +1 -1
  109. package/dist/br/data/br-uf-geo.cjs.map +1 -1
  110. package/dist/br/data/br-uf-geo.js.map +1 -1
  111. package/dist/br/data/mun/AC.cjs.map +1 -1
  112. package/dist/br/data/mun/AC.js.map +1 -1
  113. package/dist/br/data/mun/AL.cjs.map +1 -1
  114. package/dist/br/data/mun/AL.js.map +1 -1
  115. package/dist/br/data/mun/AM.cjs.map +1 -1
  116. package/dist/br/data/mun/AM.js.map +1 -1
  117. package/dist/br/data/mun/AP.cjs.map +1 -1
  118. package/dist/br/data/mun/AP.js.map +1 -1
  119. package/dist/br/data/mun/BA.cjs.map +1 -1
  120. package/dist/br/data/mun/BA.js.map +1 -1
  121. package/dist/br/data/mun/CE.cjs.map +1 -1
  122. package/dist/br/data/mun/CE.js.map +1 -1
  123. package/dist/br/data/mun/DF.cjs.map +1 -1
  124. package/dist/br/data/mun/DF.js.map +1 -1
  125. package/dist/br/data/mun/ES.cjs.map +1 -1
  126. package/dist/br/data/mun/ES.js.map +1 -1
  127. package/dist/br/data/mun/GO.cjs.map +1 -1
  128. package/dist/br/data/mun/GO.js.map +1 -1
  129. package/dist/br/data/mun/MA.cjs.map +1 -1
  130. package/dist/br/data/mun/MA.js.map +1 -1
  131. package/dist/br/data/mun/MG.cjs.map +1 -1
  132. package/dist/br/data/mun/MG.js.map +1 -1
  133. package/dist/br/data/mun/MS.cjs.map +1 -1
  134. package/dist/br/data/mun/MS.js.map +1 -1
  135. package/dist/br/data/mun/MT.cjs.map +1 -1
  136. package/dist/br/data/mun/MT.js.map +1 -1
  137. package/dist/br/data/mun/PA.cjs.map +1 -1
  138. package/dist/br/data/mun/PA.js.map +1 -1
  139. package/dist/br/data/mun/PB.cjs.map +1 -1
  140. package/dist/br/data/mun/PB.js.map +1 -1
  141. package/dist/br/data/mun/PE.cjs.map +1 -1
  142. package/dist/br/data/mun/PE.js.map +1 -1
  143. package/dist/br/data/mun/PI.cjs.map +1 -1
  144. package/dist/br/data/mun/PI.js.map +1 -1
  145. package/dist/br/data/mun/PR.cjs.map +1 -1
  146. package/dist/br/data/mun/PR.js.map +1 -1
  147. package/dist/br/data/mun/RJ.cjs.map +1 -1
  148. package/dist/br/data/mun/RJ.js.map +1 -1
  149. package/dist/br/data/mun/RN.cjs.map +1 -1
  150. package/dist/br/data/mun/RN.js.map +1 -1
  151. package/dist/br/data/mun/RO.cjs.map +1 -1
  152. package/dist/br/data/mun/RO.js.map +1 -1
  153. package/dist/br/data/mun/RR.cjs.map +1 -1
  154. package/dist/br/data/mun/RR.js.map +1 -1
  155. package/dist/br/data/mun/RS.cjs.map +1 -1
  156. package/dist/br/data/mun/RS.js.map +1 -1
  157. package/dist/br/data/mun/SC.cjs.map +1 -1
  158. package/dist/br/data/mun/SC.js.map +1 -1
  159. package/dist/br/data/mun/SE.cjs.map +1 -1
  160. package/dist/br/data/mun/SE.js.map +1 -1
  161. package/dist/br/data/mun/SP.cjs.map +1 -1
  162. package/dist/br/data/mun/SP.js.map +1 -1
  163. package/dist/br/data/mun/TO.cjs.map +1 -1
  164. package/dist/br/data/mun/TO.js.map +1 -1
  165. package/dist/br/geocode.cjs.map +1 -1
  166. package/dist/br/geocode.js.map +1 -1
  167. package/dist/br/holidays.cjs.map +1 -1
  168. package/dist/br/holidays.js.map +1 -1
  169. package/dist/br/locations.cjs.map +1 -1
  170. package/dist/br/locations.js.map +1 -1
  171. package/dist/br/nfe.cjs.map +1 -1
  172. package/dist/br/nfe.js.map +1 -1
  173. package/dist/br/pix.cjs +1 -1
  174. package/dist/br/pix.cjs.map +1 -1
  175. package/dist/br/pix.js +108 -74
  176. package/dist/br/pix.js.map +1 -1
  177. package/dist/br/regions.cjs.map +1 -1
  178. package/dist/br/regions.js.map +1 -1
  179. package/dist/br/scales.cjs.map +1 -1
  180. package/dist/br/scales.js.map +1 -1
  181. package/dist/br/state-geo.cjs.map +1 -1
  182. package/dist/br/state-geo.js.map +1 -1
  183. package/dist/br/svg-utils.cjs.map +1 -1
  184. package/dist/br/svg-utils.js.map +1 -1
  185. package/dist/br/use-map-hover.cjs.map +1 -1
  186. package/dist/br/use-map-hover.js.map +1 -1
  187. package/dist/br/use-map-zoom.cjs.map +1 -1
  188. package/dist/br/use-map-zoom.js.map +1 -1
  189. package/dist/br/whatsapp.cjs.map +1 -1
  190. package/dist/br/whatsapp.js.map +1 -1
  191. package/dist/br.cjs.map +1 -1
  192. package/dist/br.d.ts +6 -2
  193. package/dist/br.js.map +1 -1
  194. package/dist/capture/barcode.cjs.map +1 -1
  195. package/dist/capture/barcode.js.map +1 -1
  196. package/dist/capture/media-recorder.cjs.map +1 -1
  197. package/dist/capture/media-recorder.js.map +1 -1
  198. package/dist/capture/use-barcode-scanner.cjs.map +1 -1
  199. package/dist/capture/use-barcode-scanner.js.map +1 -1
  200. package/dist/capture/use-screen-capture.cjs +1 -1
  201. package/dist/capture/use-screen-capture.cjs.map +1 -1
  202. package/dist/capture/use-screen-capture.js +1 -7
  203. package/dist/capture/use-screen-capture.js.map +1 -1
  204. package/dist/capture/use-speech-recognition.cjs +1 -1
  205. package/dist/capture/use-speech-recognition.cjs.map +1 -1
  206. package/dist/capture/use-speech-recognition.js +35 -36
  207. package/dist/capture/use-speech-recognition.js.map +1 -1
  208. package/dist/capture/use-torch.cjs.map +1 -1
  209. package/dist/capture/use-torch.js.map +1 -1
  210. package/dist/capture/use-video-recorder.cjs.map +1 -1
  211. package/dist/capture/use-video-recorder.js.map +1 -1
  212. package/dist/capture/video-recorder.cjs.map +1 -1
  213. package/dist/capture/video-recorder.js.map +1 -1
  214. package/dist/charts/AreaChart.cjs.map +1 -1
  215. package/dist/charts/AreaChart.js.map +1 -1
  216. package/dist/charts/BarChart.cjs.map +1 -1
  217. package/dist/charts/BarChart.js.map +1 -1
  218. package/dist/charts/LineChart.cjs.map +1 -1
  219. package/dist/charts/LineChart.js.map +1 -1
  220. package/dist/charts/PieChart.cjs.map +1 -1
  221. package/dist/charts/PieChart.js.map +1 -1
  222. package/dist/charts/RadarChart.cjs.map +1 -1
  223. package/dist/charts/RadarChart.js.map +1 -1
  224. package/dist/charts/palette.cjs.map +1 -1
  225. package/dist/charts/palette.js.map +1 -1
  226. package/dist/charts/scales.cjs.map +1 -1
  227. package/dist/charts/scales.js.map +1 -1
  228. package/dist/charts/types.cjs.map +1 -1
  229. package/dist/charts/types.js.map +1 -1
  230. package/dist/charts/use-chart-colors.cjs.map +1 -1
  231. package/dist/charts/use-chart-colors.js.map +1 -1
  232. package/dist/components/AIChat/AIChat.cjs +1 -1
  233. package/dist/components/AIChat/AIChat.cjs.map +1 -1
  234. package/dist/components/AIChat/AIChat.js +1 -5
  235. package/dist/components/AIChat/AIChat.js.map +1 -1
  236. package/dist/components/AIChat/AIChat.module.cjs.map +1 -1
  237. package/dist/components/AIChat/AIChat.module.js.map +1 -1
  238. package/dist/components/AIChat/AIChatComposer.cjs +1 -1
  239. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
  240. package/dist/components/AIChat/AIChatComposer.js +1 -7
  241. package/dist/components/AIChat/AIChatComposer.js.map +1 -1
  242. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
  243. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  244. package/dist/components/AIChat/ai-chat-turns.cjs.map +1 -1
  245. package/dist/components/AIChat/ai-chat-turns.js.map +1 -1
  246. package/dist/components/Accordion/Accordion.cjs.map +1 -1
  247. package/dist/components/Accordion/Accordion.js.map +1 -1
  248. package/dist/components/Accordion/Accordion.module.cjs.map +1 -1
  249. package/dist/components/Accordion/Accordion.module.js.map +1 -1
  250. package/dist/components/Alert/Alert.cjs.map +1 -1
  251. package/dist/components/Alert/Alert.js.map +1 -1
  252. package/dist/components/Alert/Alert.module.cjs.map +1 -1
  253. package/dist/components/Alert/Alert.module.js.map +1 -1
  254. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  255. package/dist/components/AppBar/AppBar.js.map +1 -1
  256. package/dist/components/AppBar/AppBar.module.cjs.map +1 -1
  257. package/dist/components/AppBar/AppBar.module.js.map +1 -1
  258. package/dist/components/AppBar/use-sticky-body-warning.cjs +1 -1
  259. package/dist/components/AppBar/use-sticky-body-warning.cjs.map +1 -1
  260. package/dist/components/AppBar/use-sticky-body-warning.js +1 -1
  261. package/dist/components/AppBar/use-sticky-body-warning.js.map +1 -1
  262. package/dist/components/AppShell/AppShell.cjs.map +1 -1
  263. package/dist/components/AppShell/AppShell.js.map +1 -1
  264. package/dist/components/AppShell/AppShell.module.cjs.map +1 -1
  265. package/dist/components/AppShell/AppShell.module.js.map +1 -1
  266. package/dist/components/AspectRatio/AspectRatio.cjs.map +1 -1
  267. package/dist/components/AspectRatio/AspectRatio.js.map +1 -1
  268. package/dist/components/AspectRatio/AspectRatio.module.cjs.map +1 -1
  269. package/dist/components/AspectRatio/AspectRatio.module.js.map +1 -1
  270. package/dist/components/AudioPlayer/AudioPlayer.cjs +1 -1
  271. package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
  272. package/dist/components/AudioPlayer/AudioPlayer.js +1 -7
  273. package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
  274. package/dist/components/AudioPlayer/AudioPlayer.module.cjs.map +1 -1
  275. package/dist/components/AudioPlayer/AudioPlayer.module.js.map +1 -1
  276. package/dist/components/AudioRecorder/AudioRecorder.cjs +1 -1
  277. package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
  278. package/dist/components/AudioRecorder/AudioRecorder.js +16 -21
  279. package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
  280. package/dist/components/AudioRecorder/AudioRecorder.module.cjs.map +1 -1
  281. package/dist/components/AudioRecorder/AudioRecorder.module.js.map +1 -1
  282. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  283. package/dist/components/Avatar/Avatar.js.map +1 -1
  284. package/dist/components/Avatar/Avatar.module.cjs.map +1 -1
  285. package/dist/components/Avatar/Avatar.module.js.map +1 -1
  286. package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
  287. package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
  288. package/dist/components/AvatarGroup/AvatarGroup.module.cjs.map +1 -1
  289. package/dist/components/AvatarGroup/AvatarGroup.module.js.map +1 -1
  290. package/dist/components/Badge/Badge.cjs.map +1 -1
  291. package/dist/components/Badge/Badge.js.map +1 -1
  292. package/dist/components/Badge/Badge.module.cjs.map +1 -1
  293. package/dist/components/Badge/Badge.module.js.map +1 -1
  294. package/dist/components/Banner/Banner.cjs.map +1 -1
  295. package/dist/components/Banner/Banner.js.map +1 -1
  296. package/dist/components/Banner/Banner.module.cjs.map +1 -1
  297. package/dist/components/Banner/Banner.module.js.map +1 -1
  298. package/dist/components/BarList/BarList.cjs.map +1 -1
  299. package/dist/components/BarList/BarList.js.map +1 -1
  300. package/dist/components/BarList/BarList.module.cjs.map +1 -1
  301. package/dist/components/BarList/BarList.module.js.map +1 -1
  302. package/dist/components/BarList/bar-list-model.cjs.map +1 -1
  303. package/dist/components/BarList/bar-list-model.js.map +1 -1
  304. package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
  305. package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
  306. package/dist/components/BarcodeScanner/BarcodeScanner.module.cjs.map +1 -1
  307. package/dist/components/BarcodeScanner/BarcodeScanner.module.js.map +1 -1
  308. package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
  309. package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
  310. package/dist/components/BottomNavigation/BottomNavigation.module.cjs.map +1 -1
  311. package/dist/components/BottomNavigation/BottomNavigation.module.js.map +1 -1
  312. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  313. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  314. package/dist/components/BottomSheet/BottomSheet.module.cjs.map +1 -1
  315. package/dist/components/BottomSheet/BottomSheet.module.js.map +1 -1
  316. package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
  317. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  318. package/dist/components/Breadcrumbs/Breadcrumbs.module.cjs.map +1 -1
  319. package/dist/components/Breadcrumbs/Breadcrumbs.module.js.map +1 -1
  320. package/dist/components/Button/Button.cjs.map +1 -1
  321. package/dist/components/Button/Button.js.map +1 -1
  322. package/dist/components/Button/Button.module.cjs.map +1 -1
  323. package/dist/components/Button/Button.module.js.map +1 -1
  324. package/dist/components/Button/ButtonContent.cjs.map +1 -1
  325. package/dist/components/Button/ButtonContent.js.map +1 -1
  326. package/dist/components/Button/ButtonSlot.cjs.map +1 -1
  327. package/dist/components/Button/ButtonSlot.js.map +1 -1
  328. package/dist/components/Button/button-class.cjs.map +1 -1
  329. package/dist/components/Button/button-class.js.map +1 -1
  330. package/dist/components/Button/link-rel.cjs.map +1 -1
  331. package/dist/components/Button/link-rel.js.map +1 -1
  332. package/dist/components/Button/slot.cjs.map +1 -1
  333. package/dist/components/Button/slot.js.map +1 -1
  334. package/dist/components/Calendar/Calendar.cjs.map +1 -1
  335. package/dist/components/Calendar/Calendar.js.map +1 -1
  336. package/dist/components/Calendar/Calendar.module.cjs.map +1 -1
  337. package/dist/components/Calendar/Calendar.module.js.map +1 -1
  338. package/dist/components/Card/Card.cjs.map +1 -1
  339. package/dist/components/Card/Card.js.map +1 -1
  340. package/dist/components/Card/Card.module.cjs.map +1 -1
  341. package/dist/components/Card/Card.module.js.map +1 -1
  342. package/dist/components/Carousel/Carousel.cjs.map +1 -1
  343. package/dist/components/Carousel/Carousel.js.map +1 -1
  344. package/dist/components/Carousel/Carousel.module.cjs.map +1 -1
  345. package/dist/components/Carousel/Carousel.module.js.map +1 -1
  346. package/dist/components/Center/Center.cjs.map +1 -1
  347. package/dist/components/Center/Center.js.map +1 -1
  348. package/dist/components/Center/Center.module.cjs.map +1 -1
  349. package/dist/components/Center/Center.module.js.map +1 -1
  350. package/dist/components/Chat/Chat.cjs.map +1 -1
  351. package/dist/components/Chat/Chat.js.map +1 -1
  352. package/dist/components/Chat/Chat.module.cjs.map +1 -1
  353. package/dist/components/Chat/Chat.module.js.map +1 -1
  354. package/dist/components/Chat/ChatActionsMenu.cjs.map +1 -1
  355. package/dist/components/Chat/ChatActionsMenu.js.map +1 -1
  356. package/dist/components/Chat/ChatAttachments.cjs.map +1 -1
  357. package/dist/components/Chat/ChatAttachments.js.map +1 -1
  358. package/dist/components/Chat/ChatBubble.cjs.map +1 -1
  359. package/dist/components/Chat/ChatBubble.js.map +1 -1
  360. package/dist/components/Chat/ChatComposer.cjs.map +1 -1
  361. package/dist/components/Chat/ChatComposer.js.map +1 -1
  362. package/dist/components/Chat/chat-groups.cjs +1 -1
  363. package/dist/components/Chat/chat-groups.cjs.map +1 -1
  364. package/dist/components/Chat/chat-groups.js +2 -6
  365. package/dist/components/Chat/chat-groups.js.map +1 -1
  366. package/dist/components/Chat/chat-receipt.cjs.map +1 -1
  367. package/dist/components/Chat/chat-receipt.js.map +1 -1
  368. package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
  369. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  370. package/dist/components/Checkbox/Checkbox.module.cjs.map +1 -1
  371. package/dist/components/Checkbox/Checkbox.module.js.map +1 -1
  372. package/dist/components/ChipInput/ChipInput.cjs +1 -1
  373. package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
  374. package/dist/components/ChipInput/ChipInput.js +2 -12
  375. package/dist/components/ChipInput/ChipInput.js.map +1 -1
  376. package/dist/components/ChipInput/ChipInput.module.cjs.map +1 -1
  377. package/dist/components/ChipInput/ChipInput.module.js.map +1 -1
  378. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  379. package/dist/components/ClickOutside/ClickOutside.js.map +1 -1
  380. package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
  381. package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
  382. package/dist/components/CodeBlock/CodeBlock.module.cjs.map +1 -1
  383. package/dist/components/CodeBlock/CodeBlock.module.js.map +1 -1
  384. package/dist/components/CodeBlock/tokenize.cjs.map +1 -1
  385. package/dist/components/CodeBlock/tokenize.js.map +1 -1
  386. package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
  387. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  388. package/dist/components/Collapsible/Collapsible.module.cjs.map +1 -1
  389. package/dist/components/Collapsible/Collapsible.module.js.map +1 -1
  390. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  391. package/dist/components/Combobox/Combobox.js.map +1 -1
  392. package/dist/components/Combobox/Combobox.module.cjs.map +1 -1
  393. package/dist/components/Combobox/Combobox.module.js.map +1 -1
  394. package/dist/components/Combobox/use-listbox-dismiss.cjs.map +1 -1
  395. package/dist/components/Combobox/use-listbox-dismiss.js.map +1 -1
  396. package/dist/components/Command/Command.cjs +1 -1
  397. package/dist/components/Command/Command.cjs.map +1 -1
  398. package/dist/components/Command/Command.js +4 -11
  399. package/dist/components/Command/Command.js.map +1 -1
  400. package/dist/components/Command/Command.module.cjs.map +1 -1
  401. package/dist/components/Command/Command.module.js.map +1 -1
  402. package/dist/components/ConditionalWrapper/ConditionalWrapper.cjs.map +1 -1
  403. package/dist/components/ConditionalWrapper/ConditionalWrapper.js.map +1 -1
  404. package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
  405. package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
  406. package/dist/components/ContextMenu/ContextMenu.cjs +1 -1
  407. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  408. package/dist/components/ContextMenu/ContextMenu.js +1 -1
  409. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  410. package/dist/components/ContextMenu/ContextMenu.module.cjs.map +1 -1
  411. package/dist/components/ContextMenu/ContextMenu.module.js.map +1 -1
  412. package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
  413. package/dist/components/CopyButton/CopyButton.js.map +1 -1
  414. package/dist/components/CopyButton/CopyButton.module.cjs.map +1 -1
  415. package/dist/components/CopyButton/CopyButton.module.js.map +1 -1
  416. package/dist/components/DataList/DataList.cjs.map +1 -1
  417. package/dist/components/DataList/DataList.js.map +1 -1
  418. package/dist/components/DataList/DataList.module.cjs.map +1 -1
  419. package/dist/components/DataList/DataList.module.js.map +1 -1
  420. package/dist/components/DataTable/DataTable.cjs +1 -1
  421. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  422. package/dist/components/DataTable/DataTable.js +6 -14
  423. package/dist/components/DataTable/DataTable.js.map +1 -1
  424. package/dist/components/DataTable/DataTable.module.cjs.map +1 -1
  425. package/dist/components/DataTable/DataTable.module.js.map +1 -1
  426. package/dist/components/DataTable/EditableCell.cjs +1 -1
  427. package/dist/components/DataTable/EditableCell.cjs.map +1 -1
  428. package/dist/components/DataTable/EditableCell.js +1 -9
  429. package/dist/components/DataTable/EditableCell.js.map +1 -1
  430. package/dist/components/DataTable/LoadingRows.cjs.map +1 -1
  431. package/dist/components/DataTable/LoadingRows.js.map +1 -1
  432. package/dist/components/DataTable/edit-labels.cjs.map +1 -1
  433. package/dist/components/DataTable/edit-labels.js.map +1 -1
  434. package/dist/components/DataTable/use-dev-warnings.cjs.map +1 -1
  435. package/dist/components/DataTable/use-dev-warnings.js.map +1 -1
  436. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  437. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  438. package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
  439. package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
  440. package/dist/components/DateRangePicker/DateRangePicker.module.cjs.map +1 -1
  441. package/dist/components/DateRangePicker/DateRangePicker.module.js.map +1 -1
  442. package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
  443. package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
  444. package/dist/components/DescriptionList/DescriptionList.module.cjs.map +1 -1
  445. package/dist/components/DescriptionList/DescriptionList.module.js.map +1 -1
  446. package/dist/components/Divider/Divider.cjs.map +1 -1
  447. package/dist/components/Divider/Divider.js.map +1 -1
  448. package/dist/components/Divider/Divider.module.cjs.map +1 -1
  449. package/dist/components/Divider/Divider.module.js.map +1 -1
  450. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  451. package/dist/components/Drawer/Drawer.js.map +1 -1
  452. package/dist/components/Drawer/Drawer.module.cjs.map +1 -1
  453. package/dist/components/Drawer/Drawer.module.js.map +1 -1
  454. package/dist/components/DropdownMenu/DropdownMenu.cjs +1 -1
  455. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  456. package/dist/components/DropdownMenu/DropdownMenu.js +2 -14
  457. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  458. package/dist/components/DropdownMenu/DropdownMenu.module.cjs.map +1 -1
  459. package/dist/components/DropdownMenu/DropdownMenu.module.js.map +1 -1
  460. package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
  461. package/dist/components/Dropzone/Dropzone.js.map +1 -1
  462. package/dist/components/Dropzone/Dropzone.module.cjs.map +1 -1
  463. package/dist/components/Dropzone/Dropzone.module.js.map +1 -1
  464. package/dist/components/EmptyState/EmptyState.cjs.map +1 -1
  465. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  466. package/dist/components/EmptyState/EmptyState.module.cjs.map +1 -1
  467. package/dist/components/EmptyState/EmptyState.module.js.map +1 -1
  468. package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
  469. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  470. package/dist/components/ErrorState/ErrorState.module.cjs.map +1 -1
  471. package/dist/components/ErrorState/ErrorState.module.js.map +1 -1
  472. package/dist/components/ErrorText/ErrorText.cjs.map +1 -1
  473. package/dist/components/ErrorText/ErrorText.js.map +1 -1
  474. package/dist/components/ErrorText/ErrorText.module.cjs.map +1 -1
  475. package/dist/components/ErrorText/ErrorText.module.js.map +1 -1
  476. package/dist/components/FileUpload/FileUpload.cjs +1 -1
  477. package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
  478. package/dist/components/FileUpload/FileUpload.js +7 -17
  479. package/dist/components/FileUpload/FileUpload.js.map +1 -1
  480. package/dist/components/FileUpload/FileUpload.module.cjs.map +1 -1
  481. package/dist/components/FileUpload/FileUpload.module.js.map +1 -1
  482. package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
  483. package/dist/components/FilterBar/FilterBar.js.map +1 -1
  484. package/dist/components/FilterBar/FilterBar.module.cjs.map +1 -1
  485. package/dist/components/FilterBar/FilterBar.module.js.map +1 -1
  486. package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
  487. package/dist/components/FilterBar/filter-apply.js.map +1 -1
  488. package/dist/components/FilterBar/filter-model.cjs.map +1 -1
  489. package/dist/components/FilterBar/filter-model.js.map +1 -1
  490. package/dist/components/FilterBar/filter-query.cjs +1 -1
  491. package/dist/components/FilterBar/filter-query.cjs.map +1 -1
  492. package/dist/components/FilterBar/filter-query.js +2 -5
  493. package/dist/components/FilterBar/filter-query.js.map +1 -1
  494. package/dist/components/FilterPanel/FilterPanel.cjs.map +1 -1
  495. package/dist/components/FilterPanel/FilterPanel.js.map +1 -1
  496. package/dist/components/FilterPanel/FilterPanel.module.cjs.map +1 -1
  497. package/dist/components/FilterPanel/FilterPanel.module.js.map +1 -1
  498. package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
  499. package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
  500. package/dist/components/FloatingActionButton/FloatingActionButton.module.cjs.map +1 -1
  501. package/dist/components/FloatingActionButton/FloatingActionButton.module.js.map +1 -1
  502. package/dist/components/For/For.cjs.map +1 -1
  503. package/dist/components/For/For.js.map +1 -1
  504. package/dist/components/Form/Form.cjs.map +1 -1
  505. package/dist/components/Form/Form.js.map +1 -1
  506. package/dist/components/Form/Form.module.cjs.map +1 -1
  507. package/dist/components/Form/Form.module.js.map +1 -1
  508. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  509. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  510. package/dist/components/HoverCard/HoverCard.module.cjs.map +1 -1
  511. package/dist/components/HoverCard/HoverCard.module.js.map +1 -1
  512. package/dist/components/Image/Image.cjs.map +1 -1
  513. package/dist/components/Image/Image.js.map +1 -1
  514. package/dist/components/Image/Image.module.cjs.map +1 -1
  515. package/dist/components/Image/Image.module.js.map +1 -1
  516. package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
  517. package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
  518. package/dist/components/ImageCropper/ImageCropper.js +4 -8
  519. package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
  520. package/dist/components/ImageCropper/ImageCropper.module.cjs.map +1 -1
  521. package/dist/components/ImageCropper/ImageCropper.module.js.map +1 -1
  522. package/dist/components/ImageCropper/crop-geometry.cjs.map +1 -1
  523. package/dist/components/ImageCropper/crop-geometry.js.map +1 -1
  524. package/dist/components/Input/Input.cjs.map +1 -1
  525. package/dist/components/Input/Input.js.map +1 -1
  526. package/dist/components/Input/Input.module.cjs.map +1 -1
  527. package/dist/components/Input/Input.module.js.map +1 -1
  528. package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
  529. package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
  530. package/dist/components/InstallBanner/InstallBanner.module.cjs.map +1 -1
  531. package/dist/components/InstallBanner/InstallBanner.module.js.map +1 -1
  532. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  533. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  534. package/dist/components/InstallButton/InstallButton.module.cjs.map +1 -1
  535. package/dist/components/InstallButton/InstallButton.module.js.map +1 -1
  536. package/dist/components/InstallButton/install-hints.cjs.map +1 -1
  537. package/dist/components/InstallButton/install-hints.js.map +1 -1
  538. package/dist/components/Kanban/Kanban.cjs.map +1 -1
  539. package/dist/components/Kanban/Kanban.js.map +1 -1
  540. package/dist/components/Kanban/Kanban.module.cjs.map +1 -1
  541. package/dist/components/Kanban/Kanban.module.js.map +1 -1
  542. package/dist/components/Kbd/Kbd.cjs.map +1 -1
  543. package/dist/components/Kbd/Kbd.js.map +1 -1
  544. package/dist/components/Kbd/Kbd.module.cjs.map +1 -1
  545. package/dist/components/Kbd/Kbd.module.js.map +1 -1
  546. package/dist/components/Label/Label.cjs.map +1 -1
  547. package/dist/components/Label/Label.js.map +1 -1
  548. package/dist/components/Label/Label.module.cjs.map +1 -1
  549. package/dist/components/Label/Label.module.js.map +1 -1
  550. package/dist/components/Layout/Layout.cjs.map +1 -1
  551. package/dist/components/Layout/Layout.js.map +1 -1
  552. package/dist/components/Layout/Layout.module.cjs.map +1 -1
  553. package/dist/components/Layout/Layout.module.js.map +1 -1
  554. package/dist/components/Lightbox/Lightbox.cjs +1 -1
  555. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  556. package/dist/components/Lightbox/Lightbox.js +1 -1
  557. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  558. package/dist/components/Lightbox/Lightbox.module.cjs.map +1 -1
  559. package/dist/components/Lightbox/Lightbox.module.js.map +1 -1
  560. package/dist/components/ListTile/ListTile.cjs.map +1 -1
  561. package/dist/components/ListTile/ListTile.js.map +1 -1
  562. package/dist/components/ListTile/ListTile.module.cjs.map +1 -1
  563. package/dist/components/ListTile/ListTile.module.js.map +1 -1
  564. package/dist/components/Markdown/Markdown.cjs.map +1 -1
  565. package/dist/components/Markdown/Markdown.js.map +1 -1
  566. package/dist/components/Markdown/Markdown.module.cjs.map +1 -1
  567. package/dist/components/Markdown/Markdown.module.js.map +1 -1
  568. package/dist/components/Markdown/markdown-parse.cjs +2 -2
  569. package/dist/components/Markdown/markdown-parse.cjs.map +1 -1
  570. package/dist/components/Markdown/markdown-parse.js +8 -27
  571. package/dist/components/Markdown/markdown-parse.js.map +1 -1
  572. package/dist/components/Masonry/Masonry.cjs.map +1 -1
  573. package/dist/components/Masonry/Masonry.js.map +1 -1
  574. package/dist/components/Masonry/Masonry.module.cjs.map +1 -1
  575. package/dist/components/Masonry/Masonry.module.js.map +1 -1
  576. package/dist/components/Masonry/masonry-layout.cjs.map +1 -1
  577. package/dist/components/Masonry/masonry-layout.js.map +1 -1
  578. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  579. package/dist/components/Menubar/Menubar.js.map +1 -1
  580. package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
  581. package/dist/components/Menubar/Menubar.module.js.map +1 -1
  582. package/dist/components/Modal/Modal.cjs.map +1 -1
  583. package/dist/components/Modal/Modal.js.map +1 -1
  584. package/dist/components/Modal/Modal.module.cjs.map +1 -1
  585. package/dist/components/Modal/Modal.module.js.map +1 -1
  586. package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
  587. package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
  588. package/dist/components/ModalsManager/ModalsManager.module.cjs.map +1 -1
  589. package/dist/components/ModalsManager/ModalsManager.module.js.map +1 -1
  590. package/dist/components/Money/Money.cjs.map +1 -1
  591. package/dist/components/Money/Money.js.map +1 -1
  592. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  593. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  594. package/dist/components/MultiSelect/MultiSelect.module.cjs.map +1 -1
  595. package/dist/components/MultiSelect/MultiSelect.module.js.map +1 -1
  596. package/dist/components/NProgress/NProgress.cjs.map +1 -1
  597. package/dist/components/NProgress/NProgress.js.map +1 -1
  598. package/dist/components/NProgress/NProgress.module.cjs.map +1 -1
  599. package/dist/components/NProgress/NProgress.module.js.map +1 -1
  600. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  601. package/dist/components/Navbar/Navbar.js.map +1 -1
  602. package/dist/components/Navbar/Navbar.module.cjs.map +1 -1
  603. package/dist/components/Navbar/Navbar.module.js.map +1 -1
  604. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  605. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  606. package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
  607. package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
  608. package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
  609. package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
  610. package/dist/components/NavigationRail/NavigationRail.module.cjs.map +1 -1
  611. package/dist/components/NavigationRail/NavigationRail.module.js.map +1 -1
  612. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
  613. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
  614. package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -1
  615. package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -1
  616. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
  617. package/dist/components/NotificationCenter/use-notification-inbox.js.map +1 -1
  618. package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
  619. package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
  620. package/dist/components/OfflineIndicator/OfflineIndicator.module.cjs.map +1 -1
  621. package/dist/components/OfflineIndicator/OfflineIndicator.module.js.map +1 -1
  622. package/dist/components/Page/Page.cjs.map +1 -1
  623. package/dist/components/Page/Page.js.map +1 -1
  624. package/dist/components/Page/Page.module.cjs.map +1 -1
  625. package/dist/components/Page/Page.module.js.map +1 -1
  626. package/dist/components/Pagination/Pagination.cjs.map +1 -1
  627. package/dist/components/Pagination/Pagination.js.map +1 -1
  628. package/dist/components/Pagination/Pagination.module.cjs.map +1 -1
  629. package/dist/components/Pagination/Pagination.module.js.map +1 -1
  630. package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
  631. package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
  632. package/dist/components/PasswordInput/PasswordInput.module.cjs.map +1 -1
  633. package/dist/components/PasswordInput/PasswordInput.module.js.map +1 -1
  634. package/dist/components/PinInput/PinInput.cjs.map +1 -1
  635. package/dist/components/PinInput/PinInput.js.map +1 -1
  636. package/dist/components/PinInput/PinInput.module.cjs.map +1 -1
  637. package/dist/components/PinInput/PinInput.module.js.map +1 -1
  638. package/dist/components/Popover/Popover.cjs.map +1 -1
  639. package/dist/components/Popover/Popover.js.map +1 -1
  640. package/dist/components/Popover/Popover.module.cjs.map +1 -1
  641. package/dist/components/Popover/Popover.module.js.map +1 -1
  642. package/dist/components/Portal/Portal.cjs.map +1 -1
  643. package/dist/components/Portal/Portal.js.map +1 -1
  644. package/dist/components/Portal/anchor-position.cjs.map +1 -1
  645. package/dist/components/Portal/anchor-position.js.map +1 -1
  646. package/dist/components/Portal/escape-layer.cjs.map +1 -1
  647. package/dist/components/Portal/escape-layer.js.map +1 -1
  648. package/dist/components/Portal/portal-host.cjs.map +1 -1
  649. package/dist/components/Portal/portal-host.js.map +1 -1
  650. package/dist/components/Portal/tab-bridge.cjs +1 -1
  651. package/dist/components/Portal/tab-bridge.cjs.map +1 -1
  652. package/dist/components/Portal/tab-bridge.js +1 -5
  653. package/dist/components/Portal/tab-bridge.js.map +1 -1
  654. package/dist/components/Progress/Progress.cjs.map +1 -1
  655. package/dist/components/Progress/Progress.js.map +1 -1
  656. package/dist/components/Progress/Progress.module.cjs.map +1 -1
  657. package/dist/components/Progress/Progress.module.js.map +1 -1
  658. package/dist/components/QRCode/QRCode.cjs.map +1 -1
  659. package/dist/components/QRCode/QRCode.js.map +1 -1
  660. package/dist/components/QRCode/QRCode.module.cjs.map +1 -1
  661. package/dist/components/QRCode/QRCode.module.js.map +1 -1
  662. package/dist/components/QRCode/qr-encode.cjs +1 -1
  663. package/dist/components/QRCode/qr-encode.cjs.map +1 -1
  664. package/dist/components/QRCode/qr-encode.js +7 -13
  665. package/dist/components/QRCode/qr-encode.js.map +1 -1
  666. package/dist/components/QRCode/qr-tables.cjs.map +1 -1
  667. package/dist/components/QRCode/qr-tables.js.map +1 -1
  668. package/dist/components/Radio/Radio.cjs.map +1 -1
  669. package/dist/components/Radio/Radio.js.map +1 -1
  670. package/dist/components/Radio/Radio.module.cjs.map +1 -1
  671. package/dist/components/Radio/Radio.module.js.map +1 -1
  672. package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
  673. package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
  674. package/dist/components/RangeSlider/RangeSlider.module.cjs.map +1 -1
  675. package/dist/components/RangeSlider/RangeSlider.module.js.map +1 -1
  676. package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
  677. package/dist/components/RatingStars/RatingStars.js.map +1 -1
  678. package/dist/components/RatingStars/RatingStars.module.cjs.map +1 -1
  679. package/dist/components/RatingStars/RatingStars.module.js.map +1 -1
  680. package/dist/components/RefreshIndicator/RefreshIndicator.cjs +1 -1
  681. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  682. package/dist/components/RefreshIndicator/RefreshIndicator.js +10 -18
  683. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  684. package/dist/components/RefreshIndicator/RefreshIndicator.module.cjs.map +1 -1
  685. package/dist/components/RefreshIndicator/RefreshIndicator.module.js.map +1 -1
  686. package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
  687. package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
  688. package/dist/components/Resizable/Resizable.cjs +1 -1
  689. package/dist/components/Resizable/Resizable.cjs.map +1 -1
  690. package/dist/components/Resizable/Resizable.js +1 -9
  691. package/dist/components/Resizable/Resizable.js.map +1 -1
  692. package/dist/components/Resizable/Resizable.module.cjs.map +1 -1
  693. package/dist/components/Resizable/Resizable.module.js.map +1 -1
  694. package/dist/components/Responsive/Responsive.cjs.map +1 -1
  695. package/dist/components/Responsive/Responsive.js.map +1 -1
  696. package/dist/components/Reveal/Reveal.cjs.map +1 -1
  697. package/dist/components/Reveal/Reveal.js.map +1 -1
  698. package/dist/components/Reveal/Reveal.module.cjs.map +1 -1
  699. package/dist/components/Reveal/Reveal.module.js.map +1 -1
  700. package/dist/components/Reveal/reveal-threshold.cjs.map +1 -1
  701. package/dist/components/Reveal/reveal-threshold.js.map +1 -1
  702. package/dist/components/SafeArea/SafeArea.cjs.map +1 -1
  703. package/dist/components/SafeArea/SafeArea.js.map +1 -1
  704. package/dist/components/SafeArea/SafeArea.module.cjs.map +1 -1
  705. package/dist/components/SafeArea/SafeArea.module.js.map +1 -1
  706. package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
  707. package/dist/components/Scheduler/Scheduler.js.map +1 -1
  708. package/dist/components/Scheduler/Scheduler.module.cjs.map +1 -1
  709. package/dist/components/Scheduler/Scheduler.module.js.map +1 -1
  710. package/dist/components/Scheduler/scheduler-layout.cjs.map +1 -1
  711. package/dist/components/Scheduler/scheduler-layout.js.map +1 -1
  712. package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
  713. package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
  714. package/dist/components/ScrollArea/ScrollArea.module.cjs.map +1 -1
  715. package/dist/components/ScrollArea/ScrollArea.module.js.map +1 -1
  716. package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
  717. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  718. package/dist/components/SearchBar/SearchBar.module.cjs.map +1 -1
  719. package/dist/components/SearchBar/SearchBar.module.js.map +1 -1
  720. package/dist/components/SectionHeader/SectionHeader.cjs.map +1 -1
  721. package/dist/components/SectionHeader/SectionHeader.js.map +1 -1
  722. package/dist/components/SectionHeader/SectionHeader.module.cjs.map +1 -1
  723. package/dist/components/SectionHeader/SectionHeader.module.js.map +1 -1
  724. package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
  725. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  726. package/dist/components/SegmentedControl/SegmentedControl.module.cjs.map +1 -1
  727. package/dist/components/SegmentedControl/SegmentedControl.module.js.map +1 -1
  728. package/dist/components/Select/CaretIcon.cjs.map +1 -1
  729. package/dist/components/Select/CaretIcon.js.map +1 -1
  730. package/dist/components/Select/Select.cjs.map +1 -1
  731. package/dist/components/Select/Select.js.map +1 -1
  732. package/dist/components/Select/Select.module.cjs.map +1 -1
  733. package/dist/components/Select/Select.module.js.map +1 -1
  734. package/dist/components/Select/options.cjs.map +1 -1
  735. package/dist/components/Select/options.js.map +1 -1
  736. package/dist/components/Sidebar/Sidebar.cjs +1 -1
  737. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  738. package/dist/components/Sidebar/Sidebar.js +13 -23
  739. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  740. package/dist/components/Sidebar/Sidebar.module.cjs.map +1 -1
  741. package/dist/components/Sidebar/Sidebar.module.js.map +1 -1
  742. package/dist/components/Sidebar/SidebarEntry.cjs.map +1 -1
  743. package/dist/components/Sidebar/SidebarEntry.js.map +1 -1
  744. package/dist/components/Sidebar/active-nav-key.cjs.map +1 -1
  745. package/dist/components/Sidebar/active-nav-key.js.map +1 -1
  746. package/dist/components/SignaturePad/SignaturePad.cjs +1 -1
  747. package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
  748. package/dist/components/SignaturePad/SignaturePad.js +1 -5
  749. package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
  750. package/dist/components/SignaturePad/SignaturePad.module.cjs.map +1 -1
  751. package/dist/components/SignaturePad/SignaturePad.module.js.map +1 -1
  752. package/dist/components/Skeleton/Skeleton.cjs.map +1 -1
  753. package/dist/components/Skeleton/Skeleton.js.map +1 -1
  754. package/dist/components/Skeleton/Skeleton.module.cjs.map +1 -1
  755. package/dist/components/Skeleton/Skeleton.module.js.map +1 -1
  756. package/dist/components/Slider/Slider.cjs.map +1 -1
  757. package/dist/components/Slider/Slider.js.map +1 -1
  758. package/dist/components/Slider/Slider.module.cjs.map +1 -1
  759. package/dist/components/Slider/Slider.module.js.map +1 -1
  760. package/dist/components/Spacer/Spacer.cjs.map +1 -1
  761. package/dist/components/Spacer/Spacer.js.map +1 -1
  762. package/dist/components/Spacer/Spacer.module.cjs.map +1 -1
  763. package/dist/components/Spacer/Spacer.module.js.map +1 -1
  764. package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
  765. package/dist/components/Sparkline/Sparkline.js.map +1 -1
  766. package/dist/components/Sparkline/Sparkline.module.cjs.map +1 -1
  767. package/dist/components/Sparkline/Sparkline.module.js.map +1 -1
  768. package/dist/components/Sparkline/sparkline-geometry.cjs.map +1 -1
  769. package/dist/components/Sparkline/sparkline-geometry.js.map +1 -1
  770. package/dist/components/Spinner/Spinner.cjs.map +1 -1
  771. package/dist/components/Spinner/Spinner.js.map +1 -1
  772. package/dist/components/Spinner/Spinner.module.cjs.map +1 -1
  773. package/dist/components/Spinner/Spinner.module.js.map +1 -1
  774. package/dist/components/Stat/Stat.cjs.map +1 -1
  775. package/dist/components/Stat/Stat.js.map +1 -1
  776. package/dist/components/Stat/Stat.module.cjs.map +1 -1
  777. package/dist/components/Stat/Stat.module.js.map +1 -1
  778. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  779. package/dist/components/Stepper/Stepper.js.map +1 -1
  780. package/dist/components/Stepper/Stepper.module.cjs.map +1 -1
  781. package/dist/components/Stepper/Stepper.module.js.map +1 -1
  782. package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
  783. package/dist/components/StepperInput/StepperInput.js.map +1 -1
  784. package/dist/components/StepperInput/StepperInput.module.cjs.map +1 -1
  785. package/dist/components/StepperInput/StepperInput.module.js.map +1 -1
  786. package/dist/components/Switch/Switch.cjs.map +1 -1
  787. package/dist/components/Switch/Switch.js.map +1 -1
  788. package/dist/components/Switch/Switch.module.cjs.map +1 -1
  789. package/dist/components/Switch/Switch.module.js.map +1 -1
  790. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
  791. package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
  792. package/dist/components/SyncStatusBadge/SyncStatusBadge.module.cjs.map +1 -1
  793. package/dist/components/SyncStatusBadge/SyncStatusBadge.module.js.map +1 -1
  794. package/dist/components/Table/Table.cjs.map +1 -1
  795. package/dist/components/Table/Table.js.map +1 -1
  796. package/dist/components/Table/Table.module.cjs.map +1 -1
  797. package/dist/components/Table/Table.module.js.map +1 -1
  798. package/dist/components/Tabs/Tabs.cjs.map +1 -1
  799. package/dist/components/Tabs/Tabs.js.map +1 -1
  800. package/dist/components/Tabs/Tabs.module.cjs.map +1 -1
  801. package/dist/components/Tabs/Tabs.module.js.map +1 -1
  802. package/dist/components/Tag/Tag.cjs.map +1 -1
  803. package/dist/components/Tag/Tag.js.map +1 -1
  804. package/dist/components/Tag/Tag.module.cjs.map +1 -1
  805. package/dist/components/Tag/Tag.module.js.map +1 -1
  806. package/dist/components/Textarea/Textarea.cjs.map +1 -1
  807. package/dist/components/Textarea/Textarea.js.map +1 -1
  808. package/dist/components/Textarea/Textarea.module.cjs.map +1 -1
  809. package/dist/components/Textarea/Textarea.module.js.map +1 -1
  810. package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
  811. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  812. package/dist/components/TimePicker/TimePicker.module.cjs.map +1 -1
  813. package/dist/components/TimePicker/TimePicker.module.js.map +1 -1
  814. package/dist/components/Timeline/Timeline.cjs.map +1 -1
  815. package/dist/components/Timeline/Timeline.js.map +1 -1
  816. package/dist/components/Timeline/Timeline.module.cjs.map +1 -1
  817. package/dist/components/Timeline/Timeline.module.js.map +1 -1
  818. package/dist/components/Toast/Toast.module.cjs.map +1 -1
  819. package/dist/components/Toast/Toast.module.js.map +1 -1
  820. package/dist/components/Toast/ToastProvider.cjs.map +1 -1
  821. package/dist/components/Toast/ToastProvider.js.map +1 -1
  822. package/dist/components/Toggle/Toggle.cjs.map +1 -1
  823. package/dist/components/Toggle/Toggle.js.map +1 -1
  824. package/dist/components/Toggle/Toggle.module.cjs.map +1 -1
  825. package/dist/components/Toggle/Toggle.module.js.map +1 -1
  826. package/dist/components/ToggleGroup/ToggleGroup.cjs.map +1 -1
  827. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  828. package/dist/components/ToggleGroup/ToggleGroup.module.cjs.map +1 -1
  829. package/dist/components/ToggleGroup/ToggleGroup.module.js.map +1 -1
  830. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  831. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  832. package/dist/components/Tooltip/Tooltip.module.cjs.map +1 -1
  833. package/dist/components/Tooltip/Tooltip.module.js.map +1 -1
  834. package/dist/components/Tour/Tour.cjs +1 -1
  835. package/dist/components/Tour/Tour.cjs.map +1 -1
  836. package/dist/components/Tour/Tour.js +1 -5
  837. package/dist/components/Tour/Tour.js.map +1 -1
  838. package/dist/components/Tour/Tour.module.cjs.map +1 -1
  839. package/dist/components/Tour/Tour.module.js.map +1 -1
  840. package/dist/components/Tour/tour-position.cjs.map +1 -1
  841. package/dist/components/Tour/tour-position.js.map +1 -1
  842. package/dist/components/Transfer/Transfer.cjs.map +1 -1
  843. package/dist/components/Transfer/Transfer.js.map +1 -1
  844. package/dist/components/Transfer/Transfer.module.cjs.map +1 -1
  845. package/dist/components/Transfer/Transfer.module.js.map +1 -1
  846. package/dist/components/Transfer/transfer-state.cjs.map +1 -1
  847. package/dist/components/Transfer/transfer-state.js.map +1 -1
  848. package/dist/components/TreeView/TreeView.cjs.map +1 -1
  849. package/dist/components/TreeView/TreeView.js.map +1 -1
  850. package/dist/components/TreeView/TreeView.module.cjs.map +1 -1
  851. package/dist/components/TreeView/TreeView.module.js.map +1 -1
  852. package/dist/components/TruncateText/TruncateText.cjs.map +1 -1
  853. package/dist/components/TruncateText/TruncateText.js.map +1 -1
  854. package/dist/components/TruncateText/TruncateText.module.cjs.map +1 -1
  855. package/dist/components/TruncateText/TruncateText.module.js.map +1 -1
  856. package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
  857. package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
  858. package/dist/components/UpdatePrompt/UpdatePrompt.module.cjs.map +1 -1
  859. package/dist/components/UpdatePrompt/UpdatePrompt.module.js.map +1 -1
  860. package/dist/components/VideoPlayer/VideoPlayer.cjs +1 -1
  861. package/dist/components/VideoPlayer/VideoPlayer.cjs.map +1 -1
  862. package/dist/components/VideoPlayer/VideoPlayer.js +1 -7
  863. package/dist/components/VideoPlayer/VideoPlayer.js.map +1 -1
  864. package/dist/components/VideoPlayer/VideoPlayer.module.cjs.map +1 -1
  865. package/dist/components/VideoPlayer/VideoPlayer.module.js.map +1 -1
  866. package/dist/components/VideoPlayer/playback-rates.cjs.map +1 -1
  867. package/dist/components/VideoPlayer/playback-rates.js.map +1 -1
  868. package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
  869. package/dist/components/VirtualList/VirtualList.js.map +1 -1
  870. package/dist/components/VirtualList/VirtualList.module.cjs.map +1 -1
  871. package/dist/components/VirtualList/VirtualList.module.js.map +1 -1
  872. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
  873. package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
  874. package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -1
  875. package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -1
  876. package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
  877. package/dist/components/VisuallyHidden/VisuallyHidden.js.map +1 -1
  878. package/dist/components/VisuallyHidden/VisuallyHidden.module.cjs.map +1 -1
  879. package/dist/components/VisuallyHidden/VisuallyHidden.module.js.map +1 -1
  880. package/dist/components/Wizard/Wizard.cjs +1 -1
  881. package/dist/components/Wizard/Wizard.cjs.map +1 -1
  882. package/dist/components/Wizard/Wizard.js +4 -11
  883. package/dist/components/Wizard/Wizard.js.map +1 -1
  884. package/dist/components/Wizard/Wizard.module.cjs.map +1 -1
  885. package/dist/components/Wizard/Wizard.module.js.map +1 -1
  886. package/dist/data/create-data-provider.cjs.map +1 -1
  887. package/dist/data/create-data-provider.js.map +1 -1
  888. package/dist/data/data-provider-context.cjs.map +1 -1
  889. package/dist/data/data-provider-context.js.map +1 -1
  890. package/dist/data/use-resource.cjs.map +1 -1
  891. package/dist/data/use-resource.js.map +1 -1
  892. package/dist/editor/RichTextEditor.cjs.map +1 -1
  893. package/dist/editor/RichTextEditor.js.map +1 -1
  894. package/dist/editor/RichTextEditor.module.cjs.map +1 -1
  895. package/dist/editor/RichTextEditor.module.js.map +1 -1
  896. package/dist/editor.js +1 -2
  897. package/dist/error-boundary/ErrorBoundary.cjs.map +1 -1
  898. package/dist/error-boundary/ErrorBoundary.js.map +1 -1
  899. package/dist/error-boundary/use-error-handler.cjs.map +1 -1
  900. package/dist/error-boundary/use-error-handler.js.map +1 -1
  901. package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
  902. package/dist/feature-flags/FeatureFlagsProvider.js.map +1 -1
  903. package/dist/feature-flags/growthbook-adapter.cjs.map +1 -1
  904. package/dist/feature-flags/growthbook-adapter.js.map +1 -1
  905. package/dist/feature-flags/in-memory-adapter.cjs.map +1 -1
  906. package/dist/feature-flags/in-memory-adapter.js.map +1 -1
  907. package/dist/feature-flags/launchdarkly-adapter.cjs.map +1 -1
  908. package/dist/feature-flags/launchdarkly-adapter.js.map +1 -1
  909. package/dist/forms/FormField.cjs.map +1 -1
  910. package/dist/forms/FormField.js.map +1 -1
  911. package/dist/forms/br-validators.cjs.map +1 -1
  912. package/dist/forms/br-validators.js.map +1 -1
  913. package/dist/forms/masked-inputs.cjs.map +1 -1
  914. package/dist/forms/masked-inputs.js.map +1 -1
  915. package/dist/forms/use-viacep.cjs.map +1 -1
  916. package/dist/forms/use-viacep.js.map +1 -1
  917. package/dist/forms/use-zod-form.cjs.map +1 -1
  918. package/dist/forms/use-zod-form.js.map +1 -1
  919. package/dist/forms/validate-form.cjs.map +1 -1
  920. package/dist/forms/validate-form.js.map +1 -1
  921. package/dist/forms/zod-resolver.cjs.map +1 -1
  922. package/dist/forms/zod-resolver.js.map +1 -1
  923. package/dist/geo/TrajectoryMap.cjs.map +1 -1
  924. package/dist/geo/TrajectoryMap.js.map +1 -1
  925. package/dist/geo/TrajectoryMap.module.cjs.map +1 -1
  926. package/dist/geo/TrajectoryMap.module.js.map +1 -1
  927. package/dist/geo/bounds.cjs.map +1 -1
  928. package/dist/geo/bounds.js.map +1 -1
  929. package/dist/geo/create-position-tracker.cjs +1 -1
  930. package/dist/geo/create-position-tracker.cjs.map +1 -1
  931. package/dist/geo/create-position-tracker.js +1 -7
  932. package/dist/geo/create-position-tracker.js.map +1 -1
  933. package/dist/geo/distance.cjs.map +1 -1
  934. package/dist/geo/distance.js.map +1 -1
  935. package/dist/geo/estimate.cjs.map +1 -1
  936. package/dist/geo/estimate.js.map +1 -1
  937. package/dist/geo/leaflet-map.cjs.map +1 -1
  938. package/dist/geo/leaflet-map.js.map +1 -1
  939. package/dist/geo/projection.cjs.map +1 -1
  940. package/dist/geo/projection.js.map +1 -1
  941. package/dist/geo/routing.cjs.map +1 -1
  942. package/dist/geo/routing.js.map +1 -1
  943. package/dist/geo/types.cjs.map +1 -1
  944. package/dist/geo/types.js.map +1 -1
  945. package/dist/geo/use-position-tracker.cjs.map +1 -1
  946. package/dist/geo/use-position-tracker.js.map +1 -1
  947. package/dist/hooks/pwa-env.cjs.map +1 -1
  948. package/dist/hooks/pwa-env.js.map +1 -1
  949. package/dist/hooks/tab-sequence.cjs.map +1 -1
  950. package/dist/hooks/tab-sequence.js.map +1 -1
  951. package/dist/hooks/use-announce.cjs +1 -1
  952. package/dist/hooks/use-announce.cjs.map +1 -1
  953. package/dist/hooks/use-announce.js +2 -2
  954. package/dist/hooks/use-announce.js.map +1 -1
  955. package/dist/hooks/use-async.cjs.map +1 -1
  956. package/dist/hooks/use-async.js.map +1 -1
  957. package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
  958. package/dist/hooks/use-before-install-prompt.js.map +1 -1
  959. package/dist/hooks/use-breakpoint.cjs.map +1 -1
  960. package/dist/hooks/use-breakpoint.js.map +1 -1
  961. package/dist/hooks/use-click-outside.cjs.map +1 -1
  962. package/dist/hooks/use-click-outside.js.map +1 -1
  963. package/dist/hooks/use-client-filter.cjs.map +1 -1
  964. package/dist/hooks/use-client-filter.js.map +1 -1
  965. package/dist/hooks/use-clipboard.cjs.map +1 -1
  966. package/dist/hooks/use-clipboard.js.map +1 -1
  967. package/dist/hooks/use-countdown.cjs.map +1 -1
  968. package/dist/hooks/use-countdown.js.map +1 -1
  969. package/dist/hooks/use-counter.cjs.map +1 -1
  970. package/dist/hooks/use-counter.js.map +1 -1
  971. package/dist/hooks/use-debounce.cjs.map +1 -1
  972. package/dist/hooks/use-debounce.js.map +1 -1
  973. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  974. package/dist/hooks/use-deep-memo.js.map +1 -1
  975. package/dist/hooks/use-disclosure.cjs.map +1 -1
  976. package/dist/hooks/use-disclosure.js.map +1 -1
  977. package/dist/hooks/use-document-title.cjs.map +1 -1
  978. package/dist/hooks/use-document-title.js.map +1 -1
  979. package/dist/hooks/use-document-visibility.cjs.map +1 -1
  980. package/dist/hooks/use-document-visibility.js.map +1 -1
  981. package/dist/hooks/use-draft-filters.cjs.map +1 -1
  982. package/dist/hooks/use-draft-filters.js.map +1 -1
  983. package/dist/hooks/use-event-listener.cjs.map +1 -1
  984. package/dist/hooks/use-event-listener.js.map +1 -1
  985. package/dist/hooks/use-favicon.cjs.map +1 -1
  986. package/dist/hooks/use-favicon.js.map +1 -1
  987. package/dist/hooks/use-focus-trap.cjs.map +1 -1
  988. package/dist/hooks/use-focus-trap.js.map +1 -1
  989. package/dist/hooks/use-fullscreen-element.cjs.map +1 -1
  990. package/dist/hooks/use-fullscreen-element.js.map +1 -1
  991. package/dist/hooks/use-fullscreen.cjs +1 -1
  992. package/dist/hooks/use-fullscreen.cjs.map +1 -1
  993. package/dist/hooks/use-fullscreen.js +7 -23
  994. package/dist/hooks/use-fullscreen.js.map +1 -1
  995. package/dist/hooks/use-geolocation.cjs.map +1 -1
  996. package/dist/hooks/use-geolocation.js.map +1 -1
  997. package/dist/hooks/use-hover.cjs.map +1 -1
  998. package/dist/hooks/use-hover.js.map +1 -1
  999. package/dist/hooks/use-idle.cjs.map +1 -1
  1000. package/dist/hooks/use-idle.js.map +1 -1
  1001. package/dist/hooks/use-install-prompt.cjs +1 -1
  1002. package/dist/hooks/use-install-prompt.cjs.map +1 -1
  1003. package/dist/hooks/use-install-prompt.js +1 -1
  1004. package/dist/hooks/use-install-prompt.js.map +1 -1
  1005. package/dist/hooks/use-intersection-observer.cjs.map +1 -1
  1006. package/dist/hooks/use-intersection-observer.js.map +1 -1
  1007. package/dist/hooks/use-interval.cjs.map +1 -1
  1008. package/dist/hooks/use-interval.js.map +1 -1
  1009. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  1010. package/dist/hooks/use-is-first-render.js.map +1 -1
  1011. package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
  1012. package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
  1013. package/dist/hooks/use-latest-ref.cjs.map +1 -1
  1014. package/dist/hooks/use-latest-ref.js.map +1 -1
  1015. package/dist/hooks/use-list-state.cjs.map +1 -1
  1016. package/dist/hooks/use-list-state.js.map +1 -1
  1017. package/dist/hooks/use-local-storage.cjs +1 -1
  1018. package/dist/hooks/use-local-storage.cjs.map +1 -1
  1019. package/dist/hooks/use-local-storage.js +2 -5
  1020. package/dist/hooks/use-local-storage.js.map +1 -1
  1021. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  1022. package/dist/hooks/use-long-press-handlers.js.map +1 -1
  1023. package/dist/hooks/use-long-press.cjs.map +1 -1
  1024. package/dist/hooks/use-long-press.js.map +1 -1
  1025. package/dist/hooks/use-map.cjs.map +1 -1
  1026. package/dist/hooks/use-map.js.map +1 -1
  1027. package/dist/hooks/use-media-devices.cjs.map +1 -1
  1028. package/dist/hooks/use-media-devices.js.map +1 -1
  1029. package/dist/hooks/use-media-permission.cjs +1 -1
  1030. package/dist/hooks/use-media-permission.cjs.map +1 -1
  1031. package/dist/hooks/use-media-permission.js +2 -5
  1032. package/dist/hooks/use-media-permission.js.map +1 -1
  1033. package/dist/hooks/use-media-query.cjs.map +1 -1
  1034. package/dist/hooks/use-media-query.js.map +1 -1
  1035. package/dist/hooks/use-object-url.cjs.map +1 -1
  1036. package/dist/hooks/use-object-url.js.map +1 -1
  1037. package/dist/hooks/use-online.cjs.map +1 -1
  1038. package/dist/hooks/use-online.js.map +1 -1
  1039. package/dist/hooks/use-pagination.cjs.map +1 -1
  1040. package/dist/hooks/use-pagination.js.map +1 -1
  1041. package/dist/hooks/use-previous.cjs.map +1 -1
  1042. package/dist/hooks/use-previous.js.map +1 -1
  1043. package/dist/hooks/use-push-to-talk.cjs.map +1 -1
  1044. package/dist/hooks/use-push-to-talk.js.map +1 -1
  1045. package/dist/hooks/use-queue.cjs.map +1 -1
  1046. package/dist/hooks/use-queue.js.map +1 -1
  1047. package/dist/hooks/use-resize-observer.cjs.map +1 -1
  1048. package/dist/hooks/use-resize-observer.js.map +1 -1
  1049. package/dist/hooks/use-scroll-lock.cjs.map +1 -1
  1050. package/dist/hooks/use-scroll-lock.js.map +1 -1
  1051. package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
  1052. package/dist/hooks/use-scroll-overflow.js.map +1 -1
  1053. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  1054. package/dist/hooks/use-service-worker-update.js.map +1 -1
  1055. package/dist/hooks/use-set.cjs.map +1 -1
  1056. package/dist/hooks/use-set.js.map +1 -1
  1057. package/dist/hooks/use-sortable.cjs.map +1 -1
  1058. package/dist/hooks/use-sortable.js.map +1 -1
  1059. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  1060. package/dist/hooks/use-stable-callback.js.map +1 -1
  1061. package/dist/hooks/use-storage-estimate.cjs.map +1 -1
  1062. package/dist/hooks/use-storage-estimate.js.map +1 -1
  1063. package/dist/hooks/use-throttle.cjs.map +1 -1
  1064. package/dist/hooks/use-throttle.js.map +1 -1
  1065. package/dist/hooks/use-timeout.cjs.map +1 -1
  1066. package/dist/hooks/use-timeout.js.map +1 -1
  1067. package/dist/hooks/use-toggle.cjs.map +1 -1
  1068. package/dist/hooks/use-toggle.js.map +1 -1
  1069. package/dist/hooks/use-typewriter.cjs.map +1 -1
  1070. package/dist/hooks/use-typewriter.js.map +1 -1
  1071. package/dist/hooks/use-window-size.cjs.map +1 -1
  1072. package/dist/hooks/use-window-size.js.map +1 -1
  1073. package/dist/http/api-client.cjs.map +1 -1
  1074. package/dist/http/api-client.js.map +1 -1
  1075. package/dist/http/build-url.cjs.map +1 -1
  1076. package/dist/http/build-url.js.map +1 -1
  1077. package/dist/http/credential-scope.cjs.map +1 -1
  1078. package/dist/http/credential-scope.js.map +1 -1
  1079. package/dist/http/csrf.cjs.map +1 -1
  1080. package/dist/http/csrf.js.map +1 -1
  1081. package/dist/http/decode-response.cjs.map +1 -1
  1082. package/dist/http/decode-response.js.map +1 -1
  1083. package/dist/http/describe-api-error.cjs.map +1 -1
  1084. package/dist/http/describe-api-error.js.map +1 -1
  1085. package/dist/http/errors.cjs.map +1 -1
  1086. package/dist/http/errors.js.map +1 -1
  1087. package/dist/http/idempotency.cjs.map +1 -1
  1088. package/dist/http/idempotency.js.map +1 -1
  1089. package/dist/http/parse-response.cjs.map +1 -1
  1090. package/dist/http/parse-response.js.map +1 -1
  1091. package/dist/http/resumable-upload.cjs.map +1 -1
  1092. package/dist/http/resumable-upload.js.map +1 -1
  1093. package/dist/http/retry.cjs.map +1 -1
  1094. package/dist/http/retry.js.map +1 -1
  1095. package/dist/http/timeout.cjs.map +1 -1
  1096. package/dist/http/timeout.js.map +1 -1
  1097. package/dist/http/upload-with-progress.cjs +1 -1
  1098. package/dist/http/upload-with-progress.cjs.map +1 -1
  1099. package/dist/http/upload-with-progress.js +2 -7
  1100. package/dist/http/upload-with-progress.js.map +1 -1
  1101. package/dist/http/use-describe-api-error.cjs.map +1 -1
  1102. package/dist/http/use-describe-api-error.js.map +1 -1
  1103. package/dist/http/use-poll.cjs +1 -1
  1104. package/dist/http/use-poll.cjs.map +1 -1
  1105. package/dist/http/use-poll.js +2 -5
  1106. package/dist/http/use-poll.js.map +1 -1
  1107. package/dist/i18n/I18nProvider.cjs.map +1 -1
  1108. package/dist/i18n/I18nProvider.js.map +1 -1
  1109. package/dist/i18n/create-i18n.cjs.map +1 -1
  1110. package/dist/i18n/create-i18n.js.map +1 -1
  1111. package/dist/icons/Icon.cjs.map +1 -1
  1112. package/dist/icons/Icon.js.map +1 -1
  1113. package/dist/icons/IconPicker.cjs.map +1 -1
  1114. package/dist/icons/IconPicker.js.map +1 -1
  1115. package/dist/icons/IconPicker.module.cjs.map +1 -1
  1116. package/dist/icons/IconPicker.module.js.map +1 -1
  1117. package/dist/icons/IconProvider.cjs.map +1 -1
  1118. package/dist/icons/IconProvider.js.map +1 -1
  1119. package/dist/icons/alias.cjs.map +1 -1
  1120. package/dist/icons/alias.js.map +1 -1
  1121. package/dist/icons/generated/aliases.cjs.map +1 -1
  1122. package/dist/icons/generated/aliases.js.map +1 -1
  1123. package/dist/icons/generated/icon-names.cjs.map +1 -1
  1124. package/dist/icons/generated/icon-names.js.map +1 -1
  1125. package/dist/icons/generated/loaders.cjs.map +1 -1
  1126. package/dist/icons/generated/loaders.js.map +1 -1
  1127. package/dist/icons/generated/shard-00.cjs.map +1 -1
  1128. package/dist/icons/generated/shard-00.js.map +1 -1
  1129. package/dist/icons/generated/shard-01.cjs.map +1 -1
  1130. package/dist/icons/generated/shard-01.js.map +1 -1
  1131. package/dist/icons/generated/shard-02.cjs.map +1 -1
  1132. package/dist/icons/generated/shard-02.js.map +1 -1
  1133. package/dist/icons/generated/shard-03.cjs.map +1 -1
  1134. package/dist/icons/generated/shard-03.js.map +1 -1
  1135. package/dist/icons/generated/shard-04.cjs.map +1 -1
  1136. package/dist/icons/generated/shard-04.js.map +1 -1
  1137. package/dist/icons/generated/shard-05.cjs.map +1 -1
  1138. package/dist/icons/generated/shard-05.js.map +1 -1
  1139. package/dist/icons/generated/shard-06.cjs.map +1 -1
  1140. package/dist/icons/generated/shard-06.js.map +1 -1
  1141. package/dist/icons/generated/shard-07.cjs.map +1 -1
  1142. package/dist/icons/generated/shard-07.js.map +1 -1
  1143. package/dist/icons/generated/shard-08.cjs.map +1 -1
  1144. package/dist/icons/generated/shard-08.js.map +1 -1
  1145. package/dist/icons/generated/shard-09.cjs.map +1 -1
  1146. package/dist/icons/generated/shard-09.js.map +1 -1
  1147. package/dist/icons/generated/shard-10.cjs.map +1 -1
  1148. package/dist/icons/generated/shard-10.js.map +1 -1
  1149. package/dist/icons/generated/shard-11.cjs.map +1 -1
  1150. package/dist/icons/generated/shard-11.js.map +1 -1
  1151. package/dist/icons/generated/shard-12.cjs.map +1 -1
  1152. package/dist/icons/generated/shard-12.js.map +1 -1
  1153. package/dist/icons/generated/shard-13.cjs.map +1 -1
  1154. package/dist/icons/generated/shard-13.js.map +1 -1
  1155. package/dist/icons/generated/shard-14.cjs.map +1 -1
  1156. package/dist/icons/generated/shard-14.js.map +1 -1
  1157. package/dist/icons/generated/shard-15.cjs.map +1 -1
  1158. package/dist/icons/generated/shard-15.js.map +1 -1
  1159. package/dist/icons/generated/shard-16.cjs.map +1 -1
  1160. package/dist/icons/generated/shard-16.js.map +1 -1
  1161. package/dist/icons/generated/shard-17.cjs.map +1 -1
  1162. package/dist/icons/generated/shard-17.js.map +1 -1
  1163. package/dist/icons/generated/shard-18.cjs.map +1 -1
  1164. package/dist/icons/generated/shard-18.js.map +1 -1
  1165. package/dist/icons/generated/shard-19.cjs.map +1 -1
  1166. package/dist/icons/generated/shard-19.js.map +1 -1
  1167. package/dist/icons/generated/shard-20.cjs.map +1 -1
  1168. package/dist/icons/generated/shard-20.js.map +1 -1
  1169. package/dist/icons/generated/shard-21.cjs.map +1 -1
  1170. package/dist/icons/generated/shard-21.js.map +1 -1
  1171. package/dist/icons/generated/shard-22.cjs.map +1 -1
  1172. package/dist/icons/generated/shard-22.js.map +1 -1
  1173. package/dist/icons/generated/shard-23.cjs.map +1 -1
  1174. package/dist/icons/generated/shard-23.js.map +1 -1
  1175. package/dist/icons/generated/shard-24.cjs.map +1 -1
  1176. package/dist/icons/generated/shard-24.js.map +1 -1
  1177. package/dist/icons/generated/shard-25.cjs.map +1 -1
  1178. package/dist/icons/generated/shard-25.js.map +1 -1
  1179. package/dist/icons/generated/shard-26.cjs.map +1 -1
  1180. package/dist/icons/generated/shard-26.js.map +1 -1
  1181. package/dist/icons/generated/shard-27.cjs.map +1 -1
  1182. package/dist/icons/generated/shard-27.js.map +1 -1
  1183. package/dist/icons/generated/shard-28.cjs.map +1 -1
  1184. package/dist/icons/generated/shard-28.js.map +1 -1
  1185. package/dist/icons/generated/shard-29.cjs.map +1 -1
  1186. package/dist/icons/generated/shard-29.js.map +1 -1
  1187. package/dist/icons/generated/shard-30.cjs.map +1 -1
  1188. package/dist/icons/generated/shard-30.js.map +1 -1
  1189. package/dist/icons/generated/shard-31.cjs.map +1 -1
  1190. package/dist/icons/generated/shard-31.js.map +1 -1
  1191. package/dist/icons/generated/shard-32.cjs.map +1 -1
  1192. package/dist/icons/generated/shard-32.js.map +1 -1
  1193. package/dist/icons/generated/shard-33.cjs.map +1 -1
  1194. package/dist/icons/generated/shard-33.js.map +1 -1
  1195. package/dist/icons/generated/shard-34.cjs.map +1 -1
  1196. package/dist/icons/generated/shard-34.js.map +1 -1
  1197. package/dist/icons/generated/shard-35.cjs.map +1 -1
  1198. package/dist/icons/generated/shard-35.js.map +1 -1
  1199. package/dist/icons/generated/shard-36.cjs.map +1 -1
  1200. package/dist/icons/generated/shard-36.js.map +1 -1
  1201. package/dist/icons/generated/shard-37.cjs.map +1 -1
  1202. package/dist/icons/generated/shard-37.js.map +1 -1
  1203. package/dist/icons/generated/shard-38.cjs.map +1 -1
  1204. package/dist/icons/generated/shard-38.js.map +1 -1
  1205. package/dist/icons/generated/shard-39.cjs.map +1 -1
  1206. package/dist/icons/generated/shard-39.js.map +1 -1
  1207. package/dist/icons/generated/shard-40.cjs.map +1 -1
  1208. package/dist/icons/generated/shard-40.js.map +1 -1
  1209. package/dist/icons/generated/shard-41.cjs.map +1 -1
  1210. package/dist/icons/generated/shard-41.js.map +1 -1
  1211. package/dist/icons/generated/shard-42.cjs.map +1 -1
  1212. package/dist/icons/generated/shard-42.js.map +1 -1
  1213. package/dist/icons/generated/shard-43.cjs.map +1 -1
  1214. package/dist/icons/generated/shard-43.js.map +1 -1
  1215. package/dist/icons/generated/shard-44.cjs.map +1 -1
  1216. package/dist/icons/generated/shard-44.js.map +1 -1
  1217. package/dist/icons/generated/shard-45.cjs.map +1 -1
  1218. package/dist/icons/generated/shard-45.js.map +1 -1
  1219. package/dist/icons/icon-context.cjs.map +1 -1
  1220. package/dist/icons/icon-context.js.map +1 -1
  1221. package/dist/icons/is-icon-name.cjs.map +1 -1
  1222. package/dist/icons/is-icon-name.js.map +1 -1
  1223. package/dist/icons/material-symbols.cjs.map +1 -1
  1224. package/dist/icons/material-symbols.js.map +1 -1
  1225. package/dist/icons/normalize-icon-name.cjs.map +1 -1
  1226. package/dist/icons/normalize-icon-name.js.map +1 -1
  1227. package/dist/icons/shard-cache.cjs +1 -1
  1228. package/dist/icons/shard-cache.cjs.map +1 -1
  1229. package/dist/icons/shard-cache.js +2 -5
  1230. package/dist/icons/shard-cache.js.map +1 -1
  1231. package/dist/icons/use-icon.cjs.map +1 -1
  1232. package/dist/icons/use-icon.js.map +1 -1
  1233. package/dist/icons/validate-icon-name.cjs.map +1 -1
  1234. package/dist/icons/validate-icon-name.js.map +1 -1
  1235. package/dist/icons-virtual.cjs.map +1 -1
  1236. package/dist/icons-virtual.js.map +1 -1
  1237. package/dist/imaging/canvas.cjs.map +1 -1
  1238. package/dist/imaging/canvas.js.map +1 -1
  1239. package/dist/imaging/compress.cjs.map +1 -1
  1240. package/dist/imaging/compress.js.map +1 -1
  1241. package/dist/imaging/decode.cjs.map +1 -1
  1242. package/dist/imaging/decode.js.map +1 -1
  1243. package/dist/imaging/encode.cjs.map +1 -1
  1244. package/dist/imaging/encode.js.map +1 -1
  1245. package/dist/imaging/exceptions.cjs.map +1 -1
  1246. package/dist/imaging/exceptions.js.map +1 -1
  1247. package/dist/imaging/frame.cjs.map +1 -1
  1248. package/dist/imaging/frame.js.map +1 -1
  1249. package/dist/imaging/thumbnails.cjs.map +1 -1
  1250. package/dist/imaging/thumbnails.js.map +1 -1
  1251. package/dist/imaging/transform.cjs.map +1 -1
  1252. package/dist/imaging/transform.js.map +1 -1
  1253. package/dist/imaging/use-image-processing.cjs.map +1 -1
  1254. package/dist/imaging/use-image-processing.js.map +1 -1
  1255. package/dist/logger/logger.cjs.map +1 -1
  1256. package/dist/logger/logger.js.map +1 -1
  1257. package/dist/neural.cjs.map +1 -1
  1258. package/dist/neural.js.map +1 -1
  1259. package/dist/oauth/GoogleSignIn.cjs +1 -1
  1260. package/dist/oauth/GoogleSignIn.cjs.map +1 -1
  1261. package/dist/oauth/GoogleSignIn.js +6 -9
  1262. package/dist/oauth/GoogleSignIn.js.map +1 -1
  1263. package/dist/oauth/callback.cjs.map +1 -1
  1264. package/dist/oauth/callback.js.map +1 -1
  1265. package/dist/oauth/use-oauth-callback.cjs.map +1 -1
  1266. package/dist/oauth/use-oauth-callback.js.map +1 -1
  1267. package/dist/offline/conflict.cjs.map +1 -1
  1268. package/dist/offline/conflict.js.map +1 -1
  1269. package/dist/offline/create-offline-database.cjs.map +1 -1
  1270. package/dist/offline/create-offline-database.js.map +1 -1
  1271. package/dist/offline/create-offline-store.cjs +1 -1
  1272. package/dist/offline/create-offline-store.cjs.map +1 -1
  1273. package/dist/offline/create-offline-store.js +1 -5
  1274. package/dist/offline/create-offline-store.js.map +1 -1
  1275. package/dist/offline/create-offline-sync.cjs +1 -1
  1276. package/dist/offline/create-offline-sync.cjs.map +1 -1
  1277. package/dist/offline/create-offline-sync.js +9 -14
  1278. package/dist/offline/create-offline-sync.js.map +1 -1
  1279. package/dist/offline/use-offline-sync.cjs.map +1 -1
  1280. package/dist/offline/use-offline-sync.js.map +1 -1
  1281. package/dist/perf/cache-size.cjs.map +1 -1
  1282. package/dist/perf/cache-size.js.map +1 -1
  1283. package/dist/perf/device.cjs.map +1 -1
  1284. package/dist/perf/device.js.map +1 -1
  1285. package/dist/perf/format.cjs.map +1 -1
  1286. package/dist/perf/format.js.map +1 -1
  1287. package/dist/perf/profiler.cjs.map +1 -1
  1288. package/dist/perf/profiler.js.map +1 -1
  1289. package/dist/push/use-push-subscription.cjs.map +1 -1
  1290. package/dist/push/use-push-subscription.js.map +1 -1
  1291. package/dist/push/utils.cjs.map +1 -1
  1292. package/dist/push/utils.js.map +1 -1
  1293. package/dist/push/web-push-client.cjs.map +1 -1
  1294. package/dist/push/web-push-client.js.map +1 -1
  1295. package/dist/query/QueryProvider.cjs.map +1 -1
  1296. package/dist/query/QueryProvider.js.map +1 -1
  1297. package/dist/query/constants.cjs.map +1 -1
  1298. package/dist/query/constants.js.map +1 -1
  1299. package/dist/query/create-query-keys.cjs.map +1 -1
  1300. package/dist/query/create-query-keys.js.map +1 -1
  1301. package/dist/query/foreign-client-warning.cjs.map +1 -1
  1302. package/dist/query/foreign-client-warning.js.map +1 -1
  1303. package/dist/query/offline-persistence.cjs +1 -1
  1304. package/dist/query/offline-persistence.cjs.map +1 -1
  1305. package/dist/query/offline-persistence.js +2 -10
  1306. package/dist/query/offline-persistence.js.map +1 -1
  1307. package/dist/query/optimistic.cjs.map +1 -1
  1308. package/dist/query/optimistic.js.map +1 -1
  1309. package/dist/query/pagination.cjs.map +1 -1
  1310. package/dist/query/pagination.js.map +1 -1
  1311. package/dist/query/retry-policy.cjs.map +1 -1
  1312. package/dist/query/retry-policy.js.map +1 -1
  1313. package/dist/query/use-cursor-query.cjs.map +1 -1
  1314. package/dist/query/use-cursor-query.js.map +1 -1
  1315. package/dist/query/use-offline-mutation.cjs.map +1 -1
  1316. package/dist/query/use-offline-mutation.js.map +1 -1
  1317. package/dist/query/use-paginated-query.cjs.map +1 -1
  1318. package/dist/query/use-paginated-query.js.map +1 -1
  1319. package/dist/router/AppRouter.cjs.map +1 -1
  1320. package/dist/router/AppRouter.js.map +1 -1
  1321. package/dist/router/RouteGuard.cjs.map +1 -1
  1322. package/dist/router/RouteGuard.js.map +1 -1
  1323. package/dist/router/index.js +2 -2
  1324. package/dist/share/share-or-download.cjs.map +1 -1
  1325. package/dist/share/share-or-download.js.map +1 -1
  1326. package/dist/share/share.cjs.map +1 -1
  1327. package/dist/share/share.js.map +1 -1
  1328. package/dist/sse/create-event-stream.cjs.map +1 -1
  1329. package/dist/sse/create-event-stream.js.map +1 -1
  1330. package/dist/sse/use-event-stream.cjs.map +1 -1
  1331. package/dist/sse/use-event-stream.js.map +1 -1
  1332. package/dist/store/create-selectors.cjs.map +1 -1
  1333. package/dist/store/create-selectors.js.map +1 -1
  1334. package/dist/store/create-store.cjs.map +1 -1
  1335. package/dist/store/create-store.js.map +1 -1
  1336. package/dist/sw/background-sync.cjs.map +1 -1
  1337. package/dist/sw/background-sync.js.map +1 -1
  1338. package/dist/sw/cache-inspect.cjs.map +1 -1
  1339. package/dist/sw/cache-inspect.js.map +1 -1
  1340. package/dist/sw/cache.cjs +1 -1
  1341. package/dist/sw/cache.cjs.map +1 -1
  1342. package/dist/sw/cache.js +2 -6
  1343. package/dist/sw/cache.js.map +1 -1
  1344. package/dist/sw/create-push-handler.cjs.map +1 -1
  1345. package/dist/sw/create-push-handler.js.map +1 -1
  1346. package/dist/sw/credential-headers.cjs.map +1 -1
  1347. package/dist/sw/credential-headers.js.map +1 -1
  1348. package/dist/sw/periodic-sync.cjs.map +1 -1
  1349. package/dist/sw/periodic-sync.js.map +1 -1
  1350. package/dist/sw/register-service-worker.cjs.map +1 -1
  1351. package/dist/sw/register-service-worker.js.map +1 -1
  1352. package/dist/sw/session-data.cjs.map +1 -1
  1353. package/dist/sw/session-data.js.map +1 -1
  1354. package/dist/tabular/assets.cjs.map +1 -1
  1355. package/dist/tabular/assets.js.map +1 -1
  1356. package/dist/tabular/cache.cjs.map +1 -1
  1357. package/dist/tabular/cache.js.map +1 -1
  1358. package/dist/tabular/compact.cjs.map +1 -1
  1359. package/dist/tabular/compact.js.map +1 -1
  1360. package/dist/tabular/exceptions.cjs.map +1 -1
  1361. package/dist/tabular/exceptions.js.map +1 -1
  1362. package/dist/tabular/manifest.cjs.map +1 -1
  1363. package/dist/tabular/manifest.js.map +1 -1
  1364. package/dist/tabular/predictor.cjs.map +1 -1
  1365. package/dist/tabular/predictor.js.map +1 -1
  1366. package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
  1367. package/dist/tabular/use-tabular-predictor.js.map +1 -1
  1368. package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
  1369. package/dist/telemetry/TelemetryProvider.js.map +1 -1
  1370. package/dist/telemetry/app-error-adapter.cjs.map +1 -1
  1371. package/dist/telemetry/app-error-adapter.js.map +1 -1
  1372. package/dist/telemetry/app-error-queue.cjs.map +1 -1
  1373. package/dist/telemetry/app-error-queue.js.map +1 -1
  1374. package/dist/telemetry/app-error-reporter.cjs.map +1 -1
  1375. package/dist/telemetry/app-error-reporter.js.map +1 -1
  1376. package/dist/telemetry/app-error-schema.cjs.map +1 -1
  1377. package/dist/telemetry/app-error-schema.js.map +1 -1
  1378. package/dist/telemetry/app-error-transport.cjs.map +1 -1
  1379. package/dist/telemetry/app-error-transport.js.map +1 -1
  1380. package/dist/telemetry/console-adapter.cjs.map +1 -1
  1381. package/dist/telemetry/console-adapter.js.map +1 -1
  1382. package/dist/telemetry/describe-app-error.cjs.map +1 -1
  1383. package/dist/telemetry/describe-app-error.js.map +1 -1
  1384. package/dist/telemetry/posthog-adapter.cjs +1 -1
  1385. package/dist/telemetry/posthog-adapter.cjs.map +1 -1
  1386. package/dist/telemetry/posthog-adapter.js +1 -5
  1387. package/dist/telemetry/posthog-adapter.js.map +1 -1
  1388. package/dist/telemetry/sentry-adapter.cjs.map +1 -1
  1389. package/dist/telemetry/sentry-adapter.js.map +1 -1
  1390. package/dist/tempest-react-sdk.cjs +1 -1
  1391. package/dist/tempest-react-sdk.d.ts +234 -3
  1392. package/dist/tempest-react-sdk.js +85 -85
  1393. package/dist/testing/create-mock-handlers.cjs.map +1 -1
  1394. package/dist/testing/create-mock-handlers.js.map +1 -1
  1395. package/dist/testing.js +1 -2
  1396. package/dist/theme/ThemeProvider.cjs.map +1 -1
  1397. package/dist/theme/ThemeProvider.js.map +1 -1
  1398. package/dist/theme/apply-theme.cjs.map +1 -1
  1399. package/dist/theme/apply-theme.js.map +1 -1
  1400. package/dist/theme/color.cjs.map +1 -1
  1401. package/dist/theme/color.js.map +1 -1
  1402. package/dist/theme/create-theme.cjs.map +1 -1
  1403. package/dist/theme/create-theme.js.map +1 -1
  1404. package/dist/theme/data-viz-ramps.cjs.map +1 -1
  1405. package/dist/theme/data-viz-ramps.js.map +1 -1
  1406. package/dist/theme/initial-theme.cjs.map +1 -1
  1407. package/dist/theme/initial-theme.js.map +1 -1
  1408. package/dist/theme/inverse-render.cjs.map +1 -1
  1409. package/dist/theme/inverse-render.js.map +1 -1
  1410. package/dist/theme/inverse-restore.cjs.map +1 -1
  1411. package/dist/theme/inverse-restore.js.map +1 -1
  1412. package/dist/theme/inverse-surface.cjs.map +1 -1
  1413. package/dist/theme/inverse-surface.js.map +1 -1
  1414. package/dist/theme/status-tokens.cjs.map +1 -1
  1415. package/dist/theme/status-tokens.js.map +1 -1
  1416. package/dist/theme/theme-presets.cjs.map +1 -1
  1417. package/dist/theme/theme-presets.js.map +1 -1
  1418. package/dist/utils/absent.cjs.map +1 -1
  1419. package/dist/utils/absent.js.map +1 -1
  1420. package/dist/utils/arrays.cjs.map +1 -1
  1421. package/dist/utils/arrays.js.map +1 -1
  1422. package/dist/utils/base64.cjs.map +1 -1
  1423. package/dist/utils/base64.js.map +1 -1
  1424. package/dist/utils/cn.cjs.map +1 -1
  1425. package/dist/utils/cn.js.map +1 -1
  1426. package/dist/utils/compare-values.cjs.map +1 -1
  1427. package/dist/utils/compare-values.js.map +1 -1
  1428. package/dist/utils/compressed-storage.cjs.map +1 -1
  1429. package/dist/utils/compressed-storage.js.map +1 -1
  1430. package/dist/utils/csv.cjs.map +1 -1
  1431. package/dist/utils/csv.js.map +1 -1
  1432. package/dist/utils/dev-mode.cjs.map +1 -1
  1433. package/dist/utils/dev-mode.js.map +1 -1
  1434. package/dist/utils/duplicate-instance.cjs.map +1 -1
  1435. package/dist/utils/duplicate-instance.js.map +1 -1
  1436. package/dist/utils/format.cjs.map +1 -1
  1437. package/dist/utils/format.js.map +1 -1
  1438. package/dist/utils/functions.cjs +1 -1
  1439. package/dist/utils/functions.cjs.map +1 -1
  1440. package/dist/utils/functions.js +1 -1
  1441. package/dist/utils/functions.js.map +1 -1
  1442. package/dist/utils/guards.cjs.map +1 -1
  1443. package/dist/utils/guards.js.map +1 -1
  1444. package/dist/utils/ids.cjs.map +1 -1
  1445. package/dist/utils/ids.js.map +1 -1
  1446. package/dist/utils/intl-cache.cjs.map +1 -1
  1447. package/dist/utils/intl-cache.js.map +1 -1
  1448. package/dist/utils/json-frame.cjs.map +1 -1
  1449. package/dist/utils/json-frame.js.map +1 -1
  1450. package/dist/utils/numbers.cjs.map +1 -1
  1451. package/dist/utils/numbers.js.map +1 -1
  1452. package/dist/utils/objects.cjs.map +1 -1
  1453. package/dist/utils/objects.js.map +1 -1
  1454. package/dist/utils/owner-fingerprint.cjs.map +1 -1
  1455. package/dist/utils/owner-fingerprint.js.map +1 -1
  1456. package/dist/utils/promises.cjs.map +1 -1
  1457. package/dist/utils/promises.js.map +1 -1
  1458. package/dist/utils/relative-time.cjs.map +1 -1
  1459. package/dist/utils/relative-time.js.map +1 -1
  1460. package/dist/utils/safe-url.cjs.map +1 -1
  1461. package/dist/utils/safe-url.js.map +1 -1
  1462. package/dist/utils/schema-like.cjs.map +1 -1
  1463. package/dist/utils/schema-like.js.map +1 -1
  1464. package/dist/utils/storage.cjs +1 -1
  1465. package/dist/utils/storage.cjs.map +1 -1
  1466. package/dist/utils/storage.js +2 -2
  1467. package/dist/utils/storage.js.map +1 -1
  1468. package/dist/utils/strings.cjs.map +1 -1
  1469. package/dist/utils/strings.js.map +1 -1
  1470. package/dist/utils/xlsx.cjs.map +1 -1
  1471. package/dist/utils/xlsx.js.map +1 -1
  1472. package/dist/vision/core/canvas.cjs.map +1 -1
  1473. package/dist/vision/core/canvas.js.map +1 -1
  1474. package/dist/vision/core/dtypes.cjs.map +1 -1
  1475. package/dist/vision/core/dtypes.js.map +1 -1
  1476. package/dist/vision/core/exceptions.cjs.map +1 -1
  1477. package/dist/vision/core/exceptions.js.map +1 -1
  1478. package/dist/vision/core/graph.cjs.map +1 -1
  1479. package/dist/vision/core/graph.js.map +1 -1
  1480. package/dist/vision/core/metadata.cjs +1 -1
  1481. package/dist/vision/core/metadata.cjs.map +1 -1
  1482. package/dist/vision/core/metadata.js +9 -26
  1483. package/dist/vision/core/metadata.js.map +1 -1
  1484. package/dist/vision/core/providers.cjs.map +1 -1
  1485. package/dist/vision/core/providers.js.map +1 -1
  1486. package/dist/vision/core/session.cjs.map +1 -1
  1487. package/dist/vision/core/session.js.map +1 -1
  1488. package/dist/vision/core/timing.cjs.map +1 -1
  1489. package/dist/vision/core/timing.js.map +1 -1
  1490. package/dist/vision/fusion.cjs.map +1 -1
  1491. package/dist/vision/fusion.js.map +1 -1
  1492. package/dist/vision/index.cjs.map +1 -1
  1493. package/dist/vision/index.js.map +1 -1
  1494. package/dist/vision/io/image.cjs.map +1 -1
  1495. package/dist/vision/io/image.js.map +1 -1
  1496. package/dist/vision/labels.cjs.map +1 -1
  1497. package/dist/vision/labels.js.map +1 -1
  1498. package/dist/vision/luminance.cjs.map +1 -1
  1499. package/dist/vision/luminance.js.map +1 -1
  1500. package/dist/vision/normalization.cjs.map +1 -1
  1501. package/dist/vision/normalization.js.map +1 -1
  1502. package/dist/vision/postprocess/classification.cjs.map +1 -1
  1503. package/dist/vision/postprocess/classification.js.map +1 -1
  1504. package/dist/vision/postprocess/detection.cjs.map +1 -1
  1505. package/dist/vision/postprocess/detection.js.map +1 -1
  1506. package/dist/vision/postprocess/segmentation.cjs.map +1 -1
  1507. package/dist/vision/postprocess/segmentation.js.map +1 -1
  1508. package/dist/vision/preprocess/image.cjs.map +1 -1
  1509. package/dist/vision/preprocess/image.js.map +1 -1
  1510. package/dist/vision/preprocess/pipeline.cjs.map +1 -1
  1511. package/dist/vision/preprocess/pipeline.js.map +1 -1
  1512. package/dist/vision/results.cjs.map +1 -1
  1513. package/dist/vision/results.js.map +1 -1
  1514. package/dist/vision/tasks/base.cjs.map +1 -1
  1515. package/dist/vision/tasks/base.js.map +1 -1
  1516. package/dist/vision/tasks/classifier.cjs.map +1 -1
  1517. package/dist/vision/tasks/classifier.js.map +1 -1
  1518. package/dist/vision/tasks/detectClassify.cjs.map +1 -1
  1519. package/dist/vision/tasks/detectClassify.js.map +1 -1
  1520. package/dist/vision/tasks/detector.cjs.map +1 -1
  1521. package/dist/vision/tasks/detector.js.map +1 -1
  1522. package/dist/vision/tasks/segmenter.cjs.map +1 -1
  1523. package/dist/vision/tasks/segmenter.js.map +1 -1
  1524. package/dist/vision/types.cjs.map +1 -1
  1525. package/dist/vision/types.js.map +1 -1
  1526. package/dist/vision/use-camera-stream.cjs +1 -1
  1527. package/dist/vision/use-camera-stream.cjs.map +1 -1
  1528. package/dist/vision/use-camera-stream.js +3 -9
  1529. package/dist/vision/use-camera-stream.js.map +1 -1
  1530. package/dist/vision/use-live-luminance.cjs +1 -1
  1531. package/dist/vision/use-live-luminance.cjs.map +1 -1
  1532. package/dist/vision/use-live-luminance.js +1 -5
  1533. package/dist/vision/use-live-luminance.js.map +1 -1
  1534. package/dist/vite/base-url.cjs.map +1 -1
  1535. package/dist/vite/base-url.js.map +1 -1
  1536. package/dist/vite/create-vite-config.cjs.map +1 -1
  1537. package/dist/vite/create-vite-config.js.map +1 -1
  1538. package/dist/vite/narrow-tokens.cjs.map +1 -1
  1539. package/dist/vite/narrow-tokens.js.map +1 -1
  1540. package/dist/vite/tempest-csp.cjs +1 -1
  1541. package/dist/vite/tempest-csp.cjs.map +1 -1
  1542. package/dist/vite/tempest-csp.js +2 -10
  1543. package/dist/vite/tempest-csp.js.map +1 -1
  1544. package/dist/vite/tempest-icons.cjs.map +1 -1
  1545. package/dist/vite/tempest-icons.js.map +1 -1
  1546. package/dist/vite/tempest-pwa-dev-sw.cjs +1 -1
  1547. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  1548. package/dist/vite/tempest-pwa-dev-sw.js +9 -16
  1549. package/dist/vite/tempest-pwa-dev-sw.js.map +1 -1
  1550. package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
  1551. package/dist/vite/tempest-pwa-icons.js.map +1 -1
  1552. package/dist/vite/tempest-pwa-manifest.cjs.map +1 -1
  1553. package/dist/vite/tempest-pwa-manifest.js.map +1 -1
  1554. package/dist/vite/tempest-styles.cjs.map +1 -1
  1555. package/dist/vite/tempest-styles.js.map +1 -1
  1556. package/dist/vite/tempest-vitest.cjs.map +1 -1
  1557. package/dist/vite/tempest-vitest.js.map +1 -1
  1558. package/dist/webrtc/link-stats.cjs.map +1 -1
  1559. package/dist/webrtc/link-stats.js.map +1 -1
  1560. package/dist/webrtc/mesh-quality.cjs.map +1 -1
  1561. package/dist/webrtc/mesh-quality.js.map +1 -1
  1562. package/dist/webrtc/opus-sdp.cjs.map +1 -1
  1563. package/dist/webrtc/opus-sdp.js.map +1 -1
  1564. package/dist/webrtc/peer-link.cjs +1 -1
  1565. package/dist/webrtc/peer-link.cjs.map +1 -1
  1566. package/dist/webrtc/peer-link.js +2 -5
  1567. package/dist/webrtc/peer-link.js.map +1 -1
  1568. package/dist/webrtc/peer-mesh.cjs +1 -1
  1569. package/dist/webrtc/peer-mesh.cjs.map +1 -1
  1570. package/dist/webrtc/peer-mesh.js +8 -24
  1571. package/dist/webrtc/peer-mesh.js.map +1 -1
  1572. package/dist/webrtc/sender-bitrate.cjs.map +1 -1
  1573. package/dist/webrtc/sender-bitrate.js.map +1 -1
  1574. package/dist/webrtc/use-link-stats.cjs.map +1 -1
  1575. package/dist/webrtc/use-link-stats.js.map +1 -1
  1576. package/dist/ws/create-web-socket.cjs +1 -1
  1577. package/dist/ws/create-web-socket.cjs.map +1 -1
  1578. package/dist/ws/create-web-socket.js +4 -22
  1579. package/dist/ws/create-web-socket.js.map +1 -1
  1580. package/dist/ws/resilience.cjs.map +1 -1
  1581. package/dist/ws/resilience.js.map +1 -1
  1582. package/dist/ws/use-web-socket.cjs.map +1 -1
  1583. package/dist/ws/use-web-socket.js.map +1 -1
  1584. package/package.json +9 -6
  1585. package/template/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"build-url.cjs","names":[],"sources":["../../src/http/build-url.ts"],"sourcesContent":["/**\n * Matches a path that already carries its own scheme (`https:`, `blob:`), which\n * makes it an absolute URL rather than something to resolve against the base.\n */\nconst ABSOLUTE_URL = /^[a-z][a-z\\d+\\-.]*:/i;\n\n/** Split a path into its non-empty segments, dropping surrounding slashes. */\nfunction segments(path: string): string[] {\n return path.split(\"/\").filter(Boolean);\n}\n\n/**\n * Whether `path` already starts with every segment of `prefix`.\n *\n * Compared segment by segment, so a `/api` prefix is not considered present in\n * `/api-keys` — a plain `startsWith` would swallow the resource.\n *\n * @param path - Segments of the request path.\n * @param prefix - Segments of the base path.\n * @returns Whether the prefix is already applied.\n */\nfunction startsWithSegments(path: string[], prefix: string[]): boolean {\n if (prefix.length === 0 || prefix.length > path.length) return false;\n return prefix.every((segment, index) => path[index] === segment);\n}\n\n/**\n * Resolve the origin a relative `baseURL` hangs off.\n *\n * A base such as `\"/api\"` is the shape you get behind a dev-server proxy or a\n * reverse proxy that serves app and API from one host. It only means something\n * in a browsing context, so this throws with the config to fix rather than\n * letting `new URL` report `Invalid base URL` from three frames deeper.\n *\n * @param baseURL - The base as the caller wrote it.\n * @returns The origin to resolve against.\n * @throws When there is no `location` to borrow an origin from.\n */\nfunction currentOrigin(baseURL: string): string {\n const origin = globalThis.location?.origin;\n if (!origin) {\n throw new TypeError(\n `createApiClient: baseURL \"${baseURL}\" is relative and there is no location to resolve it against. Pass an absolute URL (https://api.example.com) outside the browser.`,\n );\n }\n return origin;\n}\n\n/** Options accepted by {@link buildApiUrl}. */\nexport interface BuildApiUrlOptions {\n /**\n * Path segment every request is nested under, such as `\"/api\"`. Joined\n * after the path the `baseURL` already carries.\n */\n prefix?: string;\n /** Query params to append. `undefined` and `null` values are skipped. */\n params?: Record<string, string | number | boolean | undefined | null>;\n}\n\n/**\n * Join a base URL, an optional prefix and a request path into an absolute URL.\n *\n * `new URL(path, base)` on its own is wrong for an API client. It follows the\n * URL spec, where a path starting with `/` is absolute against the *origin* and\n * therefore discards whatever path the base carried: a client on\n * `https://api.example.com/api` asked for `/auth/login` reaches\n * `https://api.example.com/auth/login`, and every request 404s with nothing in\n * the config that looks wrong. This function resolves the path against the base\n * *path* instead, so the leading slash is a matter of taste rather than a\n * silent 404, and `baseURL` + `prefix` are interchangeable ways to say the same\n * thing.\n *\n * The prefix is applied at most once: a path that already opens with it — say\n * `\"/api/auth/login\"` under a `\"/api\"` prefix — is left alone, so a codebase\n * migrating to `prefix` can move its call sites one at a time. The check is per\n * segment, so `/api-keys` is not mistaken for an already-prefixed path.\n *\n * A path that is itself an absolute URL wins over all of this, which is how a\n * client reaches a second host (a signed upload endpoint, a CDN) without a\n * second client.\n *\n * @example\n * buildApiUrl(\"https://api.example.com\", \"/auth/login\", { prefix: \"/api\" });\n * // \"https://api.example.com/api/auth/login\"\n *\n * buildApiUrl(\"https://api.example.com/api\", \"auth/login\");\n * // \"https://api.example.com/api/auth/login\"\n *\n * @param baseURL - Absolute base URL, or a path relative to the current origin.\n * @param path - The request path, or an absolute URL to use as-is.\n * @param options - Optional prefix and query params.\n * @returns The absolute URL to fetch.\n * @throws When `baseURL` is relative and there is no `location` to resolve it.\n */\nexport function buildApiUrl(\n baseURL: string,\n path: string,\n options: BuildApiUrlOptions = {},\n): string {\n const { prefix, params } = options;\n const url = ABSOLUTE_URL.test(path) ? new URL(path) : new URL(resolve(baseURL, path, prefix));\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\n/**\n * Build the absolute URL string for a path that is not already absolute.\n *\n * Kept separate from {@link buildApiUrl} so the query-param loop is not nested\n * inside the joining rules.\n *\n * @param baseURL - Absolute base URL, or a path relative to the current origin.\n * @param path - The request path.\n * @param prefix - Optional segment every request is nested under.\n * @returns The joined absolute URL.\n */\nfunction resolve(baseURL: string, path: string, prefix?: string): string {\n const base = ABSOLUTE_URL.test(baseURL)\n ? new URL(baseURL)\n : new URL(baseURL, currentOrigin(baseURL));\n\n const queryStart = path.indexOf(\"?\");\n const rawPath = queryStart === -1 ? path : path.slice(0, queryStart);\n const query = queryStart === -1 ? \"\" : path.slice(queryStart);\n\n const basePath = [...segments(base.pathname), ...segments(prefix ?? \"\")];\n const requested = segments(rawPath);\n const joined = startsWithSegments(requested, basePath)\n ? requested\n : [...basePath, ...requested];\n\n const trailing = rawPath.endsWith(\"/\") ? \"/\" : \"\";\n const pathname = joined.length > 0 ? `/${joined.join(\"/\")}${trailing}` : \"/\";\n return `${base.origin}${pathname}${query}`;\n}\n"],"mappings":"AAIA,IAAM,EAAe,uBAGrB,SAAS,EAAS,EAAwB,CACtC,OAAO,EAAK,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CACzC,CAYA,SAAS,EAAmB,EAAgB,EAA2B,CAEnE,OADI,EAAO,SAAW,GAAK,EAAO,OAAS,EAAK,OAAe,GACxD,EAAO,OAAO,EAAS,IAAU,EAAK,KAAW,CAAO,CACnE,CAcA,SAAS,EAAc,EAAyB,CAC5C,IAAM,EAAS,WAAW,UAAU,OACpC,GAAI,CAAC,EACD,MAAU,UACN,6BAA6B,EAAQ,kIACzC,EAEJ,OAAO,CACX,CAgDA,SAAgB,EACZ,EACA,EACA,EAA8B,CAAC,EACzB,CACN,GAAM,CAAE,SAAQ,UAAW,EACrB,EAAM,EAAa,KAAK,CAAI,EAAI,IAAI,IAAI,CAAI,EAAI,IAAI,IAAI,EAAQ,EAAS,EAAM,CAAM,CAAC,EAE5F,GAAI,EACK,IAAA,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAM,EACxC,GAAiC,MACjC,EAAI,aAAa,IAAI,EAAK,OAAO,CAAK,CAAC,EAInD,OAAO,EAAI,SAAS,CACxB,CAaA,SAAS,EAAQ,EAAiB,EAAc,EAAyB,CACrE,IAAM,EAAO,EAAa,KAAK,CAAO,EAChC,IAAI,IAAI,CAAO,EACf,IAAI,IAAI,EAAS,EAAc,CAAO,CAAC,EAEvC,EAAa,EAAK,QAAQ,GAAG,EAC7B,EAAU,IAAe,GAAK,EAAO,EAAK,MAAM,EAAG,CAAU,EAC7D,EAAQ,IAAe,GAAK,GAAK,EAAK,MAAM,CAAU,EAEtD,EAAW,CAAC,GAAG,EAAS,EAAK,QAAQ,EAAG,GAAG,EAAS,GAAU,EAAE,CAAC,EACjE,EAAY,EAAS,CAAO,EAC5B,EAAS,EAAmB,EAAW,CAAQ,EAC/C,EACA,CAAC,GAAG,EAAU,GAAG,CAAS,EAE1B,EAAW,EAAQ,SAAS,GAAG,EAAI,IAAM,GACzC,EAAW,EAAO,OAAS,EAAI,IAAI,EAAO,KAAK,GAAG,IAAI,IAAa,IACzE,MAAO,GAAG,EAAK,SAAS,IAAW,GACvC"}
1
+ {"version":3,"file":"build-url.cjs","names":["ABSOLUTE_URL","segments","path","startsWithSegments","prefix","index","segment","currentOrigin","origin","baseURL","buildApiUrl","options","url","resolve","params","key","value","base","queryStart","rawPath","query","basePath","requested","joined","trailing","pathname"],"sources":["../../src/http/build-url.ts"],"sourcesContent":["/**\n * Matches a path that already carries its own scheme (`https:`, `blob:`), which\n * makes it an absolute URL rather than something to resolve against the base.\n */\nconst ABSOLUTE_URL = /^[a-z][a-z\\d+\\-.]*:/i;\n\n/** Split a path into its non-empty segments, dropping surrounding slashes. */\nfunction segments(path: string): string[] {\n return path.split(\"/\").filter(Boolean);\n}\n\n/**\n * Whether `path` already starts with every segment of `prefix`.\n *\n * Compared segment by segment, so a `/api` prefix is not considered present in\n * `/api-keys` — a plain `startsWith` would swallow the resource.\n *\n * @param path - Segments of the request path.\n * @param prefix - Segments of the base path.\n * @returns Whether the prefix is already applied.\n */\nfunction startsWithSegments(path: string[], prefix: string[]): boolean {\n if (prefix.length === 0 || prefix.length > path.length) return false;\n return prefix.every((segment, index) => path[index] === segment);\n}\n\n/**\n * Resolve the origin a relative `baseURL` hangs off.\n *\n * A base such as `\"/api\"` is the shape you get behind a dev-server proxy or a\n * reverse proxy that serves app and API from one host. It only means something\n * in a browsing context, so this throws with the config to fix rather than\n * letting `new URL` report `Invalid base URL` from three frames deeper.\n *\n * @param baseURL - The base as the caller wrote it.\n * @returns The origin to resolve against.\n * @throws When there is no `location` to borrow an origin from.\n */\nfunction currentOrigin(baseURL: string): string {\n const origin = globalThis.location?.origin;\n if (!origin) {\n throw new TypeError(\n `createApiClient: baseURL \"${baseURL}\" is relative and there is no location to resolve it against. Pass an absolute URL (https://api.example.com) outside the browser.`,\n );\n }\n return origin;\n}\n\n/** Options accepted by {@link buildApiUrl}. */\nexport interface BuildApiUrlOptions {\n /**\n * Path segment every request is nested under, such as `\"/api\"`. Joined\n * after the path the `baseURL` already carries.\n */\n prefix?: string;\n /** Query params to append. `undefined` and `null` values are skipped. */\n params?: Record<string, string | number | boolean | undefined | null>;\n}\n\n/**\n * Join a base URL, an optional prefix and a request path into an absolute URL.\n *\n * `new URL(path, base)` on its own is wrong for an API client. It follows the\n * URL spec, where a path starting with `/` is absolute against the *origin* and\n * therefore discards whatever path the base carried: a client on\n * `https://api.example.com/api` asked for `/auth/login` reaches\n * `https://api.example.com/auth/login`, and every request 404s with nothing in\n * the config that looks wrong. This function resolves the path against the base\n * *path* instead, so the leading slash is a matter of taste rather than a\n * silent 404, and `baseURL` + `prefix` are interchangeable ways to say the same\n * thing.\n *\n * The prefix is applied at most once: a path that already opens with it — say\n * `\"/api/auth/login\"` under a `\"/api\"` prefix — is left alone, so a codebase\n * migrating to `prefix` can move its call sites one at a time. The check is per\n * segment, so `/api-keys` is not mistaken for an already-prefixed path.\n *\n * A path that is itself an absolute URL wins over all of this, which is how a\n * client reaches a second host (a signed upload endpoint, a CDN) without a\n * second client.\n *\n * @example\n * buildApiUrl(\"https://api.example.com\", \"/auth/login\", { prefix: \"/api\" });\n * // \"https://api.example.com/api/auth/login\"\n *\n * buildApiUrl(\"https://api.example.com/api\", \"auth/login\");\n * // \"https://api.example.com/api/auth/login\"\n *\n * @param baseURL - Absolute base URL, or a path relative to the current origin.\n * @param path - The request path, or an absolute URL to use as-is.\n * @param options - Optional prefix and query params.\n * @returns The absolute URL to fetch.\n * @throws When `baseURL` is relative and there is no `location` to resolve it.\n */\nexport function buildApiUrl(\n baseURL: string,\n path: string,\n options: BuildApiUrlOptions = {},\n): string {\n const { prefix, params } = options;\n const url = ABSOLUTE_URL.test(path) ? new URL(path) : new URL(resolve(baseURL, path, prefix));\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\n/**\n * Build the absolute URL string for a path that is not already absolute.\n *\n * Kept separate from {@link buildApiUrl} so the query-param loop is not nested\n * inside the joining rules.\n *\n * @param baseURL - Absolute base URL, or a path relative to the current origin.\n * @param path - The request path.\n * @param prefix - Optional segment every request is nested under.\n * @returns The joined absolute URL.\n */\nfunction resolve(baseURL: string, path: string, prefix?: string): string {\n const base = ABSOLUTE_URL.test(baseURL)\n ? new URL(baseURL)\n : new URL(baseURL, currentOrigin(baseURL));\n\n const queryStart = path.indexOf(\"?\");\n const rawPath = queryStart === -1 ? path : path.slice(0, queryStart);\n const query = queryStart === -1 ? \"\" : path.slice(queryStart);\n\n const basePath = [...segments(base.pathname), ...segments(prefix ?? \"\")];\n const requested = segments(rawPath);\n const joined = startsWithSegments(requested, basePath)\n ? requested\n : [...basePath, ...requested];\n\n const trailing = rawPath.endsWith(\"/\") ? \"/\" : \"\";\n const pathname = joined.length > 0 ? `/${joined.join(\"/\")}${trailing}` : \"/\";\n return `${base.origin}${pathname}${query}`;\n}\n"],"mappings":"AAIA,IAAMA,EAAe,uBAGrB,SAASC,EAAS,EAAwB,CACtC,OAAOC,EAAK,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CACzC,CAYA,SAASC,EAAmB,EAAgB,EAA2B,CAEnE,OADIC,EAAO,SAAW,GAAKA,EAAO,OAASF,EAAK,OAAe,GACxDE,EAAO,OAAO,EAAS,IAAUF,EAAKG,KAAWC,CAAO,CACnE,CAcA,SAASC,EAAc,EAAyB,CAC5C,IAAMC,EAAS,WAAW,UAAU,OACpC,GAAI,CAACA,EACD,MAAU,UACN,6BAA6BC,EAAQ,kIACzC,EAEJ,OAAOD,CACX,CAgDA,SAAgBE,EACZ,EACA,EACA,EAA8B,CAAC,EACzB,CACN,GAAM,CAAE,SAAQ,UAAWC,EACrBC,EAAMZ,EAAa,KAAKE,CAAI,EAAI,IAAI,IAAIA,CAAI,EAAI,IAAI,IAAIW,EAAQJ,EAASP,EAAME,CAAM,CAAC,EAE5F,GAAIU,EACK,IAAA,GAAM,CAACC,EAAKC,KAAU,OAAO,QAAQF,CAAM,EACxCE,GAAiC,MACjCJ,EAAI,aAAa,IAAIG,EAAK,OAAOC,CAAK,CAAC,EAInD,OAAOJ,EAAI,SAAS,CACxB,CAaA,SAASC,EAAQ,EAAiB,EAAc,EAAyB,CACrE,IAAMI,EAAOjB,EAAa,KAAKS,CAAO,EAChC,IAAI,IAAIA,CAAO,EACf,IAAI,IAAIA,EAASF,EAAcE,CAAO,CAAC,EAEvCS,EAAahB,EAAK,QAAQ,GAAG,EAC7BiB,EAAUD,IAAe,GAAKhB,EAAOA,EAAK,MAAM,EAAGgB,CAAU,EAC7DE,EAAQF,IAAe,GAAK,GAAKhB,EAAK,MAAMgB,CAAU,EAEtDG,EAAW,CAAC,GAAGpB,EAASgB,EAAK,QAAQ,EAAG,GAAGhB,EAASG,GAAU,EAAE,CAAC,EACjEkB,EAAYrB,EAASkB,CAAO,EAC5BI,EAASpB,EAAmBmB,EAAWD,CAAQ,EAC/CC,EACA,CAAC,GAAGD,EAAU,GAAGC,CAAS,EAE1BE,EAAWL,EAAQ,SAAS,GAAG,EAAI,IAAM,GACzCM,EAAWF,EAAO,OAAS,EAAI,IAAIA,EAAO,KAAK,GAAG,IAAIC,IAAa,IACzE,MAAO,GAAGP,EAAK,SAASQ,IAAWL,GACvC,C"}
@@ -1 +1 @@
1
- {"version":3,"file":"build-url.js","names":[],"sources":["../../src/http/build-url.ts"],"sourcesContent":["/**\n * Matches a path that already carries its own scheme (`https:`, `blob:`), which\n * makes it an absolute URL rather than something to resolve against the base.\n */\nconst ABSOLUTE_URL = /^[a-z][a-z\\d+\\-.]*:/i;\n\n/** Split a path into its non-empty segments, dropping surrounding slashes. */\nfunction segments(path: string): string[] {\n return path.split(\"/\").filter(Boolean);\n}\n\n/**\n * Whether `path` already starts with every segment of `prefix`.\n *\n * Compared segment by segment, so a `/api` prefix is not considered present in\n * `/api-keys` — a plain `startsWith` would swallow the resource.\n *\n * @param path - Segments of the request path.\n * @param prefix - Segments of the base path.\n * @returns Whether the prefix is already applied.\n */\nfunction startsWithSegments(path: string[], prefix: string[]): boolean {\n if (prefix.length === 0 || prefix.length > path.length) return false;\n return prefix.every((segment, index) => path[index] === segment);\n}\n\n/**\n * Resolve the origin a relative `baseURL` hangs off.\n *\n * A base such as `\"/api\"` is the shape you get behind a dev-server proxy or a\n * reverse proxy that serves app and API from one host. It only means something\n * in a browsing context, so this throws with the config to fix rather than\n * letting `new URL` report `Invalid base URL` from three frames deeper.\n *\n * @param baseURL - The base as the caller wrote it.\n * @returns The origin to resolve against.\n * @throws When there is no `location` to borrow an origin from.\n */\nfunction currentOrigin(baseURL: string): string {\n const origin = globalThis.location?.origin;\n if (!origin) {\n throw new TypeError(\n `createApiClient: baseURL \"${baseURL}\" is relative and there is no location to resolve it against. Pass an absolute URL (https://api.example.com) outside the browser.`,\n );\n }\n return origin;\n}\n\n/** Options accepted by {@link buildApiUrl}. */\nexport interface BuildApiUrlOptions {\n /**\n * Path segment every request is nested under, such as `\"/api\"`. Joined\n * after the path the `baseURL` already carries.\n */\n prefix?: string;\n /** Query params to append. `undefined` and `null` values are skipped. */\n params?: Record<string, string | number | boolean | undefined | null>;\n}\n\n/**\n * Join a base URL, an optional prefix and a request path into an absolute URL.\n *\n * `new URL(path, base)` on its own is wrong for an API client. It follows the\n * URL spec, where a path starting with `/` is absolute against the *origin* and\n * therefore discards whatever path the base carried: a client on\n * `https://api.example.com/api` asked for `/auth/login` reaches\n * `https://api.example.com/auth/login`, and every request 404s with nothing in\n * the config that looks wrong. This function resolves the path against the base\n * *path* instead, so the leading slash is a matter of taste rather than a\n * silent 404, and `baseURL` + `prefix` are interchangeable ways to say the same\n * thing.\n *\n * The prefix is applied at most once: a path that already opens with it — say\n * `\"/api/auth/login\"` under a `\"/api\"` prefix — is left alone, so a codebase\n * migrating to `prefix` can move its call sites one at a time. The check is per\n * segment, so `/api-keys` is not mistaken for an already-prefixed path.\n *\n * A path that is itself an absolute URL wins over all of this, which is how a\n * client reaches a second host (a signed upload endpoint, a CDN) without a\n * second client.\n *\n * @example\n * buildApiUrl(\"https://api.example.com\", \"/auth/login\", { prefix: \"/api\" });\n * // \"https://api.example.com/api/auth/login\"\n *\n * buildApiUrl(\"https://api.example.com/api\", \"auth/login\");\n * // \"https://api.example.com/api/auth/login\"\n *\n * @param baseURL - Absolute base URL, or a path relative to the current origin.\n * @param path - The request path, or an absolute URL to use as-is.\n * @param options - Optional prefix and query params.\n * @returns The absolute URL to fetch.\n * @throws When `baseURL` is relative and there is no `location` to resolve it.\n */\nexport function buildApiUrl(\n baseURL: string,\n path: string,\n options: BuildApiUrlOptions = {},\n): string {\n const { prefix, params } = options;\n const url = ABSOLUTE_URL.test(path) ? new URL(path) : new URL(resolve(baseURL, path, prefix));\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\n/**\n * Build the absolute URL string for a path that is not already absolute.\n *\n * Kept separate from {@link buildApiUrl} so the query-param loop is not nested\n * inside the joining rules.\n *\n * @param baseURL - Absolute base URL, or a path relative to the current origin.\n * @param path - The request path.\n * @param prefix - Optional segment every request is nested under.\n * @returns The joined absolute URL.\n */\nfunction resolve(baseURL: string, path: string, prefix?: string): string {\n const base = ABSOLUTE_URL.test(baseURL)\n ? new URL(baseURL)\n : new URL(baseURL, currentOrigin(baseURL));\n\n const queryStart = path.indexOf(\"?\");\n const rawPath = queryStart === -1 ? path : path.slice(0, queryStart);\n const query = queryStart === -1 ? \"\" : path.slice(queryStart);\n\n const basePath = [...segments(base.pathname), ...segments(prefix ?? \"\")];\n const requested = segments(rawPath);\n const joined = startsWithSegments(requested, basePath)\n ? requested\n : [...basePath, ...requested];\n\n const trailing = rawPath.endsWith(\"/\") ? \"/\" : \"\";\n const pathname = joined.length > 0 ? `/${joined.join(\"/\")}${trailing}` : \"/\";\n return `${base.origin}${pathname}${query}`;\n}\n"],"mappings":";AAIA,IAAM,IAAe;AAGrB,SAAS,EAAS,GAAwB;CACtC,OAAO,EAAK,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO;AACzC;AAYA,SAAS,EAAmB,GAAgB,GAA2B;CAEnE,OADI,EAAO,WAAW,KAAK,EAAO,SAAS,EAAK,SAAe,KACxD,EAAO,OAAO,GAAS,MAAU,EAAK,OAAW,CAAO;AACnE;AAcA,SAAS,EAAc,GAAyB;CAC5C,IAAM,IAAS,WAAW,UAAU;CACpC,IAAI,CAAC,GACD,MAAU,UACN,6BAA6B,EAAQ,kIACzC;CAEJ,OAAO;AACX;AAgDA,SAAgB,EACZ,GACA,GACA,IAA8B,CAAC,GACzB;CACN,IAAM,EAAE,WAAQ,cAAW,GACrB,IAAM,EAAa,KAAK,CAAI,IAAI,IAAI,IAAI,CAAI,IAAI,IAAI,IAAI,EAAQ,GAAS,GAAM,CAAM,CAAC;CAE5F,IAAI,GACK,KAAA,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,CAAM,GAC5C,AAAI,KAAiC,QACjC,EAAI,aAAa,IAAI,GAAK,OAAO,CAAK,CAAC;CAInD,OAAO,EAAI,SAAS;AACxB;AAaA,SAAS,EAAQ,GAAiB,GAAc,GAAyB;CACrE,IAAM,IAAO,EAAa,KAAK,CAAO,IAChC,IAAI,IAAI,CAAO,IACf,IAAI,IAAI,GAAS,EAAc,CAAO,CAAC,GAEvC,IAAa,EAAK,QAAQ,GAAG,GAC7B,IAAU,MAAe,KAAK,IAAO,EAAK,MAAM,GAAG,CAAU,GAC7D,IAAQ,MAAe,KAAK,KAAK,EAAK,MAAM,CAAU,GAEtD,IAAW,CAAC,GAAG,EAAS,EAAK,QAAQ,GAAG,GAAG,EAAS,KAAU,EAAE,CAAC,GACjE,IAAY,EAAS,CAAO,GAC5B,IAAS,EAAmB,GAAW,CAAQ,IAC/C,IACA,CAAC,GAAG,GAAU,GAAG,CAAS,GAE1B,IAAW,EAAQ,SAAS,GAAG,IAAI,MAAM,IACzC,IAAW,EAAO,SAAS,IAAI,IAAI,EAAO,KAAK,GAAG,IAAI,MAAa;CACzE,OAAO,GAAG,EAAK,SAAS,IAAW;AACvC"}
1
+ {"version":3,"file":"build-url.js","names":["ABSOLUTE_URL","segments","path","startsWithSegments","prefix","index","segment","currentOrigin","origin","baseURL","buildApiUrl","options","url","resolve","params","key","value","base","queryStart","rawPath","query","basePath","requested","joined","trailing","pathname"],"sources":["../../src/http/build-url.ts"],"sourcesContent":["/**\n * Matches a path that already carries its own scheme (`https:`, `blob:`), which\n * makes it an absolute URL rather than something to resolve against the base.\n */\nconst ABSOLUTE_URL = /^[a-z][a-z\\d+\\-.]*:/i;\n\n/** Split a path into its non-empty segments, dropping surrounding slashes. */\nfunction segments(path: string): string[] {\n return path.split(\"/\").filter(Boolean);\n}\n\n/**\n * Whether `path` already starts with every segment of `prefix`.\n *\n * Compared segment by segment, so a `/api` prefix is not considered present in\n * `/api-keys` — a plain `startsWith` would swallow the resource.\n *\n * @param path - Segments of the request path.\n * @param prefix - Segments of the base path.\n * @returns Whether the prefix is already applied.\n */\nfunction startsWithSegments(path: string[], prefix: string[]): boolean {\n if (prefix.length === 0 || prefix.length > path.length) return false;\n return prefix.every((segment, index) => path[index] === segment);\n}\n\n/**\n * Resolve the origin a relative `baseURL` hangs off.\n *\n * A base such as `\"/api\"` is the shape you get behind a dev-server proxy or a\n * reverse proxy that serves app and API from one host. It only means something\n * in a browsing context, so this throws with the config to fix rather than\n * letting `new URL` report `Invalid base URL` from three frames deeper.\n *\n * @param baseURL - The base as the caller wrote it.\n * @returns The origin to resolve against.\n * @throws When there is no `location` to borrow an origin from.\n */\nfunction currentOrigin(baseURL: string): string {\n const origin = globalThis.location?.origin;\n if (!origin) {\n throw new TypeError(\n `createApiClient: baseURL \"${baseURL}\" is relative and there is no location to resolve it against. Pass an absolute URL (https://api.example.com) outside the browser.`,\n );\n }\n return origin;\n}\n\n/** Options accepted by {@link buildApiUrl}. */\nexport interface BuildApiUrlOptions {\n /**\n * Path segment every request is nested under, such as `\"/api\"`. Joined\n * after the path the `baseURL` already carries.\n */\n prefix?: string;\n /** Query params to append. `undefined` and `null` values are skipped. */\n params?: Record<string, string | number | boolean | undefined | null>;\n}\n\n/**\n * Join a base URL, an optional prefix and a request path into an absolute URL.\n *\n * `new URL(path, base)` on its own is wrong for an API client. It follows the\n * URL spec, where a path starting with `/` is absolute against the *origin* and\n * therefore discards whatever path the base carried: a client on\n * `https://api.example.com/api` asked for `/auth/login` reaches\n * `https://api.example.com/auth/login`, and every request 404s with nothing in\n * the config that looks wrong. This function resolves the path against the base\n * *path* instead, so the leading slash is a matter of taste rather than a\n * silent 404, and `baseURL` + `prefix` are interchangeable ways to say the same\n * thing.\n *\n * The prefix is applied at most once: a path that already opens with it — say\n * `\"/api/auth/login\"` under a `\"/api\"` prefix — is left alone, so a codebase\n * migrating to `prefix` can move its call sites one at a time. The check is per\n * segment, so `/api-keys` is not mistaken for an already-prefixed path.\n *\n * A path that is itself an absolute URL wins over all of this, which is how a\n * client reaches a second host (a signed upload endpoint, a CDN) without a\n * second client.\n *\n * @example\n * buildApiUrl(\"https://api.example.com\", \"/auth/login\", { prefix: \"/api\" });\n * // \"https://api.example.com/api/auth/login\"\n *\n * buildApiUrl(\"https://api.example.com/api\", \"auth/login\");\n * // \"https://api.example.com/api/auth/login\"\n *\n * @param baseURL - Absolute base URL, or a path relative to the current origin.\n * @param path - The request path, or an absolute URL to use as-is.\n * @param options - Optional prefix and query params.\n * @returns The absolute URL to fetch.\n * @throws When `baseURL` is relative and there is no `location` to resolve it.\n */\nexport function buildApiUrl(\n baseURL: string,\n path: string,\n options: BuildApiUrlOptions = {},\n): string {\n const { prefix, params } = options;\n const url = ABSOLUTE_URL.test(path) ? new URL(path) : new URL(resolve(baseURL, path, prefix));\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\n/**\n * Build the absolute URL string for a path that is not already absolute.\n *\n * Kept separate from {@link buildApiUrl} so the query-param loop is not nested\n * inside the joining rules.\n *\n * @param baseURL - Absolute base URL, or a path relative to the current origin.\n * @param path - The request path.\n * @param prefix - Optional segment every request is nested under.\n * @returns The joined absolute URL.\n */\nfunction resolve(baseURL: string, path: string, prefix?: string): string {\n const base = ABSOLUTE_URL.test(baseURL)\n ? new URL(baseURL)\n : new URL(baseURL, currentOrigin(baseURL));\n\n const queryStart = path.indexOf(\"?\");\n const rawPath = queryStart === -1 ? path : path.slice(0, queryStart);\n const query = queryStart === -1 ? \"\" : path.slice(queryStart);\n\n const basePath = [...segments(base.pathname), ...segments(prefix ?? \"\")];\n const requested = segments(rawPath);\n const joined = startsWithSegments(requested, basePath)\n ? requested\n : [...basePath, ...requested];\n\n const trailing = rawPath.endsWith(\"/\") ? \"/\" : \"\";\n const pathname = joined.length > 0 ? `/${joined.join(\"/\")}${trailing}` : \"/\";\n return `${base.origin}${pathname}${query}`;\n}\n"],"mappings":";AAIA,IAAMA,IAAe;AAGrB,SAASC,EAAS,GAAwB;CACtC,OAAOC,EAAK,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO;AACzC;AAYA,SAASC,EAAmB,GAAgB,GAA2B;CAEnE,OADIC,EAAO,WAAW,KAAKA,EAAO,SAASF,EAAK,SAAe,KACxDE,EAAO,OAAO,GAAS,MAAUF,EAAKG,OAAWC,CAAO;AACnE;AAcA,SAASC,EAAc,GAAyB;CAC5C,IAAMC,IAAS,WAAW,UAAU;CACpC,IAAI,CAACA,GACD,MAAU,UACN,6BAA6BC,EAAQ,kIACzC;CAEJ,OAAOD;AACX;AAgDA,SAAgBE,EACZ,GACA,GACA,IAA8B,CAAC,GACzB;CACN,IAAM,EAAE,WAAQ,cAAWC,GACrBC,IAAMZ,EAAa,KAAKE,CAAI,IAAI,IAAI,IAAIA,CAAI,IAAI,IAAI,IAAIW,EAAQJ,GAASP,GAAME,CAAM,CAAC;CAE5F,IAAIU,GACK,KAAA,IAAM,CAACC,GAAKC,MAAU,OAAO,QAAQF,CAAM,GAC5C,AAAIE,KAAiC,QACjCJ,EAAI,aAAa,IAAIG,GAAK,OAAOC,CAAK,CAAC;CAInD,OAAOJ,EAAI,SAAS;AACxB;AAaA,SAASC,EAAQ,GAAiB,GAAc,GAAyB;CACrE,IAAMI,IAAOjB,EAAa,KAAKS,CAAO,IAChC,IAAI,IAAIA,CAAO,IACf,IAAI,IAAIA,GAASF,EAAcE,CAAO,CAAC,GAEvCS,IAAahB,EAAK,QAAQ,GAAG,GAC7BiB,IAAUD,MAAe,KAAKhB,IAAOA,EAAK,MAAM,GAAGgB,CAAU,GAC7DE,IAAQF,MAAe,KAAK,KAAKhB,EAAK,MAAMgB,CAAU,GAEtDG,IAAW,CAAC,GAAGpB,EAASgB,EAAK,QAAQ,GAAG,GAAGhB,EAASG,KAAU,EAAE,CAAC,GACjEkB,IAAYrB,EAASkB,CAAO,GAC5BI,IAASpB,EAAmBmB,GAAWD,CAAQ,IAC/CC,IACA,CAAC,GAAGD,GAAU,GAAGC,CAAS,GAE1BE,IAAWL,EAAQ,SAAS,GAAG,IAAI,MAAM,IACzCM,IAAWF,EAAO,SAAS,IAAI,IAAIA,EAAO,KAAK,GAAG,IAAIC,MAAa;CACzE,OAAO,GAAGP,EAAK,SAASQ,IAAWL;AACvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"credential-scope.cjs","names":[],"sources":["../../src/http/credential-scope.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\n\n/**\n * Origins already reported by {@link reportSuppressedCredential}, so a chunked\n * upload warns once instead of once per chunk.\n */\nconst reported = new Set<string>();\n\n/**\n * The origin a URL resolves to, or `null` when it has none to compare.\n *\n * Relative values resolve against the document, because that is what they mean\n * everywhere else in the SDK: an `endpoint` of `\"/api/uploads\"` and a `baseURL`\n * of `\"/api\"` are the shape you get behind a dev-server or a reverse proxy, and\n * both name the page's own origin. Comparing a resolved absolute target against\n * an unresolved relative reference is how the first draft of this function\n * withheld the credential from every client configured that way.\n *\n * `null` is reserved for the case with genuinely nothing to compare: a relative\n * URL outside a browsing context, where there is no document to resolve against.\n *\n * @param url - Absolute or relative URL.\n * @returns The origin, or `null` when it cannot be resolved.\n */\nfunction originOf(url: string): string | null {\n try {\n return new URL(url, globalThis.location?.href).origin;\n } catch {\n return null;\n }\n}\n\n/**\n * Whether a request to `target` may carry the caller's credential.\n *\n * The SDK writes `Authorization: Bearer` in three places, and until 0.66.0 none\n * of them looked at where the request was going. That is only safe while every\n * target URL is written by the app: a resumable upload takes its URL from the\n * server's `Location` header, and `createApiClient` lets an absolute path\n * override `baseURL` entirely, so a URL arriving over the network could decide\n * which origin received the token — and the file bytes with it.\n *\n * Handing an upload off to object storage on another host is ordinary `tus`\n * deployment, not an attack, which is exactly why the credential must be scoped\n * rather than the request blocked: the upload still goes through, it just goes\n * without the API's bearer token.\n *\n * Both sides are resolved against the document first, so a relative `baseURL`\n * or `endpoint` — the shape behind a dev-server or reverse proxy — compares\n * equal to the absolute URL the request actually goes to. Outside a browsing\n * context a relative target resolves to nothing and is allowed: there is no\n * origin for it to cross.\n *\n * @param target - The URL the request is about to go to.\n * @param reference - The origin the credential belongs to, normally the\n * client's `baseURL` or the upload `endpoint`.\n * @param trustedOrigins - Extra origins the app declared, for the legitimate\n * second host: a CDN, a signed upload endpoint.\n * @returns Whether the credential may be attached.\n *\n * @example\n * isTrustedCredentialTarget(\"https://api.acme.com/me\", \"https://api.acme.com\");\n * // true\n * isTrustedCredentialTarget(\"https://cdn.other/u/1\", \"https://api.acme.com\");\n * // false\n */\nexport function isTrustedCredentialTarget(\n target: string,\n reference: string,\n trustedOrigins: readonly string[] = [],\n): boolean {\n const targetOrigin = originOf(target);\n if (targetOrigin === null) return true;\n if (targetOrigin === originOf(reference)) return true;\n return trustedOrigins.some((origin) => originOf(origin) === targetOrigin);\n}\n\n/**\n * Say once, in a development build, that a credential was withheld.\n *\n * Without it the symptom is a `401` (or, for the CSRF header, a `403`) from a\n * host the developer never typed, and nothing in the app's code mentions the\n * origin that produced it. Keyed by credential and target origin, so a\n * hundred-chunk upload reports one line per header it withheld.\n *\n * Silent in production for the same reason {@link parseResponse} is: the origin\n * an app talks to is not something to print into a user's console or ship to an\n * error tracker.\n *\n * @param target - The URL whose request went out unauthenticated.\n * @param reference - The origin the credential was scoped to.\n * @param header - The header that was withheld. Default `\"Authorization\"`.\n */\nexport function reportSuppressedCredential(\n target: string,\n reference: string,\n header = \"Authorization\",\n): void {\n if (!isDevBuild()) return;\n const targetOrigin = originOf(target);\n if (targetOrigin === null) return;\n const key = `${header} ${targetOrigin}`;\n if (reported.has(key)) return;\n reported.add(key);\n console.warn(\n `[tempest-react-sdk] ${header} was not sent to ${targetOrigin}: the credential is scoped to ${originOf(reference) ?? reference}. Add the origin to trustedOrigins if it should receive the token.`,\n );\n}\n\n/**\n * Forget which origins were already reported.\n *\n * Exported for tests, which assert the once-per-origin behaviour and would\n * otherwise leak state between cases.\n */\nexport function resetSuppressedCredentialReports(): void {\n reported.clear();\n}\n"],"mappings":"yCAMA,IAAM,EAAW,IAAI,IAkBrB,SAAS,EAAS,EAA4B,CAC1C,GAAI,CACA,OAAO,IAAI,IAAI,EAAK,WAAW,UAAU,IAAI,CAAC,CAAC,MACnD,MAAQ,CACJ,OAAO,IACX,CACJ,CAoCA,SAAgB,EACZ,EACA,EACA,EAAoC,CAAC,EAC9B,CACP,IAAM,EAAe,EAAS,CAAM,EAGpC,OAFI,IAAiB,MACjB,IAAiB,EAAS,CAAS,GAChC,EAAe,KAAM,GAAW,EAAS,CAAM,IAAM,CAAY,CAC5E,CAkBA,SAAgB,EACZ,EACA,EACA,EAAS,gBACL,CACJ,GAAI,CAAC,EAAA,WAAW,EAAG,OACnB,IAAM,EAAe,EAAS,CAAM,EACpC,GAAI,IAAiB,KAAM,OAC3B,IAAM,EAAM,GAAG,EAAO,GAAG,IACrB,EAAS,IAAI,CAAG,IACpB,EAAS,IAAI,CAAG,EAChB,QAAQ,KACJ,uBAAuB,EAAO,mBAAmB,EAAa,gCAAgC,EAAS,CAAS,GAAK,EAAU,mEACnI,EACJ"}
1
+ {"version":3,"file":"credential-scope.cjs","names":["isDevBuild","require_dev_mode","reported","originOf","url","isTrustedCredentialTarget","targetOrigin","target","reference","trustedOrigins","origin","reportSuppressedCredential","key","header"],"sources":["../../src/http/credential-scope.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\n\n/**\n * Origins already reported by {@link reportSuppressedCredential}, so a chunked\n * upload warns once instead of once per chunk.\n */\nconst reported = new Set<string>();\n\n/**\n * The origin a URL resolves to, or `null` when it has none to compare.\n *\n * Relative values resolve against the document, because that is what they mean\n * everywhere else in the SDK: an `endpoint` of `\"/api/uploads\"` and a `baseURL`\n * of `\"/api\"` are the shape you get behind a dev-server or a reverse proxy, and\n * both name the page's own origin. Comparing a resolved absolute target against\n * an unresolved relative reference is how the first draft of this function\n * withheld the credential from every client configured that way.\n *\n * `null` is reserved for the case with genuinely nothing to compare: a relative\n * URL outside a browsing context, where there is no document to resolve against.\n *\n * @param url - Absolute or relative URL.\n * @returns The origin, or `null` when it cannot be resolved.\n */\nfunction originOf(url: string): string | null {\n try {\n return new URL(url, globalThis.location?.href).origin;\n } catch {\n return null;\n }\n}\n\n/**\n * Whether a request to `target` may carry the caller's credential.\n *\n * The SDK writes `Authorization: Bearer` in three places, and until 0.66.0 none\n * of them looked at where the request was going. That is only safe while every\n * target URL is written by the app: a resumable upload takes its URL from the\n * server's `Location` header, and `createApiClient` lets an absolute path\n * override `baseURL` entirely, so a URL arriving over the network could decide\n * which origin received the token — and the file bytes with it.\n *\n * Handing an upload off to object storage on another host is ordinary `tus`\n * deployment, not an attack, which is exactly why the credential must be scoped\n * rather than the request blocked: the upload still goes through, it just goes\n * without the API's bearer token.\n *\n * Both sides are resolved against the document first, so a relative `baseURL`\n * or `endpoint` — the shape behind a dev-server or reverse proxy — compares\n * equal to the absolute URL the request actually goes to. Outside a browsing\n * context a relative target resolves to nothing and is allowed: there is no\n * origin for it to cross.\n *\n * @param target - The URL the request is about to go to.\n * @param reference - The origin the credential belongs to, normally the\n * client's `baseURL` or the upload `endpoint`.\n * @param trustedOrigins - Extra origins the app declared, for the legitimate\n * second host: a CDN, a signed upload endpoint.\n * @returns Whether the credential may be attached.\n *\n * @example\n * isTrustedCredentialTarget(\"https://api.acme.com/me\", \"https://api.acme.com\");\n * // true\n * isTrustedCredentialTarget(\"https://cdn.other/u/1\", \"https://api.acme.com\");\n * // false\n */\nexport function isTrustedCredentialTarget(\n target: string,\n reference: string,\n trustedOrigins: readonly string[] = [],\n): boolean {\n const targetOrigin = originOf(target);\n if (targetOrigin === null) return true;\n if (targetOrigin === originOf(reference)) return true;\n return trustedOrigins.some((origin) => originOf(origin) === targetOrigin);\n}\n\n/**\n * Say once, in a development build, that a credential was withheld.\n *\n * Without it the symptom is a `401` (or, for the CSRF header, a `403`) from a\n * host the developer never typed, and nothing in the app's code mentions the\n * origin that produced it. Keyed by credential and target origin, so a\n * hundred-chunk upload reports one line per header it withheld.\n *\n * Silent in production for the same reason {@link parseResponse} is: the origin\n * an app talks to is not something to print into a user's console or ship to an\n * error tracker.\n *\n * @param target - The URL whose request went out unauthenticated.\n * @param reference - The origin the credential was scoped to.\n * @param header - The header that was withheld. Default `\"Authorization\"`.\n */\nexport function reportSuppressedCredential(\n target: string,\n reference: string,\n header = \"Authorization\",\n): void {\n if (!isDevBuild()) return;\n const targetOrigin = originOf(target);\n if (targetOrigin === null) return;\n const key = `${header} ${targetOrigin}`;\n if (reported.has(key)) return;\n reported.add(key);\n console.warn(\n `[tempest-react-sdk] ${header} was not sent to ${targetOrigin}: the credential is scoped to ${originOf(reference) ?? reference}. Add the origin to trustedOrigins if it should receive the token.`,\n );\n}\n\n/**\n * Forget which origins were already reported.\n *\n * Exported for tests, which assert the once-per-origin behaviour and would\n * otherwise leak state between cases.\n */\nexport function resetSuppressedCredentialReports(): void {\n reported.clear();\n}\n"],"mappings":"A,yCAMA,IAAME,EAAW,IAAI,IAkBrB,SAASC,EAAS,EAA4B,CAC1C,GAAI,CACA,OAAO,IAAI,IAAIC,EAAK,WAAW,UAAU,IAAI,CAAC,CAAC,MACnD,MAAQ,CACJ,OAAO,IACX,CACJ,CAoCA,SAAgBC,EACZ,EACA,EACA,EAAoC,CAAC,EAC9B,CACP,IAAMC,EAAeH,EAASI,CAAM,EAGpC,OAFID,IAAiB,MACjBA,IAAiBH,EAASK,CAAS,GAChCC,EAAe,KAAM,GAAWN,EAASO,CAAM,IAAMJ,CAAY,CAC5E,CAkBA,SAAgBK,EACZ,EACA,EACA,EAAS,gBACL,CACJ,GAAI,CAACX,EAAAA,WAAW,EAAG,OACnB,IAAMM,EAAeH,EAASI,CAAM,EACpC,GAAID,IAAiB,KAAM,OAC3B,IAAMM,EAAM,GAAGC,EAAO,GAAGP,IACrBJ,EAAS,IAAIU,CAAG,IACpBV,EAAS,IAAIU,CAAG,EAChB,QAAQ,KACJ,uBAAuBC,EAAO,mBAAmBP,EAAa,gCAAgCH,EAASK,CAAS,GAAKA,EAAU,mEACnI,EACJ,C"}
@@ -1 +1 @@
1
- {"version":3,"file":"credential-scope.js","names":[],"sources":["../../src/http/credential-scope.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\n\n/**\n * Origins already reported by {@link reportSuppressedCredential}, so a chunked\n * upload warns once instead of once per chunk.\n */\nconst reported = new Set<string>();\n\n/**\n * The origin a URL resolves to, or `null` when it has none to compare.\n *\n * Relative values resolve against the document, because that is what they mean\n * everywhere else in the SDK: an `endpoint` of `\"/api/uploads\"` and a `baseURL`\n * of `\"/api\"` are the shape you get behind a dev-server or a reverse proxy, and\n * both name the page's own origin. Comparing a resolved absolute target against\n * an unresolved relative reference is how the first draft of this function\n * withheld the credential from every client configured that way.\n *\n * `null` is reserved for the case with genuinely nothing to compare: a relative\n * URL outside a browsing context, where there is no document to resolve against.\n *\n * @param url - Absolute or relative URL.\n * @returns The origin, or `null` when it cannot be resolved.\n */\nfunction originOf(url: string): string | null {\n try {\n return new URL(url, globalThis.location?.href).origin;\n } catch {\n return null;\n }\n}\n\n/**\n * Whether a request to `target` may carry the caller's credential.\n *\n * The SDK writes `Authorization: Bearer` in three places, and until 0.66.0 none\n * of them looked at where the request was going. That is only safe while every\n * target URL is written by the app: a resumable upload takes its URL from the\n * server's `Location` header, and `createApiClient` lets an absolute path\n * override `baseURL` entirely, so a URL arriving over the network could decide\n * which origin received the token — and the file bytes with it.\n *\n * Handing an upload off to object storage on another host is ordinary `tus`\n * deployment, not an attack, which is exactly why the credential must be scoped\n * rather than the request blocked: the upload still goes through, it just goes\n * without the API's bearer token.\n *\n * Both sides are resolved against the document first, so a relative `baseURL`\n * or `endpoint` — the shape behind a dev-server or reverse proxy — compares\n * equal to the absolute URL the request actually goes to. Outside a browsing\n * context a relative target resolves to nothing and is allowed: there is no\n * origin for it to cross.\n *\n * @param target - The URL the request is about to go to.\n * @param reference - The origin the credential belongs to, normally the\n * client's `baseURL` or the upload `endpoint`.\n * @param trustedOrigins - Extra origins the app declared, for the legitimate\n * second host: a CDN, a signed upload endpoint.\n * @returns Whether the credential may be attached.\n *\n * @example\n * isTrustedCredentialTarget(\"https://api.acme.com/me\", \"https://api.acme.com\");\n * // true\n * isTrustedCredentialTarget(\"https://cdn.other/u/1\", \"https://api.acme.com\");\n * // false\n */\nexport function isTrustedCredentialTarget(\n target: string,\n reference: string,\n trustedOrigins: readonly string[] = [],\n): boolean {\n const targetOrigin = originOf(target);\n if (targetOrigin === null) return true;\n if (targetOrigin === originOf(reference)) return true;\n return trustedOrigins.some((origin) => originOf(origin) === targetOrigin);\n}\n\n/**\n * Say once, in a development build, that a credential was withheld.\n *\n * Without it the symptom is a `401` (or, for the CSRF header, a `403`) from a\n * host the developer never typed, and nothing in the app's code mentions the\n * origin that produced it. Keyed by credential and target origin, so a\n * hundred-chunk upload reports one line per header it withheld.\n *\n * Silent in production for the same reason {@link parseResponse} is: the origin\n * an app talks to is not something to print into a user's console or ship to an\n * error tracker.\n *\n * @param target - The URL whose request went out unauthenticated.\n * @param reference - The origin the credential was scoped to.\n * @param header - The header that was withheld. Default `\"Authorization\"`.\n */\nexport function reportSuppressedCredential(\n target: string,\n reference: string,\n header = \"Authorization\",\n): void {\n if (!isDevBuild()) return;\n const targetOrigin = originOf(target);\n if (targetOrigin === null) return;\n const key = `${header} ${targetOrigin}`;\n if (reported.has(key)) return;\n reported.add(key);\n console.warn(\n `[tempest-react-sdk] ${header} was not sent to ${targetOrigin}: the credential is scoped to ${originOf(reference) ?? reference}. Add the origin to trustedOrigins if it should receive the token.`,\n );\n}\n\n/**\n * Forget which origins were already reported.\n *\n * Exported for tests, which assert the once-per-origin behaviour and would\n * otherwise leak state between cases.\n */\nexport function resetSuppressedCredentialReports(): void {\n reported.clear();\n}\n"],"mappings":";;AAMA,IAAM,oBAAW,IAAI,IAAY;AAkBjC,SAAS,EAAS,GAA4B;CAC1C,IAAI;EACA,OAAO,IAAI,IAAI,GAAK,WAAW,UAAU,IAAI,CAAC,CAAC;CACnD,QAAQ;EACJ,OAAO;CACX;AACJ;AAoCA,SAAgB,EACZ,GACA,GACA,IAAoC,CAAC,GAC9B;CACP,IAAM,IAAe,EAAS,CAAM;CAGpC,OAFI,MAAiB,QACjB,MAAiB,EAAS,CAAS,KAChC,EAAe,MAAM,MAAW,EAAS,CAAM,MAAM,CAAY;AAC5E;AAkBA,SAAgB,EACZ,GACA,GACA,IAAS,iBACL;CACJ,IAAI,CAAC,EAAW,GAAG;CACnB,IAAM,IAAe,EAAS,CAAM;CACpC,IAAI,MAAiB,MAAM;CAC3B,IAAM,IAAM,GAAG,EAAO,GAAG;CACrB,EAAS,IAAI,CAAG,MACpB,EAAS,IAAI,CAAG,GAChB,QAAQ,KACJ,uBAAuB,EAAO,mBAAmB,EAAa,gCAAgC,EAAS,CAAS,KAAK,EAAU,mEACnI;AACJ"}
1
+ {"version":3,"file":"credential-scope.js","names":["reported","originOf","url","isTrustedCredentialTarget","targetOrigin","target","reference","trustedOrigins","origin","reportSuppressedCredential","isDevBuild","key","header"],"sources":["../../src/http/credential-scope.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\n\n/**\n * Origins already reported by {@link reportSuppressedCredential}, so a chunked\n * upload warns once instead of once per chunk.\n */\nconst reported = new Set<string>();\n\n/**\n * The origin a URL resolves to, or `null` when it has none to compare.\n *\n * Relative values resolve against the document, because that is what they mean\n * everywhere else in the SDK: an `endpoint` of `\"/api/uploads\"` and a `baseURL`\n * of `\"/api\"` are the shape you get behind a dev-server or a reverse proxy, and\n * both name the page's own origin. Comparing a resolved absolute target against\n * an unresolved relative reference is how the first draft of this function\n * withheld the credential from every client configured that way.\n *\n * `null` is reserved for the case with genuinely nothing to compare: a relative\n * URL outside a browsing context, where there is no document to resolve against.\n *\n * @param url - Absolute or relative URL.\n * @returns The origin, or `null` when it cannot be resolved.\n */\nfunction originOf(url: string): string | null {\n try {\n return new URL(url, globalThis.location?.href).origin;\n } catch {\n return null;\n }\n}\n\n/**\n * Whether a request to `target` may carry the caller's credential.\n *\n * The SDK writes `Authorization: Bearer` in three places, and until 0.66.0 none\n * of them looked at where the request was going. That is only safe while every\n * target URL is written by the app: a resumable upload takes its URL from the\n * server's `Location` header, and `createApiClient` lets an absolute path\n * override `baseURL` entirely, so a URL arriving over the network could decide\n * which origin received the token — and the file bytes with it.\n *\n * Handing an upload off to object storage on another host is ordinary `tus`\n * deployment, not an attack, which is exactly why the credential must be scoped\n * rather than the request blocked: the upload still goes through, it just goes\n * without the API's bearer token.\n *\n * Both sides are resolved against the document first, so a relative `baseURL`\n * or `endpoint` — the shape behind a dev-server or reverse proxy — compares\n * equal to the absolute URL the request actually goes to. Outside a browsing\n * context a relative target resolves to nothing and is allowed: there is no\n * origin for it to cross.\n *\n * @param target - The URL the request is about to go to.\n * @param reference - The origin the credential belongs to, normally the\n * client's `baseURL` or the upload `endpoint`.\n * @param trustedOrigins - Extra origins the app declared, for the legitimate\n * second host: a CDN, a signed upload endpoint.\n * @returns Whether the credential may be attached.\n *\n * @example\n * isTrustedCredentialTarget(\"https://api.acme.com/me\", \"https://api.acme.com\");\n * // true\n * isTrustedCredentialTarget(\"https://cdn.other/u/1\", \"https://api.acme.com\");\n * // false\n */\nexport function isTrustedCredentialTarget(\n target: string,\n reference: string,\n trustedOrigins: readonly string[] = [],\n): boolean {\n const targetOrigin = originOf(target);\n if (targetOrigin === null) return true;\n if (targetOrigin === originOf(reference)) return true;\n return trustedOrigins.some((origin) => originOf(origin) === targetOrigin);\n}\n\n/**\n * Say once, in a development build, that a credential was withheld.\n *\n * Without it the symptom is a `401` (or, for the CSRF header, a `403`) from a\n * host the developer never typed, and nothing in the app's code mentions the\n * origin that produced it. Keyed by credential and target origin, so a\n * hundred-chunk upload reports one line per header it withheld.\n *\n * Silent in production for the same reason {@link parseResponse} is: the origin\n * an app talks to is not something to print into a user's console or ship to an\n * error tracker.\n *\n * @param target - The URL whose request went out unauthenticated.\n * @param reference - The origin the credential was scoped to.\n * @param header - The header that was withheld. Default `\"Authorization\"`.\n */\nexport function reportSuppressedCredential(\n target: string,\n reference: string,\n header = \"Authorization\",\n): void {\n if (!isDevBuild()) return;\n const targetOrigin = originOf(target);\n if (targetOrigin === null) return;\n const key = `${header} ${targetOrigin}`;\n if (reported.has(key)) return;\n reported.add(key);\n console.warn(\n `[tempest-react-sdk] ${header} was not sent to ${targetOrigin}: the credential is scoped to ${originOf(reference) ?? reference}. Add the origin to trustedOrigins if it should receive the token.`,\n );\n}\n\n/**\n * Forget which origins were already reported.\n *\n * Exported for tests, which assert the once-per-origin behaviour and would\n * otherwise leak state between cases.\n */\nexport function resetSuppressedCredentialReports(): void {\n reported.clear();\n}\n"],"mappings":";;AAMA,IAAMA,oBAAW,IAAI,IAAY;AAkBjC,SAASC,EAAS,GAA4B;CAC1C,IAAI;EACA,OAAO,IAAI,IAAIC,GAAK,WAAW,UAAU,IAAI,CAAC,CAAC;CACnD,QAAQ;EACJ,OAAO;CACX;AACJ;AAoCA,SAAgBC,EACZ,GACA,GACA,IAAoC,CAAC,GAC9B;CACP,IAAMC,IAAeH,EAASI,CAAM;CAGpC,OAFID,MAAiB,QACjBA,MAAiBH,EAASK,CAAS,KAChCC,EAAe,MAAM,MAAWN,EAASO,CAAM,MAAMJ,CAAY;AAC5E;AAkBA,SAAgBK,EACZ,GACA,GACA,IAAS,iBACL;CACJ,IAAI,CAACC,EAAW,GAAG;CACnB,IAAMN,IAAeH,EAASI,CAAM;CACpC,IAAID,MAAiB,MAAM;CAC3B,IAAMO,IAAM,GAAGC,EAAO,GAAGR;CACzB,AAAIJ,EAAS,IAAIW,CAAG,MACpBX,EAAS,IAAIW,CAAG,GAChB,QAAQ,KACJ,uBAAuBC,EAAO,mBAAmBR,EAAa,gCAAgCH,EAASK,CAAS,KAAKA,EAAU,mEACnI;AACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"csrf.cjs","names":[],"sources":["../../src/http/csrf.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\nimport { isTrustedCredentialTarget, reportSuppressedCredential } from \"./credential-scope\";\n\n/**\n * Default cookie the CSRF token is read from.\n *\n * Ported from `tempest-fastapi-sdk`'s `CSRF_COOKIE_NAME`\n * (`tempest_fastapi_sdk/api/middlewares/csrf.py`), which is the cookie its\n * `make_csrf_token_dependency()` sets and its `CSRFMiddleware` compares against.\n * Matching it is what lets `csrf: true` work against that backend with no\n * configuration on either side.\n */\nexport const DEFAULT_CSRF_COOKIE_NAME = \"csrf_token\";\n\n/**\n * Default header the CSRF token is echoed in.\n *\n * Ported from `tempest-fastapi-sdk`'s `CSRF_HEADER_NAME`, the header its\n * `CSRFMiddleware` reads on every unsafe request.\n */\nexport const DEFAULT_CSRF_HEADER_NAME = \"X-CSRF-Token\";\n\n/**\n * Where the CSRF token comes from and which header carries it.\n *\n * The default is the **double-submit cookie**: the server sets a cookie that is\n * deliberately not `HttpOnly`, the client reads it and echoes the value in a\n * header, and the server rejects a write whose header does not match the\n * cookie. A page on another site can make the browser *send* the cookie, but\n * cannot *read* it, so it cannot write the header.\n *\n * The token is read again on every request, so a server that rotates the\n * cookie is followed without any capture step: the browser's cookie jar is the\n * store. That is also why there is no \"read the token from a response header\"\n * mode — it would depend on `Access-Control-Expose-Headers`, and a missing\n * expose header fails silently, as a `403` on the second write.\n */\nexport interface CsrfOptions {\n /** Cookie to read the token from. Default {@link DEFAULT_CSRF_COOKIE_NAME}. */\n cookieName?: string;\n /** Header to send the token in. Default {@link DEFAULT_CSRF_HEADER_NAME}. */\n headerName?: string;\n /**\n * Supply the token yourself instead of reading `cookieName`.\n *\n * For the cases the cookie cannot serve: an API on another **site**, whose\n * cookie `document.cookie` cannot see, or a backend that hands the token\n * out in a response body. Called per request, like `getToken`.\n */\n getToken?: () => string | null | undefined;\n}\n\n/**\n * Methods that must not change state, and so never carry the token.\n *\n * A deny list rather than an allow list of the four write verbs: RFC 9110\n * names the safe methods, and a custom method (`PROPFIND`, a tus extension)\n * is a write until proven otherwise. Sending the token to its own origin on\n * an unexpected verb costs nothing; omitting it costs a `403`.\n */\nconst SAFE_METHODS: ReadonlySet<string> = new Set([\"GET\", \"HEAD\", \"OPTIONS\", \"TRACE\"]);\n\n/** Token sources already reported empty, so a burst of writes warns once. */\nconst reportedMissing = new Set<string>();\n\n/**\n * Read one cookie from `document.cookie`, or `null` when it is absent.\n *\n * Returns `null` outside a document (a worker, a test without jsdom), where\n * there is no cookie jar to read. The value is URI-decoded when it can be,\n * and returned raw when it is not valid percent-encoding.\n *\n * @param name - The cookie name.\n * @returns The value, or `null`.\n */\nfunction readCookie(name: string): string | null {\n if (typeof document === \"undefined\") return null;\n const prefix = `${name}=`;\n for (const part of document.cookie.split(\";\")) {\n const entry = part.trim();\n if (!entry.startsWith(prefix)) continue;\n const raw = entry.slice(prefix.length);\n try {\n return decodeURIComponent(raw);\n } catch {\n return raw;\n }\n }\n return null;\n}\n\n/**\n * Say once, in a development build, that CSRF is on but there is no token.\n *\n * The request still goes out, because the SDK cannot know whether this path\n * is guarded — `CSRFMiddleware` is commonly mounted with `exclude_paths`. When\n * it is guarded, the symptom is a `403 CSRF_VALIDATION_FAILED` with nothing\n * in the app's code pointing at the cause, and the three usual causes are all\n * on the server: the cookie was never issued, was issued `HttpOnly`, or was\n * issued for a domain this page cannot read.\n *\n * @param source - What was read: the cookie name, or `\"getToken\"`.\n */\nfunction reportMissingToken(source: string): void {\n if (!isDevBuild() || reportedMissing.has(source)) return;\n reportedMissing.add(source);\n const where =\n source === \"getToken\"\n ? \"csrf.getToken() returned nothing\"\n : `no readable \"${source}\" cookie on this page`;\n console.warn(\n `[tempest-react-sdk] CSRF is enabled but ${where}, so the write went without the token. The cookie must be issued before the first write and must not be HttpOnly.`,\n );\n}\n\n/**\n * Whether a header is already present, compared case-insensitively.\n *\n * Header names are case-insensitive, but object keys are not: a caller's\n * `\"x-csrf-token\"` next to the SDK's `\"X-CSRF-Token\"` would reach `fetch` as\n * two entries and be joined into `\"a, b\"`, which matches neither.\n *\n * @param headers - The headers the caller already set.\n * @param name - The header to look for.\n * @returns Whether it is set.\n */\nfunction hasHeader(headers: HeadersInit | undefined, name: string): boolean {\n if (!headers) return false;\n return new Headers(headers).has(name);\n}\n\n/** What {@link csrfHeaders} needs to decide. */\nexport interface CsrfHeadersInput {\n /** The HTTP method of the request. Case-insensitive. */\n method: string;\n /** The URL the request is going to. */\n url: string;\n /**\n * The origin the token belongs to, normally the API's `baseURL`. The token\n * is only sent to this origin or to one listed in `trustedOrigins`.\n */\n reference: string;\n /** The CSRF config. `undefined` or `false` turns the header off. */\n csrf: boolean | CsrfOptions | undefined;\n /** Extra origins allowed to receive the token. */\n trustedOrigins?: readonly string[];\n /** Headers the caller already set. A CSRF header among them is never replaced. */\n headers?: HeadersInit;\n}\n\n/**\n * The CSRF header a request should carry, or an empty object.\n *\n * Every request path in the SDK — `createApiClient`, `uploadWithProgress`,\n * `createResumableUpload` — asks this function, so the rules are one rule:\n *\n * - **Off unless configured.** Without `csrf`, nothing changes.\n * - **Unsafe methods only.** `GET`, `HEAD`, `OPTIONS` and `TRACE` never carry\n * it; they must not change state, and a token in a `GET` ends up in logs\n * and caches for nothing.\n * - **Never across an origin.** The token follows the same scope as the bearer\n * credential ({@link isTrustedCredentialTarget}), because a URL can come off\n * the network — a tus `Location`, a pagination link — and a CSRF token sent\n * to a third party is a token that third party can replay. Withheld tokens\n * are reported once per origin in a development build.\n * - **Your header wins.** A CSRF header you set by hand, in any casing, is\n * left alone.\n * - **Independent of auth.** It is sent on `skipAuth` requests too: login and\n * refresh are exactly the writes a cookie session exposes to forgery.\n *\n * Exported for the request you build by hand, so it follows the same rules.\n *\n * @example\n * const headers = csrfHeaders({\n * method: \"POST\",\n * url: \"https://api.acme.com/orders\",\n * reference: \"https://api.acme.com\",\n * csrf: true,\n * });\n * // { \"X-CSRF-Token\": \"<value of the csrf_token cookie>\" }\n *\n * @param input - The request and the CSRF config.\n * @returns A header record to spread into the request's headers.\n */\nexport function csrfHeaders(input: CsrfHeadersInput): Record<string, string> {\n const { method, url, reference, csrf, trustedOrigins, headers } = input;\n if (!csrf) return {};\n if (SAFE_METHODS.has(method.toUpperCase())) return {};\n const options: CsrfOptions = csrf === true ? {} : csrf;\n const headerName = options.headerName ?? DEFAULT_CSRF_HEADER_NAME;\n if (hasHeader(headers, headerName)) return {};\n if (!isTrustedCredentialTarget(url, reference, trustedOrigins)) {\n reportSuppressedCredential(url, reference, headerName);\n return {};\n }\n const cookieName = options.cookieName ?? DEFAULT_CSRF_COOKIE_NAME;\n const token = options.getToken ? options.getToken() : readCookie(cookieName);\n if (!token) {\n reportMissingToken(options.getToken ? \"getToken\" : cookieName);\n return {};\n }\n return { [headerName]: token };\n}\n\n/**\n * Forget which token sources were already reported empty.\n *\n * Exported for tests, which assert the once-per-source behaviour and would\n * otherwise leak state between cases.\n */\nexport function resetCsrfReports(): void {\n reportedMissing.clear();\n}\n"],"mappings":"6EAYA,IAAa,EAA2B,aAQ3B,EAA2B,eAwClC,EAAoC,IAAI,IAAI,CAAC,MAAO,OAAQ,UAAW,OAAO,CAAC,EAG/E,EAAkB,IAAI,IAY5B,SAAS,EAAW,EAA6B,CAC7C,GAAI,OAAO,SAAa,IAAa,OAAO,KAC5C,IAAM,EAAS,GAAG,EAAK,GACvB,IAAK,IAAM,KAAQ,SAAS,OAAO,MAAM,GAAG,EAAG,CAC3C,IAAM,EAAQ,EAAK,KAAK,EACxB,GAAI,CAAC,EAAM,WAAW,CAAM,EAAG,SAC/B,IAAM,EAAM,EAAM,MAAM,EAAO,MAAM,EACrC,GAAI,CACA,OAAO,mBAAmB,CAAG,CACjC,MAAQ,CACJ,OAAO,CACX,CACJ,CACA,OAAO,IACX,CAcA,SAAS,EAAmB,EAAsB,CAC9C,GAAI,CAAC,EAAA,WAAW,GAAK,EAAgB,IAAI,CAAM,EAAG,OAClD,EAAgB,IAAI,CAAM,EAC1B,IAAM,EACF,IAAW,WACL,mCACA,gBAAgB,EAAO,uBACjC,QAAQ,KACJ,2CAA2C,EAAM,kHACrD,CACJ,CAaA,SAAS,EAAU,EAAkC,EAAuB,CAExE,OADK,EACE,IAAI,QAAQ,CAAO,CAAC,CAAC,IAAI,CAAI,EADf,EAEzB,CAuDA,SAAgB,EAAY,EAAiD,CACzE,GAAM,CAAE,SAAQ,MAAK,YAAW,OAAM,iBAAgB,WAAY,EAElE,GADI,CAAC,GACD,EAAa,IAAI,EAAO,YAAY,CAAC,EAAG,MAAO,CAAC,EACpD,IAAM,EAAuB,IAAS,GAAO,CAAC,EAAI,EAC5C,EAAa,EAAQ,YAAA,eAC3B,GAAI,EAAU,EAAS,CAAU,EAAG,MAAO,CAAC,EAC5C,GAAI,CAAC,EAAA,0BAA0B,EAAK,EAAW,CAAc,EAEzD,OADA,EAAA,2BAA2B,EAAK,EAAW,CAAU,EAC9C,CAAC,EAEZ,IAAM,EAAa,EAAQ,YAAA,aACrB,EAAQ,EAAQ,SAAW,EAAQ,SAAS,EAAI,EAAW,CAAU,EAK3E,OAJK,EAIE,EAAG,GAAa,CAAM,GAHzB,EAAmB,EAAQ,SAAW,WAAa,CAAU,EACtD,CAAC,EAGhB"}
1
+ {"version":3,"file":"csrf.cjs","names":["isDevBuild","isTrustedCredentialTarget","require_dev_mode","require_credential_scope","DEFAULT_CSRF_COOKIE_NAME","DEFAULT_CSRF_HEADER_NAME","SAFE_METHODS","reportedMissing","readCookie","prefix","name","part","entry","raw","reportMissingToken","source","where","hasHeader","headers","csrfHeaders","input","csrf","method","options","headerName","url","reference","trustedOrigins","cookieName","token"],"sources":["../../src/http/csrf.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\nimport { isTrustedCredentialTarget, reportSuppressedCredential } from \"./credential-scope\";\n\n/**\n * Default cookie the CSRF token is read from.\n *\n * Ported from `tempest-fastapi-sdk`'s `CSRF_COOKIE_NAME`\n * (`tempest_fastapi_sdk/api/middlewares/csrf.py`), which is the cookie its\n * `make_csrf_token_dependency()` sets and its `CSRFMiddleware` compares against.\n * Matching it is what lets `csrf: true` work against that backend with no\n * configuration on either side.\n */\nexport const DEFAULT_CSRF_COOKIE_NAME = \"csrf_token\";\n\n/**\n * Default header the CSRF token is echoed in.\n *\n * Ported from `tempest-fastapi-sdk`'s `CSRF_HEADER_NAME`, the header its\n * `CSRFMiddleware` reads on every unsafe request.\n */\nexport const DEFAULT_CSRF_HEADER_NAME = \"X-CSRF-Token\";\n\n/**\n * Where the CSRF token comes from and which header carries it.\n *\n * The default is the **double-submit cookie**: the server sets a cookie that is\n * deliberately not `HttpOnly`, the client reads it and echoes the value in a\n * header, and the server rejects a write whose header does not match the\n * cookie. A page on another site can make the browser *send* the cookie, but\n * cannot *read* it, so it cannot write the header.\n *\n * The token is read again on every request, so a server that rotates the\n * cookie is followed without any capture step: the browser's cookie jar is the\n * store. That is also why there is no \"read the token from a response header\"\n * mode — it would depend on `Access-Control-Expose-Headers`, and a missing\n * expose header fails silently, as a `403` on the second write.\n */\nexport interface CsrfOptions {\n /** Cookie to read the token from. Default {@link DEFAULT_CSRF_COOKIE_NAME}. */\n cookieName?: string;\n /** Header to send the token in. Default {@link DEFAULT_CSRF_HEADER_NAME}. */\n headerName?: string;\n /**\n * Supply the token yourself instead of reading `cookieName`.\n *\n * For the cases the cookie cannot serve: an API on another **site**, whose\n * cookie `document.cookie` cannot see, or a backend that hands the token\n * out in a response body. Called per request, like `getToken`.\n */\n getToken?: () => string | null | undefined;\n}\n\n/**\n * Methods that must not change state, and so never carry the token.\n *\n * A deny list rather than an allow list of the four write verbs: RFC 9110\n * names the safe methods, and a custom method (`PROPFIND`, a tus extension)\n * is a write until proven otherwise. Sending the token to its own origin on\n * an unexpected verb costs nothing; omitting it costs a `403`.\n */\nconst SAFE_METHODS: ReadonlySet<string> = new Set([\"GET\", \"HEAD\", \"OPTIONS\", \"TRACE\"]);\n\n/** Token sources already reported empty, so a burst of writes warns once. */\nconst reportedMissing = new Set<string>();\n\n/**\n * Read one cookie from `document.cookie`, or `null` when it is absent.\n *\n * Returns `null` outside a document (a worker, a test without jsdom), where\n * there is no cookie jar to read. The value is URI-decoded when it can be,\n * and returned raw when it is not valid percent-encoding.\n *\n * @param name - The cookie name.\n * @returns The value, or `null`.\n */\nfunction readCookie(name: string): string | null {\n if (typeof document === \"undefined\") return null;\n const prefix = `${name}=`;\n for (const part of document.cookie.split(\";\")) {\n const entry = part.trim();\n if (!entry.startsWith(prefix)) continue;\n const raw = entry.slice(prefix.length);\n try {\n return decodeURIComponent(raw);\n } catch {\n return raw;\n }\n }\n return null;\n}\n\n/**\n * Say once, in a development build, that CSRF is on but there is no token.\n *\n * The request still goes out, because the SDK cannot know whether this path\n * is guarded — `CSRFMiddleware` is commonly mounted with `exclude_paths`. When\n * it is guarded, the symptom is a `403 CSRF_VALIDATION_FAILED` with nothing\n * in the app's code pointing at the cause, and the three usual causes are all\n * on the server: the cookie was never issued, was issued `HttpOnly`, or was\n * issued for a domain this page cannot read.\n *\n * @param source - What was read: the cookie name, or `\"getToken\"`.\n */\nfunction reportMissingToken(source: string): void {\n if (!isDevBuild() || reportedMissing.has(source)) return;\n reportedMissing.add(source);\n const where =\n source === \"getToken\"\n ? \"csrf.getToken() returned nothing\"\n : `no readable \"${source}\" cookie on this page`;\n console.warn(\n `[tempest-react-sdk] CSRF is enabled but ${where}, so the write went without the token. The cookie must be issued before the first write and must not be HttpOnly.`,\n );\n}\n\n/**\n * Whether a header is already present, compared case-insensitively.\n *\n * Header names are case-insensitive, but object keys are not: a caller's\n * `\"x-csrf-token\"` next to the SDK's `\"X-CSRF-Token\"` would reach `fetch` as\n * two entries and be joined into `\"a, b\"`, which matches neither.\n *\n * @param headers - The headers the caller already set.\n * @param name - The header to look for.\n * @returns Whether it is set.\n */\nfunction hasHeader(headers: HeadersInit | undefined, name: string): boolean {\n if (!headers) return false;\n return new Headers(headers).has(name);\n}\n\n/** What {@link csrfHeaders} needs to decide. */\nexport interface CsrfHeadersInput {\n /** The HTTP method of the request. Case-insensitive. */\n method: string;\n /** The URL the request is going to. */\n url: string;\n /**\n * The origin the token belongs to, normally the API's `baseURL`. The token\n * is only sent to this origin or to one listed in `trustedOrigins`.\n */\n reference: string;\n /** The CSRF config. `undefined` or `false` turns the header off. */\n csrf: boolean | CsrfOptions | undefined;\n /** Extra origins allowed to receive the token. */\n trustedOrigins?: readonly string[];\n /** Headers the caller already set. A CSRF header among them is never replaced. */\n headers?: HeadersInit;\n}\n\n/**\n * The CSRF header a request should carry, or an empty object.\n *\n * Every request path in the SDK — `createApiClient`, `uploadWithProgress`,\n * `createResumableUpload` — asks this function, so the rules are one rule:\n *\n * - **Off unless configured.** Without `csrf`, nothing changes.\n * - **Unsafe methods only.** `GET`, `HEAD`, `OPTIONS` and `TRACE` never carry\n * it; they must not change state, and a token in a `GET` ends up in logs\n * and caches for nothing.\n * - **Never across an origin.** The token follows the same scope as the bearer\n * credential ({@link isTrustedCredentialTarget}), because a URL can come off\n * the network — a tus `Location`, a pagination link — and a CSRF token sent\n * to a third party is a token that third party can replay. Withheld tokens\n * are reported once per origin in a development build.\n * - **Your header wins.** A CSRF header you set by hand, in any casing, is\n * left alone.\n * - **Independent of auth.** It is sent on `skipAuth` requests too: login and\n * refresh are exactly the writes a cookie session exposes to forgery.\n *\n * Exported for the request you build by hand, so it follows the same rules.\n *\n * @example\n * const headers = csrfHeaders({\n * method: \"POST\",\n * url: \"https://api.acme.com/orders\",\n * reference: \"https://api.acme.com\",\n * csrf: true,\n * });\n * // { \"X-CSRF-Token\": \"<value of the csrf_token cookie>\" }\n *\n * @param input - The request and the CSRF config.\n * @returns A header record to spread into the request's headers.\n */\nexport function csrfHeaders(input: CsrfHeadersInput): Record<string, string> {\n const { method, url, reference, csrf, trustedOrigins, headers } = input;\n if (!csrf) return {};\n if (SAFE_METHODS.has(method.toUpperCase())) return {};\n const options: CsrfOptions = csrf === true ? {} : csrf;\n const headerName = options.headerName ?? DEFAULT_CSRF_HEADER_NAME;\n if (hasHeader(headers, headerName)) return {};\n if (!isTrustedCredentialTarget(url, reference, trustedOrigins)) {\n reportSuppressedCredential(url, reference, headerName);\n return {};\n }\n const cookieName = options.cookieName ?? DEFAULT_CSRF_COOKIE_NAME;\n const token = options.getToken ? options.getToken() : readCookie(cookieName);\n if (!token) {\n reportMissingToken(options.getToken ? \"getToken\" : cookieName);\n return {};\n }\n return { [headerName]: token };\n}\n\n/**\n * Forget which token sources were already reported empty.\n *\n * Exported for tests, which assert the once-per-source behaviour and would\n * otherwise leak state between cases.\n */\nexport function resetCsrfReports(): void {\n reportedMissing.clear();\n}\n"],"mappings":"A,6EAYA,IAAaI,EAA2B,aAQ3BC,EAA2B,eAwClCC,EAAoC,IAAI,IAAI,CAAC,MAAO,OAAQ,UAAW,OAAO,CAAC,EAG/EC,EAAkB,IAAI,IAY5B,SAASC,EAAW,EAA6B,CAC7C,GAAI,OAAO,SAAa,IAAa,OAAO,KAC5C,IAAMC,EAAS,GAAGC,EAAK,GACvB,IAAK,IAAMC,KAAQ,SAAS,OAAO,MAAM,GAAG,EAAG,CAC3C,IAAMC,EAAQD,EAAK,KAAK,EACxB,GAAI,CAACC,EAAM,WAAWH,CAAM,EAAG,SAC/B,IAAMI,EAAMD,EAAM,MAAMH,EAAO,MAAM,EACrC,GAAI,CACA,OAAO,mBAAmBI,CAAG,CACjC,MAAQ,CACJ,OAAOA,CACX,CACJ,CACA,OAAO,IACX,CAcA,SAASC,EAAmB,EAAsB,CAC9C,GAAI,CAACd,EAAAA,WAAW,GAAKO,EAAgB,IAAIQ,CAAM,EAAG,OAClDR,EAAgB,IAAIQ,CAAM,EAC1B,IAAMC,EACFD,IAAW,WACL,mCACA,gBAAgBA,EAAO,uBACjC,QAAQ,KACJ,2CAA2CC,EAAM,kHACrD,CACJ,CAaA,SAASC,EAAU,EAAkC,EAAuB,CAExE,OADKC,EACE,IAAI,QAAQA,CAAO,CAAC,CAAC,IAAIR,CAAI,EADf,EAEzB,CAuDA,SAAgBS,EAAY,EAAiD,CACzE,GAAM,CAAE,SAAQ,MAAK,YAAW,OAAM,iBAAgB,WAAYC,EAElE,GADI,CAACC,GACDf,EAAa,IAAIgB,EAAO,YAAY,CAAC,EAAG,MAAO,CAAC,EACpD,IAAMC,EAAuBF,IAAS,GAAO,CAAC,EAAIA,EAC5CG,EAAaD,EAAQ,YAAA,eAC3B,GAAIN,EAAUC,EAASM,CAAU,EAAG,MAAO,CAAC,EAC5C,GAAI,CAACvB,EAAAA,0BAA0BwB,EAAKC,EAAWC,CAAc,EAEzD,OADAxB,EAAA,2BAA2BsB,EAAKC,EAAWF,CAAU,EAC9C,CAAC,EAEZ,IAAMI,EAAaL,EAAQ,YAAA,aACrBM,EAAQN,EAAQ,SAAWA,EAAQ,SAAS,EAAIf,EAAWoB,CAAU,EAK3E,OAJKC,EAIE,EAAGL,GAAaK,CAAM,GAHzBf,EAAmBS,EAAQ,SAAW,WAAaK,CAAU,EACtD,CAAC,EAGhB,C"}
@@ -1 +1 @@
1
- {"version":3,"file":"csrf.js","names":[],"sources":["../../src/http/csrf.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\nimport { isTrustedCredentialTarget, reportSuppressedCredential } from \"./credential-scope\";\n\n/**\n * Default cookie the CSRF token is read from.\n *\n * Ported from `tempest-fastapi-sdk`'s `CSRF_COOKIE_NAME`\n * (`tempest_fastapi_sdk/api/middlewares/csrf.py`), which is the cookie its\n * `make_csrf_token_dependency()` sets and its `CSRFMiddleware` compares against.\n * Matching it is what lets `csrf: true` work against that backend with no\n * configuration on either side.\n */\nexport const DEFAULT_CSRF_COOKIE_NAME = \"csrf_token\";\n\n/**\n * Default header the CSRF token is echoed in.\n *\n * Ported from `tempest-fastapi-sdk`'s `CSRF_HEADER_NAME`, the header its\n * `CSRFMiddleware` reads on every unsafe request.\n */\nexport const DEFAULT_CSRF_HEADER_NAME = \"X-CSRF-Token\";\n\n/**\n * Where the CSRF token comes from and which header carries it.\n *\n * The default is the **double-submit cookie**: the server sets a cookie that is\n * deliberately not `HttpOnly`, the client reads it and echoes the value in a\n * header, and the server rejects a write whose header does not match the\n * cookie. A page on another site can make the browser *send* the cookie, but\n * cannot *read* it, so it cannot write the header.\n *\n * The token is read again on every request, so a server that rotates the\n * cookie is followed without any capture step: the browser's cookie jar is the\n * store. That is also why there is no \"read the token from a response header\"\n * mode — it would depend on `Access-Control-Expose-Headers`, and a missing\n * expose header fails silently, as a `403` on the second write.\n */\nexport interface CsrfOptions {\n /** Cookie to read the token from. Default {@link DEFAULT_CSRF_COOKIE_NAME}. */\n cookieName?: string;\n /** Header to send the token in. Default {@link DEFAULT_CSRF_HEADER_NAME}. */\n headerName?: string;\n /**\n * Supply the token yourself instead of reading `cookieName`.\n *\n * For the cases the cookie cannot serve: an API on another **site**, whose\n * cookie `document.cookie` cannot see, or a backend that hands the token\n * out in a response body. Called per request, like `getToken`.\n */\n getToken?: () => string | null | undefined;\n}\n\n/**\n * Methods that must not change state, and so never carry the token.\n *\n * A deny list rather than an allow list of the four write verbs: RFC 9110\n * names the safe methods, and a custom method (`PROPFIND`, a tus extension)\n * is a write until proven otherwise. Sending the token to its own origin on\n * an unexpected verb costs nothing; omitting it costs a `403`.\n */\nconst SAFE_METHODS: ReadonlySet<string> = new Set([\"GET\", \"HEAD\", \"OPTIONS\", \"TRACE\"]);\n\n/** Token sources already reported empty, so a burst of writes warns once. */\nconst reportedMissing = new Set<string>();\n\n/**\n * Read one cookie from `document.cookie`, or `null` when it is absent.\n *\n * Returns `null` outside a document (a worker, a test without jsdom), where\n * there is no cookie jar to read. The value is URI-decoded when it can be,\n * and returned raw when it is not valid percent-encoding.\n *\n * @param name - The cookie name.\n * @returns The value, or `null`.\n */\nfunction readCookie(name: string): string | null {\n if (typeof document === \"undefined\") return null;\n const prefix = `${name}=`;\n for (const part of document.cookie.split(\";\")) {\n const entry = part.trim();\n if (!entry.startsWith(prefix)) continue;\n const raw = entry.slice(prefix.length);\n try {\n return decodeURIComponent(raw);\n } catch {\n return raw;\n }\n }\n return null;\n}\n\n/**\n * Say once, in a development build, that CSRF is on but there is no token.\n *\n * The request still goes out, because the SDK cannot know whether this path\n * is guarded — `CSRFMiddleware` is commonly mounted with `exclude_paths`. When\n * it is guarded, the symptom is a `403 CSRF_VALIDATION_FAILED` with nothing\n * in the app's code pointing at the cause, and the three usual causes are all\n * on the server: the cookie was never issued, was issued `HttpOnly`, or was\n * issued for a domain this page cannot read.\n *\n * @param source - What was read: the cookie name, or `\"getToken\"`.\n */\nfunction reportMissingToken(source: string): void {\n if (!isDevBuild() || reportedMissing.has(source)) return;\n reportedMissing.add(source);\n const where =\n source === \"getToken\"\n ? \"csrf.getToken() returned nothing\"\n : `no readable \"${source}\" cookie on this page`;\n console.warn(\n `[tempest-react-sdk] CSRF is enabled but ${where}, so the write went without the token. The cookie must be issued before the first write and must not be HttpOnly.`,\n );\n}\n\n/**\n * Whether a header is already present, compared case-insensitively.\n *\n * Header names are case-insensitive, but object keys are not: a caller's\n * `\"x-csrf-token\"` next to the SDK's `\"X-CSRF-Token\"` would reach `fetch` as\n * two entries and be joined into `\"a, b\"`, which matches neither.\n *\n * @param headers - The headers the caller already set.\n * @param name - The header to look for.\n * @returns Whether it is set.\n */\nfunction hasHeader(headers: HeadersInit | undefined, name: string): boolean {\n if (!headers) return false;\n return new Headers(headers).has(name);\n}\n\n/** What {@link csrfHeaders} needs to decide. */\nexport interface CsrfHeadersInput {\n /** The HTTP method of the request. Case-insensitive. */\n method: string;\n /** The URL the request is going to. */\n url: string;\n /**\n * The origin the token belongs to, normally the API's `baseURL`. The token\n * is only sent to this origin or to one listed in `trustedOrigins`.\n */\n reference: string;\n /** The CSRF config. `undefined` or `false` turns the header off. */\n csrf: boolean | CsrfOptions | undefined;\n /** Extra origins allowed to receive the token. */\n trustedOrigins?: readonly string[];\n /** Headers the caller already set. A CSRF header among them is never replaced. */\n headers?: HeadersInit;\n}\n\n/**\n * The CSRF header a request should carry, or an empty object.\n *\n * Every request path in the SDK — `createApiClient`, `uploadWithProgress`,\n * `createResumableUpload` — asks this function, so the rules are one rule:\n *\n * - **Off unless configured.** Without `csrf`, nothing changes.\n * - **Unsafe methods only.** `GET`, `HEAD`, `OPTIONS` and `TRACE` never carry\n * it; they must not change state, and a token in a `GET` ends up in logs\n * and caches for nothing.\n * - **Never across an origin.** The token follows the same scope as the bearer\n * credential ({@link isTrustedCredentialTarget}), because a URL can come off\n * the network — a tus `Location`, a pagination link — and a CSRF token sent\n * to a third party is a token that third party can replay. Withheld tokens\n * are reported once per origin in a development build.\n * - **Your header wins.** A CSRF header you set by hand, in any casing, is\n * left alone.\n * - **Independent of auth.** It is sent on `skipAuth` requests too: login and\n * refresh are exactly the writes a cookie session exposes to forgery.\n *\n * Exported for the request you build by hand, so it follows the same rules.\n *\n * @example\n * const headers = csrfHeaders({\n * method: \"POST\",\n * url: \"https://api.acme.com/orders\",\n * reference: \"https://api.acme.com\",\n * csrf: true,\n * });\n * // { \"X-CSRF-Token\": \"<value of the csrf_token cookie>\" }\n *\n * @param input - The request and the CSRF config.\n * @returns A header record to spread into the request's headers.\n */\nexport function csrfHeaders(input: CsrfHeadersInput): Record<string, string> {\n const { method, url, reference, csrf, trustedOrigins, headers } = input;\n if (!csrf) return {};\n if (SAFE_METHODS.has(method.toUpperCase())) return {};\n const options: CsrfOptions = csrf === true ? {} : csrf;\n const headerName = options.headerName ?? DEFAULT_CSRF_HEADER_NAME;\n if (hasHeader(headers, headerName)) return {};\n if (!isTrustedCredentialTarget(url, reference, trustedOrigins)) {\n reportSuppressedCredential(url, reference, headerName);\n return {};\n }\n const cookieName = options.cookieName ?? DEFAULT_CSRF_COOKIE_NAME;\n const token = options.getToken ? options.getToken() : readCookie(cookieName);\n if (!token) {\n reportMissingToken(options.getToken ? \"getToken\" : cookieName);\n return {};\n }\n return { [headerName]: token };\n}\n\n/**\n * Forget which token sources were already reported empty.\n *\n * Exported for tests, which assert the once-per-source behaviour and would\n * otherwise leak state between cases.\n */\nexport function resetCsrfReports(): void {\n reportedMissing.clear();\n}\n"],"mappings":";;;AAYA,IAAa,IAA2B,cAQ3B,IAA2B,gBAwClC,oBAAoC,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAW;AAAO,CAAC,GAG/E,oBAAkB,IAAI,IAAY;AAYxC,SAAS,EAAW,GAA6B;CAC7C,IAAI,OAAO,WAAa,KAAa,OAAO;CAC5C,IAAM,IAAS,GAAG,EAAK;CACvB,KAAK,IAAM,KAAQ,SAAS,OAAO,MAAM,GAAG,GAAG;EAC3C,IAAM,IAAQ,EAAK,KAAK;EACxB,IAAI,CAAC,EAAM,WAAW,CAAM,GAAG;EAC/B,IAAM,IAAM,EAAM,MAAM,EAAO,MAAM;EACrC,IAAI;GACA,OAAO,mBAAmB,CAAG;EACjC,QAAQ;GACJ,OAAO;EACX;CACJ;CACA,OAAO;AACX;AAcA,SAAS,EAAmB,GAAsB;CAC9C,IAAI,CAAC,EAAW,KAAK,EAAgB,IAAI,CAAM,GAAG;CAClD,EAAgB,IAAI,CAAM;CAC1B,IAAM,IACF,MAAW,aACL,qCACA,gBAAgB,EAAO;CACjC,QAAQ,KACJ,2CAA2C,EAAM,kHACrD;AACJ;AAaA,SAAS,EAAU,GAAkC,GAAuB;CAExE,OADK,IACE,IAAI,QAAQ,CAAO,CAAC,CAAC,IAAI,CAAI,IADf;AAEzB;AAuDA,SAAgB,EAAY,GAAiD;CACzE,IAAM,EAAE,WAAQ,QAAK,cAAW,SAAM,mBAAgB,eAAY;CAElE,IADI,CAAC,KACD,EAAa,IAAI,EAAO,YAAY,CAAC,GAAG,OAAO,CAAC;CACpD,IAAM,IAAuB,MAAS,KAAO,CAAC,IAAI,GAC5C,IAAa,EAAQ,cAAA;CAC3B,IAAI,EAAU,GAAS,CAAU,GAAG,OAAO,CAAC;CAC5C,IAAI,CAAC,EAA0B,GAAK,GAAW,CAAc,GAEzD,OADA,EAA2B,GAAK,GAAW,CAAU,GAC9C,CAAC;CAEZ,IAAM,IAAa,EAAQ,cAAA,cACrB,IAAQ,EAAQ,WAAW,EAAQ,SAAS,IAAI,EAAW,CAAU;CAK3E,OAJK,IAIE,GAAG,IAAa,EAAM,KAHzB,EAAmB,EAAQ,WAAW,aAAa,CAAU,GACtD,CAAC;AAGhB"}
1
+ {"version":3,"file":"csrf.js","names":["DEFAULT_CSRF_COOKIE_NAME","DEFAULT_CSRF_HEADER_NAME","SAFE_METHODS","reportedMissing","readCookie","prefix","name","part","entry","raw","reportMissingToken","isDevBuild","source","where","hasHeader","headers","csrfHeaders","input","csrf","method","options","headerName","isTrustedCredentialTarget","url","reference","trustedOrigins","reportSuppressedCredential","cookieName","token"],"sources":["../../src/http/csrf.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\nimport { isTrustedCredentialTarget, reportSuppressedCredential } from \"./credential-scope\";\n\n/**\n * Default cookie the CSRF token is read from.\n *\n * Ported from `tempest-fastapi-sdk`'s `CSRF_COOKIE_NAME`\n * (`tempest_fastapi_sdk/api/middlewares/csrf.py`), which is the cookie its\n * `make_csrf_token_dependency()` sets and its `CSRFMiddleware` compares against.\n * Matching it is what lets `csrf: true` work against that backend with no\n * configuration on either side.\n */\nexport const DEFAULT_CSRF_COOKIE_NAME = \"csrf_token\";\n\n/**\n * Default header the CSRF token is echoed in.\n *\n * Ported from `tempest-fastapi-sdk`'s `CSRF_HEADER_NAME`, the header its\n * `CSRFMiddleware` reads on every unsafe request.\n */\nexport const DEFAULT_CSRF_HEADER_NAME = \"X-CSRF-Token\";\n\n/**\n * Where the CSRF token comes from and which header carries it.\n *\n * The default is the **double-submit cookie**: the server sets a cookie that is\n * deliberately not `HttpOnly`, the client reads it and echoes the value in a\n * header, and the server rejects a write whose header does not match the\n * cookie. A page on another site can make the browser *send* the cookie, but\n * cannot *read* it, so it cannot write the header.\n *\n * The token is read again on every request, so a server that rotates the\n * cookie is followed without any capture step: the browser's cookie jar is the\n * store. That is also why there is no \"read the token from a response header\"\n * mode — it would depend on `Access-Control-Expose-Headers`, and a missing\n * expose header fails silently, as a `403` on the second write.\n */\nexport interface CsrfOptions {\n /** Cookie to read the token from. Default {@link DEFAULT_CSRF_COOKIE_NAME}. */\n cookieName?: string;\n /** Header to send the token in. Default {@link DEFAULT_CSRF_HEADER_NAME}. */\n headerName?: string;\n /**\n * Supply the token yourself instead of reading `cookieName`.\n *\n * For the cases the cookie cannot serve: an API on another **site**, whose\n * cookie `document.cookie` cannot see, or a backend that hands the token\n * out in a response body. Called per request, like `getToken`.\n */\n getToken?: () => string | null | undefined;\n}\n\n/**\n * Methods that must not change state, and so never carry the token.\n *\n * A deny list rather than an allow list of the four write verbs: RFC 9110\n * names the safe methods, and a custom method (`PROPFIND`, a tus extension)\n * is a write until proven otherwise. Sending the token to its own origin on\n * an unexpected verb costs nothing; omitting it costs a `403`.\n */\nconst SAFE_METHODS: ReadonlySet<string> = new Set([\"GET\", \"HEAD\", \"OPTIONS\", \"TRACE\"]);\n\n/** Token sources already reported empty, so a burst of writes warns once. */\nconst reportedMissing = new Set<string>();\n\n/**\n * Read one cookie from `document.cookie`, or `null` when it is absent.\n *\n * Returns `null` outside a document (a worker, a test without jsdom), where\n * there is no cookie jar to read. The value is URI-decoded when it can be,\n * and returned raw when it is not valid percent-encoding.\n *\n * @param name - The cookie name.\n * @returns The value, or `null`.\n */\nfunction readCookie(name: string): string | null {\n if (typeof document === \"undefined\") return null;\n const prefix = `${name}=`;\n for (const part of document.cookie.split(\";\")) {\n const entry = part.trim();\n if (!entry.startsWith(prefix)) continue;\n const raw = entry.slice(prefix.length);\n try {\n return decodeURIComponent(raw);\n } catch {\n return raw;\n }\n }\n return null;\n}\n\n/**\n * Say once, in a development build, that CSRF is on but there is no token.\n *\n * The request still goes out, because the SDK cannot know whether this path\n * is guarded — `CSRFMiddleware` is commonly mounted with `exclude_paths`. When\n * it is guarded, the symptom is a `403 CSRF_VALIDATION_FAILED` with nothing\n * in the app's code pointing at the cause, and the three usual causes are all\n * on the server: the cookie was never issued, was issued `HttpOnly`, or was\n * issued for a domain this page cannot read.\n *\n * @param source - What was read: the cookie name, or `\"getToken\"`.\n */\nfunction reportMissingToken(source: string): void {\n if (!isDevBuild() || reportedMissing.has(source)) return;\n reportedMissing.add(source);\n const where =\n source === \"getToken\"\n ? \"csrf.getToken() returned nothing\"\n : `no readable \"${source}\" cookie on this page`;\n console.warn(\n `[tempest-react-sdk] CSRF is enabled but ${where}, so the write went without the token. The cookie must be issued before the first write and must not be HttpOnly.`,\n );\n}\n\n/**\n * Whether a header is already present, compared case-insensitively.\n *\n * Header names are case-insensitive, but object keys are not: a caller's\n * `\"x-csrf-token\"` next to the SDK's `\"X-CSRF-Token\"` would reach `fetch` as\n * two entries and be joined into `\"a, b\"`, which matches neither.\n *\n * @param headers - The headers the caller already set.\n * @param name - The header to look for.\n * @returns Whether it is set.\n */\nfunction hasHeader(headers: HeadersInit | undefined, name: string): boolean {\n if (!headers) return false;\n return new Headers(headers).has(name);\n}\n\n/** What {@link csrfHeaders} needs to decide. */\nexport interface CsrfHeadersInput {\n /** The HTTP method of the request. Case-insensitive. */\n method: string;\n /** The URL the request is going to. */\n url: string;\n /**\n * The origin the token belongs to, normally the API's `baseURL`. The token\n * is only sent to this origin or to one listed in `trustedOrigins`.\n */\n reference: string;\n /** The CSRF config. `undefined` or `false` turns the header off. */\n csrf: boolean | CsrfOptions | undefined;\n /** Extra origins allowed to receive the token. */\n trustedOrigins?: readonly string[];\n /** Headers the caller already set. A CSRF header among them is never replaced. */\n headers?: HeadersInit;\n}\n\n/**\n * The CSRF header a request should carry, or an empty object.\n *\n * Every request path in the SDK — `createApiClient`, `uploadWithProgress`,\n * `createResumableUpload` — asks this function, so the rules are one rule:\n *\n * - **Off unless configured.** Without `csrf`, nothing changes.\n * - **Unsafe methods only.** `GET`, `HEAD`, `OPTIONS` and `TRACE` never carry\n * it; they must not change state, and a token in a `GET` ends up in logs\n * and caches for nothing.\n * - **Never across an origin.** The token follows the same scope as the bearer\n * credential ({@link isTrustedCredentialTarget}), because a URL can come off\n * the network — a tus `Location`, a pagination link — and a CSRF token sent\n * to a third party is a token that third party can replay. Withheld tokens\n * are reported once per origin in a development build.\n * - **Your header wins.** A CSRF header you set by hand, in any casing, is\n * left alone.\n * - **Independent of auth.** It is sent on `skipAuth` requests too: login and\n * refresh are exactly the writes a cookie session exposes to forgery.\n *\n * Exported for the request you build by hand, so it follows the same rules.\n *\n * @example\n * const headers = csrfHeaders({\n * method: \"POST\",\n * url: \"https://api.acme.com/orders\",\n * reference: \"https://api.acme.com\",\n * csrf: true,\n * });\n * // { \"X-CSRF-Token\": \"<value of the csrf_token cookie>\" }\n *\n * @param input - The request and the CSRF config.\n * @returns A header record to spread into the request's headers.\n */\nexport function csrfHeaders(input: CsrfHeadersInput): Record<string, string> {\n const { method, url, reference, csrf, trustedOrigins, headers } = input;\n if (!csrf) return {};\n if (SAFE_METHODS.has(method.toUpperCase())) return {};\n const options: CsrfOptions = csrf === true ? {} : csrf;\n const headerName = options.headerName ?? DEFAULT_CSRF_HEADER_NAME;\n if (hasHeader(headers, headerName)) return {};\n if (!isTrustedCredentialTarget(url, reference, trustedOrigins)) {\n reportSuppressedCredential(url, reference, headerName);\n return {};\n }\n const cookieName = options.cookieName ?? DEFAULT_CSRF_COOKIE_NAME;\n const token = options.getToken ? options.getToken() : readCookie(cookieName);\n if (!token) {\n reportMissingToken(options.getToken ? \"getToken\" : cookieName);\n return {};\n }\n return { [headerName]: token };\n}\n\n/**\n * Forget which token sources were already reported empty.\n *\n * Exported for tests, which assert the once-per-source behaviour and would\n * otherwise leak state between cases.\n */\nexport function resetCsrfReports(): void {\n reportedMissing.clear();\n}\n"],"mappings":";;;AAYA,IAAaA,IAA2B,cAQ3BC,IAA2B,gBAwClCC,oBAAoC,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAW;AAAO,CAAC,GAG/EC,oBAAkB,IAAI,IAAY;AAYxC,SAASC,EAAW,GAA6B;CAC7C,IAAI,OAAO,WAAa,KAAa,OAAO;CAC5C,IAAMC,IAAS,GAAGC,EAAK;CACvB,KAAK,IAAMC,KAAQ,SAAS,OAAO,MAAM,GAAG,GAAG;EAC3C,IAAMC,IAAQD,EAAK,KAAK;EACxB,IAAI,CAACC,EAAM,WAAWH,CAAM,GAAG;EAC/B,IAAMI,IAAMD,EAAM,MAAMH,EAAO,MAAM;EACrC,IAAI;GACA,OAAO,mBAAmBI,CAAG;EACjC,QAAQ;GACJ,OAAOA;EACX;CACJ;CACA,OAAO;AACX;AAcA,SAASC,EAAmB,GAAsB;CAC9C,IAAI,CAACC,EAAW,KAAKR,EAAgB,IAAIS,CAAM,GAAG;CAClD,EAAgB,IAAIA,CAAM;CAC1B,IAAMC,IACFD,MAAW,aACL,qCACA,gBAAgBA,EAAO;CACjC,QAAQ,KACJ,2CAA2CC,EAAM,kHACrD;AACJ;AAaA,SAASC,EAAU,GAAkC,GAAuB;CAExE,OADKC,IACE,IAAI,QAAQA,CAAO,CAAC,CAAC,IAAIT,CAAI,IADf;AAEzB;AAuDA,SAAgBU,EAAY,GAAiD;CACzE,IAAM,EAAE,WAAQ,QAAK,cAAW,SAAM,mBAAgB,eAAYC;CAElE,IADI,CAACC,KACDhB,EAAa,IAAIiB,EAAO,YAAY,CAAC,GAAG,OAAO,CAAC;CACpD,IAAMC,IAAuBF,MAAS,KAAO,CAAC,IAAIA,GAC5CG,IAAaD,EAAQ,cAAA;CAC3B,IAAIN,EAAUC,GAASM,CAAU,GAAG,OAAO,CAAC;CAC5C,IAAI,CAACC,EAA0BC,GAAKC,GAAWC,CAAc,GAEzD,OADAC,EAA2BH,GAAKC,GAAWH,CAAU,GAC9C,CAAC;CAEZ,IAAMM,IAAaP,EAAQ,cAAA,cACrBQ,IAAQR,EAAQ,WAAWA,EAAQ,SAAS,IAAIhB,EAAWuB,CAAU;CAK3E,OAJKC,IAIE,GAAGP,IAAaO,EAAM,KAHzBlB,EAAmBU,EAAQ,WAAW,aAAaO,CAAU,GACtD,CAAC;AAGhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"decode-response.cjs","names":[],"sources":["../../src/http/decode-response.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\n\n/**\n * Media-type fragments that name something safe to read as text, for the types\n * that do not open with `text/` — `application/xml`, `application/javascript`,\n * `application/x-www-form-urlencoded`.\n */\nconst TEXTUAL_TOKENS: readonly string[] = [\"xml\", \"javascript\", \"ecmascript\", \"urlencoded\", \"csv\"];\n\n/** How a {@link createApiClient} response body becomes the value a caller awaited. */\nexport type ResponseDecoder<T> = (response: Response) => Promise<T>;\n\n/**\n * Whether a `Content-Type` names a JSON dialect.\n *\n * Matches the suffix forms as well as the plain one, so `application/json`,\n * `application/problem+json` (RFC 9457, what a FastAPI error handler sends) and\n * `application/vnd.tempest.v2+json` all decode as JSON instead of falling\n * through to text.\n *\n * @param contentType - The raw header value, possibly with parameters.\n * @returns Whether the body should be read with `response.json()`.\n */\nexport function isJsonContentType(contentType: string): boolean {\n return contentType.toLowerCase().includes(\"json\");\n}\n\n/**\n * Whether a `Content-Type` names something that survives being read as text.\n *\n * An absent header counts as textual: a backend that answers without one is\n * almost always sending text, and treating it as binary would change what\n * existing callers get back for no measured gain.\n *\n * @param contentType - The raw header value, possibly with parameters.\n * @returns Whether the body should be read with `response.text()`.\n */\nexport function isTextualContentType(contentType: string): boolean {\n const type = contentType.trim().toLowerCase();\n if (type === \"\") return true;\n if (type.startsWith(\"text/\")) return true;\n return TEXTUAL_TOKENS.some((token) => type.includes(token));\n}\n\n/**\n * Warn, in a development build, that a binary body reached the JSON/text path.\n *\n * @param contentType - The `Content-Type` that was decoded as a `Blob`.\n */\nfunction warnBinaryBody(contentType: string): void {\n if (!isDevBuild()) return;\n console.warn(\n `[tempest] <ApiClient> received a binary response (content-type: ${contentType}) and returned a Blob. ` +\n \"Call `client.blob()` or `client.arrayBuffer()` so the type matches what arrives.\",\n );\n}\n\n/**\n * Decode a response the way its `Content-Type` asks to be decoded.\n *\n * JSON is parsed, text is read as text, and **everything else comes back as a\n * `Blob`**. That last branch is the fix for a silent data defect: the client\n * used to fall back to `response.text()` for any non-JSON body, so an\n * `image/jpeg` was decoded as UTF-8 and the bytes were destroyed on the way in.\n * Measured on a bare JPEG header — `ff d8 ff e0 00 10 4a 46 49 46` — the\n * round-trip through text returns 18 bytes for the 10 that arrived, 4 of them\n * replaced by `U+FFFD`. No caller can undo that, which is why the download had\n * to leave the client entirely.\n *\n * A `204` has no body at all and resolves to `undefined`, whatever the headers\n * claim.\n *\n * @typeParam T - What the caller expects back.\n * @param response - A response already known to be successful.\n * @returns The decoded body.\n */\nexport async function decodeByContentType<T>(response: Response): Promise<T> {\n if (response.status === 204) {\n return undefined as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (isJsonContentType(contentType)) {\n return (await response.json()) as T;\n }\n if (isTextualContentType(contentType)) {\n return (await response.text()) as unknown as T;\n }\n\n warnBinaryBody(contentType);\n return (await response.blob()) as unknown as T;\n}\n"],"mappings":"yCAOA,IAAM,EAAoC,CAAC,MAAO,aAAc,aAAc,aAAc,KAAK,EAgBjG,SAAgB,EAAkB,EAA8B,CAC5D,OAAO,EAAY,YAAY,CAAC,CAAC,SAAS,MAAM,CACpD,CAYA,SAAgB,EAAqB,EAA8B,CAC/D,IAAM,EAAO,EAAY,KAAK,CAAC,CAAC,YAAY,EAG5C,OAFI,IAAS,IACT,EAAK,WAAW,OAAO,EAAU,GAC9B,EAAe,KAAM,GAAU,EAAK,SAAS,CAAK,CAAC,CAC9D,CAOA,SAAS,EAAe,EAA2B,CAC1C,EAAA,WAAW,GAChB,QAAQ,KACJ,mEAAmE,EAAY,4GAEnF,CACJ,CAqBA,eAAsB,EAAuB,EAAgC,CACzE,GAAI,EAAS,SAAW,IACpB,OAGJ,IAAM,EAAc,EAAS,QAAQ,IAAI,cAAc,GAAK,GAS5D,OARI,EAAkB,CAAW,EACrB,MAAM,EAAS,KAAK,EAE5B,EAAqB,CAAW,EACxB,MAAM,EAAS,KAAK,GAGhC,EAAe,CAAW,EAClB,MAAM,EAAS,KAAK,EAChC"}
1
+ {"version":3,"file":"decode-response.cjs","names":["isDevBuild","require_dev_mode","TEXTUAL_TOKENS","isJsonContentType","contentType","isTextualContentType","type","token","warnBinaryBody","decodeByContentType","response"],"sources":["../../src/http/decode-response.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\n\n/**\n * Media-type fragments that name something safe to read as text, for the types\n * that do not open with `text/` — `application/xml`, `application/javascript`,\n * `application/x-www-form-urlencoded`.\n */\nconst TEXTUAL_TOKENS: readonly string[] = [\"xml\", \"javascript\", \"ecmascript\", \"urlencoded\", \"csv\"];\n\n/** How a {@link createApiClient} response body becomes the value a caller awaited. */\nexport type ResponseDecoder<T> = (response: Response) => Promise<T>;\n\n/**\n * Whether a `Content-Type` names a JSON dialect.\n *\n * Matches the suffix forms as well as the plain one, so `application/json`,\n * `application/problem+json` (RFC 9457, what a FastAPI error handler sends) and\n * `application/vnd.tempest.v2+json` all decode as JSON instead of falling\n * through to text.\n *\n * @param contentType - The raw header value, possibly with parameters.\n * @returns Whether the body should be read with `response.json()`.\n */\nexport function isJsonContentType(contentType: string): boolean {\n return contentType.toLowerCase().includes(\"json\");\n}\n\n/**\n * Whether a `Content-Type` names something that survives being read as text.\n *\n * An absent header counts as textual: a backend that answers without one is\n * almost always sending text, and treating it as binary would change what\n * existing callers get back for no measured gain.\n *\n * @param contentType - The raw header value, possibly with parameters.\n * @returns Whether the body should be read with `response.text()`.\n */\nexport function isTextualContentType(contentType: string): boolean {\n const type = contentType.trim().toLowerCase();\n if (type === \"\") return true;\n if (type.startsWith(\"text/\")) return true;\n return TEXTUAL_TOKENS.some((token) => type.includes(token));\n}\n\n/**\n * Warn, in a development build, that a binary body reached the JSON/text path.\n *\n * @param contentType - The `Content-Type` that was decoded as a `Blob`.\n */\nfunction warnBinaryBody(contentType: string): void {\n if (!isDevBuild()) return;\n console.warn(\n `[tempest] <ApiClient> received a binary response (content-type: ${contentType}) and returned a Blob. ` +\n \"Call `client.blob()` or `client.arrayBuffer()` so the type matches what arrives.\",\n );\n}\n\n/**\n * Decode a response the way its `Content-Type` asks to be decoded.\n *\n * JSON is parsed, text is read as text, and **everything else comes back as a\n * `Blob`**. That last branch is the fix for a silent data defect: the client\n * used to fall back to `response.text()` for any non-JSON body, so an\n * `image/jpeg` was decoded as UTF-8 and the bytes were destroyed on the way in.\n * Measured on a bare JPEG header — `ff d8 ff e0 00 10 4a 46 49 46` — the\n * round-trip through text returns 18 bytes for the 10 that arrived, 4 of them\n * replaced by `U+FFFD`. No caller can undo that, which is why the download had\n * to leave the client entirely.\n *\n * A `204` has no body at all and resolves to `undefined`, whatever the headers\n * claim.\n *\n * @typeParam T - What the caller expects back.\n * @param response - A response already known to be successful.\n * @returns The decoded body.\n */\nexport async function decodeByContentType<T>(response: Response): Promise<T> {\n if (response.status === 204) {\n return undefined as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (isJsonContentType(contentType)) {\n return (await response.json()) as T;\n }\n if (isTextualContentType(contentType)) {\n return (await response.text()) as unknown as T;\n }\n\n warnBinaryBody(contentType);\n return (await response.blob()) as unknown as T;\n}\n"],"mappings":"A,yCAOA,IAAME,EAAoC,CAAC,MAAO,aAAc,aAAc,aAAc,KAAK,EAgBjG,SAAgBC,EAAkB,EAA8B,CAC5D,OAAOC,EAAY,YAAY,CAAC,CAAC,SAAS,MAAM,CACpD,CAYA,SAAgBC,EAAqB,EAA8B,CAC/D,IAAMC,EAAOF,EAAY,KAAK,CAAC,CAAC,YAAY,EAG5C,OAFIE,IAAS,IACTA,EAAK,WAAW,OAAO,EAAU,GAC9BJ,EAAe,KAAM,GAAUI,EAAK,SAASC,CAAK,CAAC,CAC9D,CAOA,SAASC,EAAe,EAA2B,CAC1CR,EAAAA,WAAW,GAChB,QAAQ,KACJ,mEAAmEI,EAAY,4GAEnF,CACJ,CAqBA,eAAsBK,EAAuB,EAAgC,CACzE,GAAIC,EAAS,SAAW,IACpB,OAGJ,IAAMN,EAAcM,EAAS,QAAQ,IAAI,cAAc,GAAK,GAS5D,OARIP,EAAkBC,CAAW,EACrB,MAAMM,EAAS,KAAK,EAE5BL,EAAqBD,CAAW,EACxB,MAAMM,EAAS,KAAK,GAGhCF,EAAeJ,CAAW,EAClB,MAAMM,EAAS,KAAK,EAChC,C"}
@@ -1 +1 @@
1
- {"version":3,"file":"decode-response.js","names":[],"sources":["../../src/http/decode-response.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\n\n/**\n * Media-type fragments that name something safe to read as text, for the types\n * that do not open with `text/` — `application/xml`, `application/javascript`,\n * `application/x-www-form-urlencoded`.\n */\nconst TEXTUAL_TOKENS: readonly string[] = [\"xml\", \"javascript\", \"ecmascript\", \"urlencoded\", \"csv\"];\n\n/** How a {@link createApiClient} response body becomes the value a caller awaited. */\nexport type ResponseDecoder<T> = (response: Response) => Promise<T>;\n\n/**\n * Whether a `Content-Type` names a JSON dialect.\n *\n * Matches the suffix forms as well as the plain one, so `application/json`,\n * `application/problem+json` (RFC 9457, what a FastAPI error handler sends) and\n * `application/vnd.tempest.v2+json` all decode as JSON instead of falling\n * through to text.\n *\n * @param contentType - The raw header value, possibly with parameters.\n * @returns Whether the body should be read with `response.json()`.\n */\nexport function isJsonContentType(contentType: string): boolean {\n return contentType.toLowerCase().includes(\"json\");\n}\n\n/**\n * Whether a `Content-Type` names something that survives being read as text.\n *\n * An absent header counts as textual: a backend that answers without one is\n * almost always sending text, and treating it as binary would change what\n * existing callers get back for no measured gain.\n *\n * @param contentType - The raw header value, possibly with parameters.\n * @returns Whether the body should be read with `response.text()`.\n */\nexport function isTextualContentType(contentType: string): boolean {\n const type = contentType.trim().toLowerCase();\n if (type === \"\") return true;\n if (type.startsWith(\"text/\")) return true;\n return TEXTUAL_TOKENS.some((token) => type.includes(token));\n}\n\n/**\n * Warn, in a development build, that a binary body reached the JSON/text path.\n *\n * @param contentType - The `Content-Type` that was decoded as a `Blob`.\n */\nfunction warnBinaryBody(contentType: string): void {\n if (!isDevBuild()) return;\n console.warn(\n `[tempest] <ApiClient> received a binary response (content-type: ${contentType}) and returned a Blob. ` +\n \"Call `client.blob()` or `client.arrayBuffer()` so the type matches what arrives.\",\n );\n}\n\n/**\n * Decode a response the way its `Content-Type` asks to be decoded.\n *\n * JSON is parsed, text is read as text, and **everything else comes back as a\n * `Blob`**. That last branch is the fix for a silent data defect: the client\n * used to fall back to `response.text()` for any non-JSON body, so an\n * `image/jpeg` was decoded as UTF-8 and the bytes were destroyed on the way in.\n * Measured on a bare JPEG header — `ff d8 ff e0 00 10 4a 46 49 46` — the\n * round-trip through text returns 18 bytes for the 10 that arrived, 4 of them\n * replaced by `U+FFFD`. No caller can undo that, which is why the download had\n * to leave the client entirely.\n *\n * A `204` has no body at all and resolves to `undefined`, whatever the headers\n * claim.\n *\n * @typeParam T - What the caller expects back.\n * @param response - A response already known to be successful.\n * @returns The decoded body.\n */\nexport async function decodeByContentType<T>(response: Response): Promise<T> {\n if (response.status === 204) {\n return undefined as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (isJsonContentType(contentType)) {\n return (await response.json()) as T;\n }\n if (isTextualContentType(contentType)) {\n return (await response.text()) as unknown as T;\n }\n\n warnBinaryBody(contentType);\n return (await response.blob()) as unknown as T;\n}\n"],"mappings":";;AAOA,IAAM,IAAoC;CAAC;CAAO;CAAc;CAAc;CAAc;AAAK;AAgBjG,SAAgB,EAAkB,GAA8B;CAC5D,OAAO,EAAY,YAAY,CAAC,CAAC,SAAS,MAAM;AACpD;AAYA,SAAgB,EAAqB,GAA8B;CAC/D,IAAM,IAAO,EAAY,KAAK,CAAC,CAAC,YAAY;CAG5C,OAFI,MAAS,MACT,EAAK,WAAW,OAAO,IAAU,KAC9B,EAAe,MAAM,MAAU,EAAK,SAAS,CAAK,CAAC;AAC9D;AAOA,SAAS,EAAe,GAA2B;CAC1C,EAAW,KAChB,QAAQ,KACJ,mEAAmE,EAAY,4GAEnF;AACJ;AAqBA,eAAsB,EAAuB,GAAgC;CACzE,IAAI,EAAS,WAAW,KACpB;CAGJ,IAAM,IAAc,EAAS,QAAQ,IAAI,cAAc,KAAK;CAS5D,OARI,EAAkB,CAAW,IACrB,MAAM,EAAS,KAAK,IAE5B,EAAqB,CAAW,IACxB,MAAM,EAAS,KAAK,KAGhC,EAAe,CAAW,GAClB,MAAM,EAAS,KAAK;AAChC"}
1
+ {"version":3,"file":"decode-response.js","names":["TEXTUAL_TOKENS","isJsonContentType","contentType","isTextualContentType","type","token","warnBinaryBody","isDevBuild","decodeByContentType","response"],"sources":["../../src/http/decode-response.ts"],"sourcesContent":["import { isDevBuild } from \"../utils/dev-mode\";\n\n/**\n * Media-type fragments that name something safe to read as text, for the types\n * that do not open with `text/` — `application/xml`, `application/javascript`,\n * `application/x-www-form-urlencoded`.\n */\nconst TEXTUAL_TOKENS: readonly string[] = [\"xml\", \"javascript\", \"ecmascript\", \"urlencoded\", \"csv\"];\n\n/** How a {@link createApiClient} response body becomes the value a caller awaited. */\nexport type ResponseDecoder<T> = (response: Response) => Promise<T>;\n\n/**\n * Whether a `Content-Type` names a JSON dialect.\n *\n * Matches the suffix forms as well as the plain one, so `application/json`,\n * `application/problem+json` (RFC 9457, what a FastAPI error handler sends) and\n * `application/vnd.tempest.v2+json` all decode as JSON instead of falling\n * through to text.\n *\n * @param contentType - The raw header value, possibly with parameters.\n * @returns Whether the body should be read with `response.json()`.\n */\nexport function isJsonContentType(contentType: string): boolean {\n return contentType.toLowerCase().includes(\"json\");\n}\n\n/**\n * Whether a `Content-Type` names something that survives being read as text.\n *\n * An absent header counts as textual: a backend that answers without one is\n * almost always sending text, and treating it as binary would change what\n * existing callers get back for no measured gain.\n *\n * @param contentType - The raw header value, possibly with parameters.\n * @returns Whether the body should be read with `response.text()`.\n */\nexport function isTextualContentType(contentType: string): boolean {\n const type = contentType.trim().toLowerCase();\n if (type === \"\") return true;\n if (type.startsWith(\"text/\")) return true;\n return TEXTUAL_TOKENS.some((token) => type.includes(token));\n}\n\n/**\n * Warn, in a development build, that a binary body reached the JSON/text path.\n *\n * @param contentType - The `Content-Type` that was decoded as a `Blob`.\n */\nfunction warnBinaryBody(contentType: string): void {\n if (!isDevBuild()) return;\n console.warn(\n `[tempest] <ApiClient> received a binary response (content-type: ${contentType}) and returned a Blob. ` +\n \"Call `client.blob()` or `client.arrayBuffer()` so the type matches what arrives.\",\n );\n}\n\n/**\n * Decode a response the way its `Content-Type` asks to be decoded.\n *\n * JSON is parsed, text is read as text, and **everything else comes back as a\n * `Blob`**. That last branch is the fix for a silent data defect: the client\n * used to fall back to `response.text()` for any non-JSON body, so an\n * `image/jpeg` was decoded as UTF-8 and the bytes were destroyed on the way in.\n * Measured on a bare JPEG header — `ff d8 ff e0 00 10 4a 46 49 46` — the\n * round-trip through text returns 18 bytes for the 10 that arrived, 4 of them\n * replaced by `U+FFFD`. No caller can undo that, which is why the download had\n * to leave the client entirely.\n *\n * A `204` has no body at all and resolves to `undefined`, whatever the headers\n * claim.\n *\n * @typeParam T - What the caller expects back.\n * @param response - A response already known to be successful.\n * @returns The decoded body.\n */\nexport async function decodeByContentType<T>(response: Response): Promise<T> {\n if (response.status === 204) {\n return undefined as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (isJsonContentType(contentType)) {\n return (await response.json()) as T;\n }\n if (isTextualContentType(contentType)) {\n return (await response.text()) as unknown as T;\n }\n\n warnBinaryBody(contentType);\n return (await response.blob()) as unknown as T;\n}\n"],"mappings":";;AAOA,IAAMA,IAAoC;CAAC;CAAO;CAAc;CAAc;CAAc;AAAK;AAgBjG,SAAgBC,EAAkB,GAA8B;CAC5D,OAAOC,EAAY,YAAY,CAAC,CAAC,SAAS,MAAM;AACpD;AAYA,SAAgBC,EAAqB,GAA8B;CAC/D,IAAMC,IAAOF,EAAY,KAAK,CAAC,CAAC,YAAY;CAG5C,OAFIE,MAAS,MACTA,EAAK,WAAW,OAAO,IAAU,KAC9BJ,EAAe,MAAM,MAAUI,EAAK,SAASC,CAAK,CAAC;AAC9D;AAOA,SAASC,EAAe,GAA2B;CAC/C,AAAKC,EAAW,KAChB,QAAQ,KACJ,mEAAmEL,EAAY,4GAEnF;AACJ;AAqBA,eAAsBM,EAAuB,GAAgC;CACzE,IAAIC,EAAS,WAAW,KACpB;CAGJ,IAAMP,IAAcO,EAAS,QAAQ,IAAI,cAAc,KAAK;CAS5D,OARIR,EAAkBC,CAAW,IACrB,MAAMO,EAAS,KAAK,IAE5BN,EAAqBD,CAAW,IACxB,MAAMO,EAAS,KAAK,KAGhCH,EAAeJ,CAAW,GAClB,MAAMO,EAAS,KAAK;AAChC"}
@@ -1 +1 @@
1
- {"version":3,"file":"describe-api-error.cjs","names":[],"sources":["../../src/http/describe-api-error.ts"],"sourcesContent":["// The last mile of error handling: a typed error is what code reads, a sentence\n// is what a person reads, and every app was writing the funnel between the two.\n// The case everyone forgets is the request that never reached the server, which\n// without special handling renders as the nonsense \"erro 0\".\n\nimport { isApiError, syntheticDetail } from \"./errors\";\n\n/** The fixed sentences {@link describeApiError} may need. */\nexport interface ApiErrorStrings {\n /** Shown when the request never reached the server. */\n offline: string;\n /**\n * Shown when the backend rejected the payload field by field.\n *\n * The per-field messages are on `error.fields`, to be attached to the inputs\n * themselves; this sentence is what the toast says.\n *\n * It does not apply to the one rejection that named a single field with a\n * finished sentence — there the server's own `detail` is shown instead, since\n * it is the same string `fields` carries. Pass `useDetail: false` to force\n * this sentence in that case too.\n */\n validation: string;\n}\n\n/**\n * PT-BR defaults, used when no strings are supplied and no catalog answers.\n *\n * The SDK's copy is pt-BR everywhere else (`FilterBar`, `DataTable`, `Chat`), so\n * the default here matches rather than introducing an English string that only\n * shows up on a network failure.\n */\nexport const DEFAULT_API_ERROR_STRINGS: ApiErrorStrings = {\n offline: \"Sem conexão com o servidor. Verifique sua internet e tente de novo.\",\n validation: \"Confira os campos destacados e tente de novo.\",\n};\n\n/**\n * Translation key the {@link useDescribeApiError} hook looks up.\n *\n * A catalog that does not define it falls back to\n * {@link DEFAULT_API_ERROR_STRINGS}, because `t` returns the key itself when the\n * lookup misses and printing `tempest.error.offline` at the user would be worse\n * than printing pt-BR at them.\n */\nexport const API_ERROR_OFFLINE_KEY = \"tempest.error.offline\";\n\n/**\n * Translation key for the validation sentence, looked up the same way as\n * {@link API_ERROR_OFFLINE_KEY}.\n */\nexport const API_ERROR_VALIDATION_KEY = \"tempest.error.validation\";\n\n/**\n * Everything {@link describeApiError} accepts beyond the error and the fallback.\n *\n * Extends the fixed sentences rather than sitting beside them, so a caller that\n * already passed `{ offline, validation }` keeps compiling untouched.\n */\nexport interface DescribeApiErrorOptions extends Partial<ApiErrorStrings> {\n /**\n * Maps the backend's programmatic `code` to a sentence in your language.\n *\n * The client already surfaces `code` on `ApiError`, but without this every\n * app writes the same `switch` over it. A hit here wins over every other\n * step: it is the only sentence written for that exact case, by someone who\n * knew both the backend contract and the screen it lands on.\n */\n codes?: Readonly<Record<string, string>>;\n /**\n * Maps an HTTP status to a sentence, for the failures that arrive with no\n * useful body.\n *\n * `codes` covers the cases the backend named; this covers the ones it did\n * not. The reference case is the `403` of an admin-only route: the body\n * carries a generic `detail` (or none), so the funnel fell through to the\n * fallback and an administrator read \"Não foi possível carregar\" when the\n * fact that answers their question is \"esta listagem é só para\n * administradores\".\n *\n * Checked after `codes` and **before** the backend's `detail`: a generic\n * sentence emitted by the framework is worse than the one the app wrote for\n * that status. `useDetail: false` remains the way to suppress `detail`\n * entirely.\n *\n * A `0` key is honoured like any other, ahead of the offline sentence —\n * `statuses` is the caller's explicit map, and the fixed `offline` string is\n * already the way to reword that case. Status `0` covers a request that\n * never landed **and** one abandoned by the client timeout, so an app that\n * maps it is taking both.\n */\n statuses?: Readonly<Record<number, string>>;\n /**\n * Whether the backend's `detail` may be shown when no `code` matched.\n * Default `true`.\n *\n * Set it to `false` when `detail` is written for developers rather than\n * users, or when it could echo internals — the result is then always either\n * a sentence you wrote or the fallback.\n */\n useDetail?: boolean;\n}\n\n/**\n * Whether the browser currently reports itself as offline.\n *\n * `fetch` rejects a network failure with a plain `TypeError` whose message\n * differs per browser (\"Failed to fetch\", \"NetworkError when attempting to fetch\n * resource.\", \"Load failed\"), so sniffing the message is not portable. The online\n * flag is, and it is the signal that matters for the sentence being chosen.\n *\n * @returns `true` only when the environment positively says it is offline.\n */\nfunction browserIsOffline(): boolean {\n return typeof navigator !== \"undefined\" && navigator.onLine === false;\n}\n\n/**\n * Whether `fields` is the flattened single-field envelope, carrying `detail`.\n *\n * The check is identity rather than shape-sniffing. `collectFields` has exactly\n * two sources: FastAPI's `detail` **list**, whose entries are the per-issue\n * messages, and the flattened envelope, whose one entry is built from the same\n * string that becomes `ApiError.detail`. So one entry equal to `detail` can only\n * have come from the second, and returning `detail` there shows the string the\n * form is already about to attach to that input.\n *\n * @param fields - The error's field messages.\n * @param detail - `error.detail`, already trimmed.\n * @param status - The HTTP status, to recognise the synthetic `Erro <status>`\n * that stands in when the body carried no message at all.\n * @returns Whether `detail` is safe to show as the sentence.\n */\nfunction singleFieldSentence(\n fields: Record<string, string>,\n detail: string,\n status: number,\n): boolean {\n if (detail === \"\" || detail === syntheticDetail(status)) return false;\n const messages = Object.values(fields);\n return messages.length === 1 && messages[0].trim() === detail;\n}\n\n/**\n * Turn any caught value into a sentence worth showing.\n *\n * The funnel, in order:\n *\n * 0. `codes[error.code]` — the sentence you wrote for that exact backend case.\n * Checked first because nothing the funnel derives can beat it, and because a\n * request that never landed carries no `code` for it to shadow.\n * 0.5. `statuses[error.status]` — the sentence for a whole class of failure,\n * for the errors that arrive with no useful body. It beats the backend's\n * `detail`, because a generic line emitted by the framework is worse than the\n * one the app wrote for that status, and it beats the offline sentence when\n * the caller maps `0` explicitly.\n * 1. A request that never reached the server — `status === 0`, or a non-API\n * error thrown while the browser reports itself offline — produces the\n * offline sentence. This is the step apps skip, and skipping it renders\n * \"erro 0\" or a raw `TypeError` at the user.\n * 2. A validation rejection — `error.fields` is set — produces the validation\n * sentence, **not** `detail`. On a FastAPI `422` the `detail` line is assembled\n * from the backend's field paths and the validator's own wording\n * (`\"items.0.price: Input should be greater than 0\"`), which is right for a\n * log and wrong for a person: it is half English in a pt-BR screen and it\n * names internals. The per-field messages stay on `fields`, where a form can\n * attach them to the inputs that failed.\n *\n * **Unless the rejection named exactly one field and its message is\n * `detail` itself**, in which case `detail` is returned. That is not a guess\n * about the text: `collectFields` fills a single entry from `detail` only for\n * the flattened envelope a `tempest-fastapi-sdk` backend sends, where the\n * server wrote one finished sentence about one field (`\"CPF ou CNPJ\n * inválido\"`). Returning it shows the same string that is already on\n * `fields`, so nothing is invented and nothing is lost. The assembled FastAPI\n * line never reaches this branch, because it comes from the `detail` **list**\n * and its entries are the per-issue messages, not `detail`.\n *\n * This is a fix, not a preference. Before `namedField` shipped in 0.54.0,\n * `fields` was empty against that backend and the sentence reached the user\n * through step 3; filling `fields` silently replaced it with \"Confira os\n * campos destacados\", which presumes a screen that highlights fields — and\n * no app highlighted anything on the day of the bump.\n *\n * `useDetail: false` still suppresses it, and is the way to force the fixed\n * sentence for a backend whose text is written for developers. `validation`\n * does **not** override it, and that is on purpose: its own contract is the\n * sentence for a payload rejected *field by field*, which one field carrying\n * one finished sentence is not — and `useDescribeApiError` always passes\n * `validation`, so treating it as an override would mean the branch never ran\n * for any component, which is every caller that matters here.\n * 3. The backend's own `detail`, which is the most specific thing available and\n * is already written for a person — unless `useDetail: false` says that text\n * is for developers.\n * 4. `fallback`, with `(HTTP <status>)` appended when a status is known, so the\n * screenshot in the support ticket carries the one fact a developer needs.\n *\n * Pure on purpose: it works in an interceptor, in a logger and anywhere outside\n * the React tree. {@link useDescribeApiError} is the same funnel with the\n * sentences resolved through `I18nProvider`.\n *\n * @example\n * catch (error) {\n * toast(describeApiError(error, \"Não foi possível salvar o pedido\"));\n * }\n *\n * @example\n * catch (error) {\n * toast(\n * describeApiError(error, \"Não foi possível se candidatar\", {\n * codes: {\n * SERVICE_FULL: \"Este serviço atingiu o limite de vagas.\",\n * CANDIDATE_ALREADY_EXISTS: \"Você já se candidatou a este serviço.\",\n * },\n * useDetail: false,\n * }),\n * );\n * }\n *\n * @param error - The caught value, of any shape.\n * @param fallback - What to say when the error carries nothing better.\n * @param options - A `codes` catalog, `useDetail`, and overrides for the fixed\n * sentences.\n * @returns A sentence to show the user.\n */\nexport function describeApiError(\n error: unknown,\n fallback: string,\n options?: DescribeApiErrorOptions,\n): string {\n const offline = options?.offline ?? DEFAULT_API_ERROR_STRINGS.offline;\n\n if (isApiError(error)) {\n const mapped = error.code === undefined ? undefined : options?.codes?.[error.code];\n if (mapped !== undefined) return mapped;\n const byStatus = options?.statuses?.[error.status];\n if (byStatus !== undefined) return byStatus;\n if (error.status === 0) return offline;\n const detail = error.detail.trim();\n if (error.fields && Object.keys(error.fields).length > 0) {\n if (\n options?.useDetail !== false &&\n singleFieldSentence(error.fields, detail, error.status)\n ) {\n return detail;\n }\n return options?.validation ?? DEFAULT_API_ERROR_STRINGS.validation;\n }\n if (\n options?.useDetail !== false &&\n detail !== \"\" &&\n detail !== syntheticDetail(error.status)\n ) {\n return detail;\n }\n return `${fallback} (HTTP ${error.status})`;\n }\n\n if (browserIsOffline()) return offline;\n\n return fallback;\n}\n"],"mappings":"gCAgCA,IAAa,EAA6C,CACtD,QAAS,sEACT,WAAY,+CAChB,EAUa,EAAwB,wBAMxB,EAA2B,2BA8DxC,SAAS,GAA4B,CACjC,OAAO,OAAO,UAAc,KAAe,UAAU,SAAW,EACpE,CAkBA,SAAS,EACL,EACA,EACA,EACO,CACP,GAAI,IAAW,IAAM,IAAW,EAAA,gBAAgB,CAAM,EAAG,MAAO,GAChE,IAAM,EAAW,OAAO,OAAO,CAAM,EACrC,OAAO,EAAS,SAAW,GAAK,EAAS,EAAE,CAAC,KAAK,IAAM,CAC3D,CAoFA,SAAgB,EACZ,EACA,EACA,EACM,CACN,IAAM,EAAU,GAAS,SAAW,EAA0B,QAE9D,GAAI,EAAA,WAAW,CAAK,EAAG,CACnB,IAAM,EAAS,EAAM,OAAS,IAAA,GAAY,IAAA,GAAY,GAAS,QAAQ,EAAM,MAC7E,GAAI,IAAW,IAAA,GAAW,OAAO,EACjC,IAAM,EAAW,GAAS,WAAW,EAAM,QAC3C,GAAI,IAAa,IAAA,GAAW,OAAO,EACnC,GAAI,EAAM,SAAW,EAAG,OAAO,EAC/B,IAAM,EAAS,EAAM,OAAO,KAAK,EAiBjC,OAhBI,EAAM,QAAU,OAAO,KAAK,EAAM,MAAM,CAAC,CAAC,OAAS,EAE/C,GAAS,YAAc,IACvB,EAAoB,EAAM,OAAQ,EAAQ,EAAM,MAAM,EAE/C,EAEJ,GAAS,YAAc,EAA0B,WAGxD,GAAS,YAAc,IACvB,IAAW,IACX,IAAW,EAAA,gBAAgB,EAAM,MAAM,EAEhC,EAEJ,GAAG,EAAS,SAAS,EAAM,OAAO,EAC7C,CAIA,OAFI,EAAiB,EAAU,EAExB,CACX"}
1
+ {"version":3,"file":"describe-api-error.cjs","names":["syntheticDetail","isApiError","require_errors","DEFAULT_API_ERROR_STRINGS","API_ERROR_OFFLINE_KEY","API_ERROR_VALIDATION_KEY","browserIsOffline","singleFieldSentence","detail","status","messages","fields","describeApiError","offline","options","error","mapped","byStatus","fallback"],"sources":["../../src/http/describe-api-error.ts"],"sourcesContent":["// The last mile of error handling: a typed error is what code reads, a sentence\n// is what a person reads, and every app was writing the funnel between the two.\n// The case everyone forgets is the request that never reached the server, which\n// without special handling renders as the nonsense \"erro 0\".\n\nimport { isApiError, syntheticDetail } from \"./errors\";\n\n/** The fixed sentences {@link describeApiError} may need. */\nexport interface ApiErrorStrings {\n /** Shown when the request never reached the server. */\n offline: string;\n /**\n * Shown when the backend rejected the payload field by field.\n *\n * The per-field messages are on `error.fields`, to be attached to the inputs\n * themselves; this sentence is what the toast says.\n *\n * It does not apply to the one rejection that named a single field with a\n * finished sentence — there the server's own `detail` is shown instead, since\n * it is the same string `fields` carries. Pass `useDetail: false` to force\n * this sentence in that case too.\n */\n validation: string;\n}\n\n/**\n * PT-BR defaults, used when no strings are supplied and no catalog answers.\n *\n * The SDK's copy is pt-BR everywhere else (`FilterBar`, `DataTable`, `Chat`), so\n * the default here matches rather than introducing an English string that only\n * shows up on a network failure.\n */\nexport const DEFAULT_API_ERROR_STRINGS: ApiErrorStrings = {\n offline: \"Sem conexão com o servidor. Verifique sua internet e tente de novo.\",\n validation: \"Confira os campos destacados e tente de novo.\",\n};\n\n/**\n * Translation key the {@link useDescribeApiError} hook looks up.\n *\n * A catalog that does not define it falls back to\n * {@link DEFAULT_API_ERROR_STRINGS}, because `t` returns the key itself when the\n * lookup misses and printing `tempest.error.offline` at the user would be worse\n * than printing pt-BR at them.\n */\nexport const API_ERROR_OFFLINE_KEY = \"tempest.error.offline\";\n\n/**\n * Translation key for the validation sentence, looked up the same way as\n * {@link API_ERROR_OFFLINE_KEY}.\n */\nexport const API_ERROR_VALIDATION_KEY = \"tempest.error.validation\";\n\n/**\n * Everything {@link describeApiError} accepts beyond the error and the fallback.\n *\n * Extends the fixed sentences rather than sitting beside them, so a caller that\n * already passed `{ offline, validation }` keeps compiling untouched.\n */\nexport interface DescribeApiErrorOptions extends Partial<ApiErrorStrings> {\n /**\n * Maps the backend's programmatic `code` to a sentence in your language.\n *\n * The client already surfaces `code` on `ApiError`, but without this every\n * app writes the same `switch` over it. A hit here wins over every other\n * step: it is the only sentence written for that exact case, by someone who\n * knew both the backend contract and the screen it lands on.\n */\n codes?: Readonly<Record<string, string>>;\n /**\n * Maps an HTTP status to a sentence, for the failures that arrive with no\n * useful body.\n *\n * `codes` covers the cases the backend named; this covers the ones it did\n * not. The reference case is the `403` of an admin-only route: the body\n * carries a generic `detail` (or none), so the funnel fell through to the\n * fallback and an administrator read \"Não foi possível carregar\" when the\n * fact that answers their question is \"esta listagem é só para\n * administradores\".\n *\n * Checked after `codes` and **before** the backend's `detail`: a generic\n * sentence emitted by the framework is worse than the one the app wrote for\n * that status. `useDetail: false` remains the way to suppress `detail`\n * entirely.\n *\n * A `0` key is honoured like any other, ahead of the offline sentence —\n * `statuses` is the caller's explicit map, and the fixed `offline` string is\n * already the way to reword that case. Status `0` covers a request that\n * never landed **and** one abandoned by the client timeout, so an app that\n * maps it is taking both.\n */\n statuses?: Readonly<Record<number, string>>;\n /**\n * Whether the backend's `detail` may be shown when no `code` matched.\n * Default `true`.\n *\n * Set it to `false` when `detail` is written for developers rather than\n * users, or when it could echo internals — the result is then always either\n * a sentence you wrote or the fallback.\n */\n useDetail?: boolean;\n}\n\n/**\n * Whether the browser currently reports itself as offline.\n *\n * `fetch` rejects a network failure with a plain `TypeError` whose message\n * differs per browser (\"Failed to fetch\", \"NetworkError when attempting to fetch\n * resource.\", \"Load failed\"), so sniffing the message is not portable. The online\n * flag is, and it is the signal that matters for the sentence being chosen.\n *\n * @returns `true` only when the environment positively says it is offline.\n */\nfunction browserIsOffline(): boolean {\n return typeof navigator !== \"undefined\" && navigator.onLine === false;\n}\n\n/**\n * Whether `fields` is the flattened single-field envelope, carrying `detail`.\n *\n * The check is identity rather than shape-sniffing. `collectFields` has exactly\n * two sources: FastAPI's `detail` **list**, whose entries are the per-issue\n * messages, and the flattened envelope, whose one entry is built from the same\n * string that becomes `ApiError.detail`. So one entry equal to `detail` can only\n * have come from the second, and returning `detail` there shows the string the\n * form is already about to attach to that input.\n *\n * @param fields - The error's field messages.\n * @param detail - `error.detail`, already trimmed.\n * @param status - The HTTP status, to recognise the synthetic `Erro <status>`\n * that stands in when the body carried no message at all.\n * @returns Whether `detail` is safe to show as the sentence.\n */\nfunction singleFieldSentence(\n fields: Record<string, string>,\n detail: string,\n status: number,\n): boolean {\n if (detail === \"\" || detail === syntheticDetail(status)) return false;\n const messages = Object.values(fields);\n return messages.length === 1 && messages[0].trim() === detail;\n}\n\n/**\n * Turn any caught value into a sentence worth showing.\n *\n * The funnel, in order:\n *\n * 0. `codes[error.code]` — the sentence you wrote for that exact backend case.\n * Checked first because nothing the funnel derives can beat it, and because a\n * request that never landed carries no `code` for it to shadow.\n * 0.5. `statuses[error.status]` — the sentence for a whole class of failure,\n * for the errors that arrive with no useful body. It beats the backend's\n * `detail`, because a generic line emitted by the framework is worse than the\n * one the app wrote for that status, and it beats the offline sentence when\n * the caller maps `0` explicitly.\n * 1. A request that never reached the server — `status === 0`, or a non-API\n * error thrown while the browser reports itself offline — produces the\n * offline sentence. This is the step apps skip, and skipping it renders\n * \"erro 0\" or a raw `TypeError` at the user.\n * 2. A validation rejection — `error.fields` is set — produces the validation\n * sentence, **not** `detail`. On a FastAPI `422` the `detail` line is assembled\n * from the backend's field paths and the validator's own wording\n * (`\"items.0.price: Input should be greater than 0\"`), which is right for a\n * log and wrong for a person: it is half English in a pt-BR screen and it\n * names internals. The per-field messages stay on `fields`, where a form can\n * attach them to the inputs that failed.\n *\n * **Unless the rejection named exactly one field and its message is\n * `detail` itself**, in which case `detail` is returned. That is not a guess\n * about the text: `collectFields` fills a single entry from `detail` only for\n * the flattened envelope a `tempest-fastapi-sdk` backend sends, where the\n * server wrote one finished sentence about one field (`\"CPF ou CNPJ\n * inválido\"`). Returning it shows the same string that is already on\n * `fields`, so nothing is invented and nothing is lost. The assembled FastAPI\n * line never reaches this branch, because it comes from the `detail` **list**\n * and its entries are the per-issue messages, not `detail`.\n *\n * This is a fix, not a preference. Before `namedField` shipped in 0.54.0,\n * `fields` was empty against that backend and the sentence reached the user\n * through step 3; filling `fields` silently replaced it with \"Confira os\n * campos destacados\", which presumes a screen that highlights fields — and\n * no app highlighted anything on the day of the bump.\n *\n * `useDetail: false` still suppresses it, and is the way to force the fixed\n * sentence for a backend whose text is written for developers. `validation`\n * does **not** override it, and that is on purpose: its own contract is the\n * sentence for a payload rejected *field by field*, which one field carrying\n * one finished sentence is not — and `useDescribeApiError` always passes\n * `validation`, so treating it as an override would mean the branch never ran\n * for any component, which is every caller that matters here.\n * 3. The backend's own `detail`, which is the most specific thing available and\n * is already written for a person — unless `useDetail: false` says that text\n * is for developers.\n * 4. `fallback`, with `(HTTP <status>)` appended when a status is known, so the\n * screenshot in the support ticket carries the one fact a developer needs.\n *\n * Pure on purpose: it works in an interceptor, in a logger and anywhere outside\n * the React tree. {@link useDescribeApiError} is the same funnel with the\n * sentences resolved through `I18nProvider`.\n *\n * @example\n * catch (error) {\n * toast(describeApiError(error, \"Não foi possível salvar o pedido\"));\n * }\n *\n * @example\n * catch (error) {\n * toast(\n * describeApiError(error, \"Não foi possível se candidatar\", {\n * codes: {\n * SERVICE_FULL: \"Este serviço atingiu o limite de vagas.\",\n * CANDIDATE_ALREADY_EXISTS: \"Você já se candidatou a este serviço.\",\n * },\n * useDetail: false,\n * }),\n * );\n * }\n *\n * @param error - The caught value, of any shape.\n * @param fallback - What to say when the error carries nothing better.\n * @param options - A `codes` catalog, `useDetail`, and overrides for the fixed\n * sentences.\n * @returns A sentence to show the user.\n */\nexport function describeApiError(\n error: unknown,\n fallback: string,\n options?: DescribeApiErrorOptions,\n): string {\n const offline = options?.offline ?? DEFAULT_API_ERROR_STRINGS.offline;\n\n if (isApiError(error)) {\n const mapped = error.code === undefined ? undefined : options?.codes?.[error.code];\n if (mapped !== undefined) return mapped;\n const byStatus = options?.statuses?.[error.status];\n if (byStatus !== undefined) return byStatus;\n if (error.status === 0) return offline;\n const detail = error.detail.trim();\n if (error.fields && Object.keys(error.fields).length > 0) {\n if (\n options?.useDetail !== false &&\n singleFieldSentence(error.fields, detail, error.status)\n ) {\n return detail;\n }\n return options?.validation ?? DEFAULT_API_ERROR_STRINGS.validation;\n }\n if (\n options?.useDetail !== false &&\n detail !== \"\" &&\n detail !== syntheticDetail(error.status)\n ) {\n return detail;\n }\n return `${fallback} (HTTP ${error.status})`;\n }\n\n if (browserIsOffline()) return offline;\n\n return fallback;\n}\n"],"mappings":"A,gCAgCA,IAAaG,EAA6C,CACtD,QAAS,sEACT,WAAY,+CAChB,EAUaC,EAAwB,wBAMxBC,EAA2B,2BA8DxC,SAASC,GAA4B,CACjC,OAAO,OAAO,UAAc,KAAe,UAAU,SAAW,EACpE,CAkBA,SAASC,EACL,EACA,EACA,EACO,CACP,GAAIC,IAAW,IAAMA,IAAWR,EAAAA,gBAAgBS,CAAM,EAAG,MAAO,GAChE,IAAMC,EAAW,OAAO,OAAOC,CAAM,EACrC,OAAOD,EAAS,SAAW,GAAKA,EAAS,EAAE,CAAC,KAAK,IAAMF,CAC3D,CAoFA,SAAgBI,EACZ,EACA,EACA,EACM,CACN,IAAMC,EAAUC,GAAS,SAAWX,EAA0B,QAE9D,GAAIF,EAAAA,WAAWc,CAAK,EAAG,CACnB,IAAMC,EAASD,EAAM,OAAS,IAAA,GAAY,IAAA,GAAYD,GAAS,QAAQC,EAAM,MAC7E,GAAIC,IAAW,IAAA,GAAW,OAAOA,EACjC,IAAMC,EAAWH,GAAS,WAAWC,EAAM,QAC3C,GAAIE,IAAa,IAAA,GAAW,OAAOA,EACnC,GAAIF,EAAM,SAAW,EAAG,OAAOF,EAC/B,IAAML,EAASO,EAAM,OAAO,KAAK,EAiBjC,OAhBIA,EAAM,QAAU,OAAO,KAAKA,EAAM,MAAM,CAAC,CAAC,OAAS,EAE/CD,GAAS,YAAc,IACvBP,EAAoBQ,EAAM,OAAQP,EAAQO,EAAM,MAAM,EAE/CP,EAEJM,GAAS,YAAcX,EAA0B,WAGxDW,GAAS,YAAc,IACvBN,IAAW,IACXA,IAAWR,EAAAA,gBAAgBe,EAAM,MAAM,EAEhCP,EAEJ,GAAGU,EAAS,SAASH,EAAM,OAAO,EAC7C,CAIA,OAFIT,EAAiB,EAAUO,EAExBK,CACX,C"}
@@ -1 +1 @@
1
- {"version":3,"file":"describe-api-error.js","names":[],"sources":["../../src/http/describe-api-error.ts"],"sourcesContent":["// The last mile of error handling: a typed error is what code reads, a sentence\n// is what a person reads, and every app was writing the funnel between the two.\n// The case everyone forgets is the request that never reached the server, which\n// without special handling renders as the nonsense \"erro 0\".\n\nimport { isApiError, syntheticDetail } from \"./errors\";\n\n/** The fixed sentences {@link describeApiError} may need. */\nexport interface ApiErrorStrings {\n /** Shown when the request never reached the server. */\n offline: string;\n /**\n * Shown when the backend rejected the payload field by field.\n *\n * The per-field messages are on `error.fields`, to be attached to the inputs\n * themselves; this sentence is what the toast says.\n *\n * It does not apply to the one rejection that named a single field with a\n * finished sentence — there the server's own `detail` is shown instead, since\n * it is the same string `fields` carries. Pass `useDetail: false` to force\n * this sentence in that case too.\n */\n validation: string;\n}\n\n/**\n * PT-BR defaults, used when no strings are supplied and no catalog answers.\n *\n * The SDK's copy is pt-BR everywhere else (`FilterBar`, `DataTable`, `Chat`), so\n * the default here matches rather than introducing an English string that only\n * shows up on a network failure.\n */\nexport const DEFAULT_API_ERROR_STRINGS: ApiErrorStrings = {\n offline: \"Sem conexão com o servidor. Verifique sua internet e tente de novo.\",\n validation: \"Confira os campos destacados e tente de novo.\",\n};\n\n/**\n * Translation key the {@link useDescribeApiError} hook looks up.\n *\n * A catalog that does not define it falls back to\n * {@link DEFAULT_API_ERROR_STRINGS}, because `t` returns the key itself when the\n * lookup misses and printing `tempest.error.offline` at the user would be worse\n * than printing pt-BR at them.\n */\nexport const API_ERROR_OFFLINE_KEY = \"tempest.error.offline\";\n\n/**\n * Translation key for the validation sentence, looked up the same way as\n * {@link API_ERROR_OFFLINE_KEY}.\n */\nexport const API_ERROR_VALIDATION_KEY = \"tempest.error.validation\";\n\n/**\n * Everything {@link describeApiError} accepts beyond the error and the fallback.\n *\n * Extends the fixed sentences rather than sitting beside them, so a caller that\n * already passed `{ offline, validation }` keeps compiling untouched.\n */\nexport interface DescribeApiErrorOptions extends Partial<ApiErrorStrings> {\n /**\n * Maps the backend's programmatic `code` to a sentence in your language.\n *\n * The client already surfaces `code` on `ApiError`, but without this every\n * app writes the same `switch` over it. A hit here wins over every other\n * step: it is the only sentence written for that exact case, by someone who\n * knew both the backend contract and the screen it lands on.\n */\n codes?: Readonly<Record<string, string>>;\n /**\n * Maps an HTTP status to a sentence, for the failures that arrive with no\n * useful body.\n *\n * `codes` covers the cases the backend named; this covers the ones it did\n * not. The reference case is the `403` of an admin-only route: the body\n * carries a generic `detail` (or none), so the funnel fell through to the\n * fallback and an administrator read \"Não foi possível carregar\" when the\n * fact that answers their question is \"esta listagem é só para\n * administradores\".\n *\n * Checked after `codes` and **before** the backend's `detail`: a generic\n * sentence emitted by the framework is worse than the one the app wrote for\n * that status. `useDetail: false` remains the way to suppress `detail`\n * entirely.\n *\n * A `0` key is honoured like any other, ahead of the offline sentence —\n * `statuses` is the caller's explicit map, and the fixed `offline` string is\n * already the way to reword that case. Status `0` covers a request that\n * never landed **and** one abandoned by the client timeout, so an app that\n * maps it is taking both.\n */\n statuses?: Readonly<Record<number, string>>;\n /**\n * Whether the backend's `detail` may be shown when no `code` matched.\n * Default `true`.\n *\n * Set it to `false` when `detail` is written for developers rather than\n * users, or when it could echo internals — the result is then always either\n * a sentence you wrote or the fallback.\n */\n useDetail?: boolean;\n}\n\n/**\n * Whether the browser currently reports itself as offline.\n *\n * `fetch` rejects a network failure with a plain `TypeError` whose message\n * differs per browser (\"Failed to fetch\", \"NetworkError when attempting to fetch\n * resource.\", \"Load failed\"), so sniffing the message is not portable. The online\n * flag is, and it is the signal that matters for the sentence being chosen.\n *\n * @returns `true` only when the environment positively says it is offline.\n */\nfunction browserIsOffline(): boolean {\n return typeof navigator !== \"undefined\" && navigator.onLine === false;\n}\n\n/**\n * Whether `fields` is the flattened single-field envelope, carrying `detail`.\n *\n * The check is identity rather than shape-sniffing. `collectFields` has exactly\n * two sources: FastAPI's `detail` **list**, whose entries are the per-issue\n * messages, and the flattened envelope, whose one entry is built from the same\n * string that becomes `ApiError.detail`. So one entry equal to `detail` can only\n * have come from the second, and returning `detail` there shows the string the\n * form is already about to attach to that input.\n *\n * @param fields - The error's field messages.\n * @param detail - `error.detail`, already trimmed.\n * @param status - The HTTP status, to recognise the synthetic `Erro <status>`\n * that stands in when the body carried no message at all.\n * @returns Whether `detail` is safe to show as the sentence.\n */\nfunction singleFieldSentence(\n fields: Record<string, string>,\n detail: string,\n status: number,\n): boolean {\n if (detail === \"\" || detail === syntheticDetail(status)) return false;\n const messages = Object.values(fields);\n return messages.length === 1 && messages[0].trim() === detail;\n}\n\n/**\n * Turn any caught value into a sentence worth showing.\n *\n * The funnel, in order:\n *\n * 0. `codes[error.code]` — the sentence you wrote for that exact backend case.\n * Checked first because nothing the funnel derives can beat it, and because a\n * request that never landed carries no `code` for it to shadow.\n * 0.5. `statuses[error.status]` — the sentence for a whole class of failure,\n * for the errors that arrive with no useful body. It beats the backend's\n * `detail`, because a generic line emitted by the framework is worse than the\n * one the app wrote for that status, and it beats the offline sentence when\n * the caller maps `0` explicitly.\n * 1. A request that never reached the server — `status === 0`, or a non-API\n * error thrown while the browser reports itself offline — produces the\n * offline sentence. This is the step apps skip, and skipping it renders\n * \"erro 0\" or a raw `TypeError` at the user.\n * 2. A validation rejection — `error.fields` is set — produces the validation\n * sentence, **not** `detail`. On a FastAPI `422` the `detail` line is assembled\n * from the backend's field paths and the validator's own wording\n * (`\"items.0.price: Input should be greater than 0\"`), which is right for a\n * log and wrong for a person: it is half English in a pt-BR screen and it\n * names internals. The per-field messages stay on `fields`, where a form can\n * attach them to the inputs that failed.\n *\n * **Unless the rejection named exactly one field and its message is\n * `detail` itself**, in which case `detail` is returned. That is not a guess\n * about the text: `collectFields` fills a single entry from `detail` only for\n * the flattened envelope a `tempest-fastapi-sdk` backend sends, where the\n * server wrote one finished sentence about one field (`\"CPF ou CNPJ\n * inválido\"`). Returning it shows the same string that is already on\n * `fields`, so nothing is invented and nothing is lost. The assembled FastAPI\n * line never reaches this branch, because it comes from the `detail` **list**\n * and its entries are the per-issue messages, not `detail`.\n *\n * This is a fix, not a preference. Before `namedField` shipped in 0.54.0,\n * `fields` was empty against that backend and the sentence reached the user\n * through step 3; filling `fields` silently replaced it with \"Confira os\n * campos destacados\", which presumes a screen that highlights fields — and\n * no app highlighted anything on the day of the bump.\n *\n * `useDetail: false` still suppresses it, and is the way to force the fixed\n * sentence for a backend whose text is written for developers. `validation`\n * does **not** override it, and that is on purpose: its own contract is the\n * sentence for a payload rejected *field by field*, which one field carrying\n * one finished sentence is not — and `useDescribeApiError` always passes\n * `validation`, so treating it as an override would mean the branch never ran\n * for any component, which is every caller that matters here.\n * 3. The backend's own `detail`, which is the most specific thing available and\n * is already written for a person — unless `useDetail: false` says that text\n * is for developers.\n * 4. `fallback`, with `(HTTP <status>)` appended when a status is known, so the\n * screenshot in the support ticket carries the one fact a developer needs.\n *\n * Pure on purpose: it works in an interceptor, in a logger and anywhere outside\n * the React tree. {@link useDescribeApiError} is the same funnel with the\n * sentences resolved through `I18nProvider`.\n *\n * @example\n * catch (error) {\n * toast(describeApiError(error, \"Não foi possível salvar o pedido\"));\n * }\n *\n * @example\n * catch (error) {\n * toast(\n * describeApiError(error, \"Não foi possível se candidatar\", {\n * codes: {\n * SERVICE_FULL: \"Este serviço atingiu o limite de vagas.\",\n * CANDIDATE_ALREADY_EXISTS: \"Você já se candidatou a este serviço.\",\n * },\n * useDetail: false,\n * }),\n * );\n * }\n *\n * @param error - The caught value, of any shape.\n * @param fallback - What to say when the error carries nothing better.\n * @param options - A `codes` catalog, `useDetail`, and overrides for the fixed\n * sentences.\n * @returns A sentence to show the user.\n */\nexport function describeApiError(\n error: unknown,\n fallback: string,\n options?: DescribeApiErrorOptions,\n): string {\n const offline = options?.offline ?? DEFAULT_API_ERROR_STRINGS.offline;\n\n if (isApiError(error)) {\n const mapped = error.code === undefined ? undefined : options?.codes?.[error.code];\n if (mapped !== undefined) return mapped;\n const byStatus = options?.statuses?.[error.status];\n if (byStatus !== undefined) return byStatus;\n if (error.status === 0) return offline;\n const detail = error.detail.trim();\n if (error.fields && Object.keys(error.fields).length > 0) {\n if (\n options?.useDetail !== false &&\n singleFieldSentence(error.fields, detail, error.status)\n ) {\n return detail;\n }\n return options?.validation ?? DEFAULT_API_ERROR_STRINGS.validation;\n }\n if (\n options?.useDetail !== false &&\n detail !== \"\" &&\n detail !== syntheticDetail(error.status)\n ) {\n return detail;\n }\n return `${fallback} (HTTP ${error.status})`;\n }\n\n if (browserIsOffline()) return offline;\n\n return fallback;\n}\n"],"mappings":";;AAgCA,IAAa,IAA6C;CACtD,SAAS;CACT,YAAY;AAChB,GAUa,IAAwB,yBAMxB,IAA2B;AA8DxC,SAAS,IAA4B;CACjC,OAAO,OAAO,YAAc,OAAe,UAAU,WAAW;AACpE;AAkBA,SAAS,EACL,GACA,GACA,GACO;CACP,IAAI,MAAW,MAAM,MAAW,EAAgB,CAAM,GAAG,OAAO;CAChE,IAAM,IAAW,OAAO,OAAO,CAAM;CACrC,OAAO,EAAS,WAAW,KAAK,EAAS,EAAE,CAAC,KAAK,MAAM;AAC3D;AAoFA,SAAgB,EACZ,GACA,GACA,GACM;CACN,IAAM,IAAU,GAAS,WAAW,EAA0B;CAE9D,IAAI,EAAW,CAAK,GAAG;EACnB,IAAM,IAAS,EAAM,SAAS,KAAA,IAAY,KAAA,IAAY,GAAS,QAAQ,EAAM;EAC7E,IAAI,MAAW,KAAA,GAAW,OAAO;EACjC,IAAM,IAAW,GAAS,WAAW,EAAM;EAC3C,IAAI,MAAa,KAAA,GAAW,OAAO;EACnC,IAAI,EAAM,WAAW,GAAG,OAAO;EAC/B,IAAM,IAAS,EAAM,OAAO,KAAK;EAiBjC,OAhBI,EAAM,UAAU,OAAO,KAAK,EAAM,MAAM,CAAC,CAAC,SAAS,IAE/C,GAAS,cAAc,MACvB,EAAoB,EAAM,QAAQ,GAAQ,EAAM,MAAM,IAE/C,IAEJ,GAAS,cAAc,EAA0B,aAGxD,GAAS,cAAc,MACvB,MAAW,MACX,MAAW,EAAgB,EAAM,MAAM,IAEhC,IAEJ,GAAG,EAAS,SAAS,EAAM,OAAO;CAC7C;CAIA,OAFI,EAAiB,IAAU,IAExB;AACX"}
1
+ {"version":3,"file":"describe-api-error.js","names":["DEFAULT_API_ERROR_STRINGS","API_ERROR_OFFLINE_KEY","API_ERROR_VALIDATION_KEY","browserIsOffline","singleFieldSentence","detail","syntheticDetail","status","messages","fields","describeApiError","offline","options","isApiError","error","mapped","byStatus","fallback"],"sources":["../../src/http/describe-api-error.ts"],"sourcesContent":["// The last mile of error handling: a typed error is what code reads, a sentence\n// is what a person reads, and every app was writing the funnel between the two.\n// The case everyone forgets is the request that never reached the server, which\n// without special handling renders as the nonsense \"erro 0\".\n\nimport { isApiError, syntheticDetail } from \"./errors\";\n\n/** The fixed sentences {@link describeApiError} may need. */\nexport interface ApiErrorStrings {\n /** Shown when the request never reached the server. */\n offline: string;\n /**\n * Shown when the backend rejected the payload field by field.\n *\n * The per-field messages are on `error.fields`, to be attached to the inputs\n * themselves; this sentence is what the toast says.\n *\n * It does not apply to the one rejection that named a single field with a\n * finished sentence — there the server's own `detail` is shown instead, since\n * it is the same string `fields` carries. Pass `useDetail: false` to force\n * this sentence in that case too.\n */\n validation: string;\n}\n\n/**\n * PT-BR defaults, used when no strings are supplied and no catalog answers.\n *\n * The SDK's copy is pt-BR everywhere else (`FilterBar`, `DataTable`, `Chat`), so\n * the default here matches rather than introducing an English string that only\n * shows up on a network failure.\n */\nexport const DEFAULT_API_ERROR_STRINGS: ApiErrorStrings = {\n offline: \"Sem conexão com o servidor. Verifique sua internet e tente de novo.\",\n validation: \"Confira os campos destacados e tente de novo.\",\n};\n\n/**\n * Translation key the {@link useDescribeApiError} hook looks up.\n *\n * A catalog that does not define it falls back to\n * {@link DEFAULT_API_ERROR_STRINGS}, because `t` returns the key itself when the\n * lookup misses and printing `tempest.error.offline` at the user would be worse\n * than printing pt-BR at them.\n */\nexport const API_ERROR_OFFLINE_KEY = \"tempest.error.offline\";\n\n/**\n * Translation key for the validation sentence, looked up the same way as\n * {@link API_ERROR_OFFLINE_KEY}.\n */\nexport const API_ERROR_VALIDATION_KEY = \"tempest.error.validation\";\n\n/**\n * Everything {@link describeApiError} accepts beyond the error and the fallback.\n *\n * Extends the fixed sentences rather than sitting beside them, so a caller that\n * already passed `{ offline, validation }` keeps compiling untouched.\n */\nexport interface DescribeApiErrorOptions extends Partial<ApiErrorStrings> {\n /**\n * Maps the backend's programmatic `code` to a sentence in your language.\n *\n * The client already surfaces `code` on `ApiError`, but without this every\n * app writes the same `switch` over it. A hit here wins over every other\n * step: it is the only sentence written for that exact case, by someone who\n * knew both the backend contract and the screen it lands on.\n */\n codes?: Readonly<Record<string, string>>;\n /**\n * Maps an HTTP status to a sentence, for the failures that arrive with no\n * useful body.\n *\n * `codes` covers the cases the backend named; this covers the ones it did\n * not. The reference case is the `403` of an admin-only route: the body\n * carries a generic `detail` (or none), so the funnel fell through to the\n * fallback and an administrator read \"Não foi possível carregar\" when the\n * fact that answers their question is \"esta listagem é só para\n * administradores\".\n *\n * Checked after `codes` and **before** the backend's `detail`: a generic\n * sentence emitted by the framework is worse than the one the app wrote for\n * that status. `useDetail: false` remains the way to suppress `detail`\n * entirely.\n *\n * A `0` key is honoured like any other, ahead of the offline sentence —\n * `statuses` is the caller's explicit map, and the fixed `offline` string is\n * already the way to reword that case. Status `0` covers a request that\n * never landed **and** one abandoned by the client timeout, so an app that\n * maps it is taking both.\n */\n statuses?: Readonly<Record<number, string>>;\n /**\n * Whether the backend's `detail` may be shown when no `code` matched.\n * Default `true`.\n *\n * Set it to `false` when `detail` is written for developers rather than\n * users, or when it could echo internals — the result is then always either\n * a sentence you wrote or the fallback.\n */\n useDetail?: boolean;\n}\n\n/**\n * Whether the browser currently reports itself as offline.\n *\n * `fetch` rejects a network failure with a plain `TypeError` whose message\n * differs per browser (\"Failed to fetch\", \"NetworkError when attempting to fetch\n * resource.\", \"Load failed\"), so sniffing the message is not portable. The online\n * flag is, and it is the signal that matters for the sentence being chosen.\n *\n * @returns `true` only when the environment positively says it is offline.\n */\nfunction browserIsOffline(): boolean {\n return typeof navigator !== \"undefined\" && navigator.onLine === false;\n}\n\n/**\n * Whether `fields` is the flattened single-field envelope, carrying `detail`.\n *\n * The check is identity rather than shape-sniffing. `collectFields` has exactly\n * two sources: FastAPI's `detail` **list**, whose entries are the per-issue\n * messages, and the flattened envelope, whose one entry is built from the same\n * string that becomes `ApiError.detail`. So one entry equal to `detail` can only\n * have come from the second, and returning `detail` there shows the string the\n * form is already about to attach to that input.\n *\n * @param fields - The error's field messages.\n * @param detail - `error.detail`, already trimmed.\n * @param status - The HTTP status, to recognise the synthetic `Erro <status>`\n * that stands in when the body carried no message at all.\n * @returns Whether `detail` is safe to show as the sentence.\n */\nfunction singleFieldSentence(\n fields: Record<string, string>,\n detail: string,\n status: number,\n): boolean {\n if (detail === \"\" || detail === syntheticDetail(status)) return false;\n const messages = Object.values(fields);\n return messages.length === 1 && messages[0].trim() === detail;\n}\n\n/**\n * Turn any caught value into a sentence worth showing.\n *\n * The funnel, in order:\n *\n * 0. `codes[error.code]` — the sentence you wrote for that exact backend case.\n * Checked first because nothing the funnel derives can beat it, and because a\n * request that never landed carries no `code` for it to shadow.\n * 0.5. `statuses[error.status]` — the sentence for a whole class of failure,\n * for the errors that arrive with no useful body. It beats the backend's\n * `detail`, because a generic line emitted by the framework is worse than the\n * one the app wrote for that status, and it beats the offline sentence when\n * the caller maps `0` explicitly.\n * 1. A request that never reached the server — `status === 0`, or a non-API\n * error thrown while the browser reports itself offline — produces the\n * offline sentence. This is the step apps skip, and skipping it renders\n * \"erro 0\" or a raw `TypeError` at the user.\n * 2. A validation rejection — `error.fields` is set — produces the validation\n * sentence, **not** `detail`. On a FastAPI `422` the `detail` line is assembled\n * from the backend's field paths and the validator's own wording\n * (`\"items.0.price: Input should be greater than 0\"`), which is right for a\n * log and wrong for a person: it is half English in a pt-BR screen and it\n * names internals. The per-field messages stay on `fields`, where a form can\n * attach them to the inputs that failed.\n *\n * **Unless the rejection named exactly one field and its message is\n * `detail` itself**, in which case `detail` is returned. That is not a guess\n * about the text: `collectFields` fills a single entry from `detail` only for\n * the flattened envelope a `tempest-fastapi-sdk` backend sends, where the\n * server wrote one finished sentence about one field (`\"CPF ou CNPJ\n * inválido\"`). Returning it shows the same string that is already on\n * `fields`, so nothing is invented and nothing is lost. The assembled FastAPI\n * line never reaches this branch, because it comes from the `detail` **list**\n * and its entries are the per-issue messages, not `detail`.\n *\n * This is a fix, not a preference. Before `namedField` shipped in 0.54.0,\n * `fields` was empty against that backend and the sentence reached the user\n * through step 3; filling `fields` silently replaced it with \"Confira os\n * campos destacados\", which presumes a screen that highlights fields — and\n * no app highlighted anything on the day of the bump.\n *\n * `useDetail: false` still suppresses it, and is the way to force the fixed\n * sentence for a backend whose text is written for developers. `validation`\n * does **not** override it, and that is on purpose: its own contract is the\n * sentence for a payload rejected *field by field*, which one field carrying\n * one finished sentence is not — and `useDescribeApiError` always passes\n * `validation`, so treating it as an override would mean the branch never ran\n * for any component, which is every caller that matters here.\n * 3. The backend's own `detail`, which is the most specific thing available and\n * is already written for a person — unless `useDetail: false` says that text\n * is for developers.\n * 4. `fallback`, with `(HTTP <status>)` appended when a status is known, so the\n * screenshot in the support ticket carries the one fact a developer needs.\n *\n * Pure on purpose: it works in an interceptor, in a logger and anywhere outside\n * the React tree. {@link useDescribeApiError} is the same funnel with the\n * sentences resolved through `I18nProvider`.\n *\n * @example\n * catch (error) {\n * toast(describeApiError(error, \"Não foi possível salvar o pedido\"));\n * }\n *\n * @example\n * catch (error) {\n * toast(\n * describeApiError(error, \"Não foi possível se candidatar\", {\n * codes: {\n * SERVICE_FULL: \"Este serviço atingiu o limite de vagas.\",\n * CANDIDATE_ALREADY_EXISTS: \"Você já se candidatou a este serviço.\",\n * },\n * useDetail: false,\n * }),\n * );\n * }\n *\n * @param error - The caught value, of any shape.\n * @param fallback - What to say when the error carries nothing better.\n * @param options - A `codes` catalog, `useDetail`, and overrides for the fixed\n * sentences.\n * @returns A sentence to show the user.\n */\nexport function describeApiError(\n error: unknown,\n fallback: string,\n options?: DescribeApiErrorOptions,\n): string {\n const offline = options?.offline ?? DEFAULT_API_ERROR_STRINGS.offline;\n\n if (isApiError(error)) {\n const mapped = error.code === undefined ? undefined : options?.codes?.[error.code];\n if (mapped !== undefined) return mapped;\n const byStatus = options?.statuses?.[error.status];\n if (byStatus !== undefined) return byStatus;\n if (error.status === 0) return offline;\n const detail = error.detail.trim();\n if (error.fields && Object.keys(error.fields).length > 0) {\n if (\n options?.useDetail !== false &&\n singleFieldSentence(error.fields, detail, error.status)\n ) {\n return detail;\n }\n return options?.validation ?? DEFAULT_API_ERROR_STRINGS.validation;\n }\n if (\n options?.useDetail !== false &&\n detail !== \"\" &&\n detail !== syntheticDetail(error.status)\n ) {\n return detail;\n }\n return `${fallback} (HTTP ${error.status})`;\n }\n\n if (browserIsOffline()) return offline;\n\n return fallback;\n}\n"],"mappings":";;AAgCA,IAAaA,IAA6C;CACtD,SAAS;CACT,YAAY;AAChB,GAUaC,IAAwB,yBAMxBC,IAA2B;AA8DxC,SAASC,IAA4B;CACjC,OAAO,OAAO,YAAc,OAAe,UAAU,WAAW;AACpE;AAkBA,SAASC,EACL,GACA,GACA,GACO;CACP,IAAIC,MAAW,MAAMA,MAAWC,EAAgBC,CAAM,GAAG,OAAO;CAChE,IAAMC,IAAW,OAAO,OAAOC,CAAM;CACrC,OAAOD,EAAS,WAAW,KAAKA,EAAS,EAAE,CAAC,KAAK,MAAMH;AAC3D;AAoFA,SAAgBK,EACZ,GACA,GACA,GACM;CACN,IAAMC,IAAUC,GAAS,WAAWZ,EAA0B;CAE9D,IAAIa,EAAWC,CAAK,GAAG;EACnB,IAAMC,IAASD,EAAM,SAAS,KAAA,IAAY,KAAA,IAAYF,GAAS,QAAQE,EAAM;EAC7E,IAAIC,MAAW,KAAA,GAAW,OAAOA;EACjC,IAAMC,IAAWJ,GAAS,WAAWE,EAAM;EAC3C,IAAIE,MAAa,KAAA,GAAW,OAAOA;EACnC,IAAIF,EAAM,WAAW,GAAG,OAAOH;EAC/B,IAAMN,IAASS,EAAM,OAAO,KAAK;EAiBjC,OAhBIA,EAAM,UAAU,OAAO,KAAKA,EAAM,MAAM,CAAC,CAAC,SAAS,IAE/CF,GAAS,cAAc,MACvBR,EAAoBU,EAAM,QAAQT,GAAQS,EAAM,MAAM,IAE/CT,IAEJO,GAAS,cAAcZ,EAA0B,aAGxDY,GAAS,cAAc,MACvBP,MAAW,MACXA,MAAWC,EAAgBQ,EAAM,MAAM,IAEhCT,IAEJ,GAAGY,EAAS,SAASH,EAAM,OAAO;CAC7C;CAIA,OAFIX,EAAiB,IAAUQ,IAExBM;AACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.cjs","names":[],"sources":["../../src/http/errors.ts"],"sourcesContent":["import type { ApiError } from \"./types\";\n\n/**\n * Error thrown by {@link createApiClient} / {@link uploadWithProgress} on a\n * non-2xx response. Mirrors the Tempest FastAPI SDK error envelope\n * (`{ detail, code, details.request_id }`) so callers get a typed `code` and a\n * `requestId` for log correlation, while still being a real `Error` (stack\n * trace, `instanceof Error`).\n *\n * @example\n * try {\n * await api.post(\"/users\", { body });\n * } catch (err) {\n * if (isApiError(err) && err.code === \"EMAIL_TAKEN\") {\n * showFieldError(\"email\", err.detail);\n * }\n * }\n */\nexport class TempestApiError extends Error implements ApiError {\n readonly status: number;\n readonly detail: string;\n readonly code?: string;\n readonly requestId?: string;\n readonly fields?: Record<string, string>;\n readonly body?: unknown;\n\n constructor(init: ApiError) {\n super(init.detail);\n this.name = \"TempestApiError\";\n this.status = init.status;\n this.detail = init.detail;\n this.code = init.code;\n this.requestId = init.requestId;\n this.fields = init.fields;\n this.body = init.body;\n }\n}\n\n/**\n * Thrown when the session that started an operation is no longer the current\n * one by the time it settles: a `refresh` hook (rethrown by\n * {@link createApiClient}), or a `createTempestAuth` `login()` whose session\n * was replaced while it waited on the previous session's teardown.\n *\n * A refresh is a network round trip, and the session can end or change hands\n * during it: the user signs out, or signs out and another account signs in. The\n * tokens that refresh brings back belong to the session that ended, so they are\n * discarded instead of installed, and the request that was waiting on them is\n * not replayed — replaying it would send it as whoever is signed in now.\n *\n * This is deliberately not an unauthorized outcome. The client does **not** call\n * `onUnauthorized` for it: that callback ends the session, and the current\n * session — possibly a different account that just signed in — did nothing\n * wrong. Treat it like an aborted request: drop the result, show nothing.\n *\n * @example\n * try {\n * await api.get(\"/api/orders\");\n * } catch (err) {\n * if (err instanceof SessionSupersededError) return;\n * throw err;\n * }\n */\nexport class SessionSupersededError extends Error {\n constructor() {\n super(\"A sessão mudou antes de a operação terminar.\");\n this.name = \"SessionSupersededError\";\n }\n}\n\n/**\n * Type guard for the {@link ApiError} shape. Matches both {@link TempestApiError}\n * instances and plain objects carrying `status` + `detail`.\n *\n * @param error - The unknown value (typically a caught error).\n * @returns Whether `error` conforms to the `ApiError` contract.\n */\nexport function isApiError(error: unknown): error is ApiError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n typeof (error as ApiError).status === \"number\" &&\n typeof (error as ApiError).detail === \"string\"\n );\n}\n\n/**\n * Location prefixes FastAPI puts at the head of a validation error's `loc`,\n * naming the part of the request rather than the field. Dropped from the\n * rendered path, so `[\"body\", \"email\"]` reads as `email`.\n */\nconst LOC_ROOTS: ReadonlySet<string> = new Set([\"body\", \"query\", \"path\", \"header\", \"cookie\"]);\n\n/**\n * Render a FastAPI validation error's `loc` tuple as a dotted field path.\n *\n * @param loc - The raw `loc` value from one validation error entry.\n * @returns The dotted path (`\"items.0.price\"`), or undefined when `loc` carries\n * nothing addressable.\n */\nfunction formatLoc(loc: unknown): string | undefined {\n if (!Array.isArray(loc)) return undefined;\n const parts = loc\n .filter(\n (part): part is string | number => typeof part === \"string\" || typeof part === \"number\",\n )\n .filter((part, index) => !(index === 0 && LOC_ROOTS.has(String(part))));\n return parts.length > 0 ? parts.join(\".\") : undefined;\n}\n\n/**\n * How deep {@link normalizeDetail} follows a nested `detail` before giving up.\n *\n * A real envelope needs two or three levels: the list, an entry, the entry's\n * own `detail`. The cap exists because the body is untrusted input arriving on\n * the error path — a response nesting `{\"detail\":{\"detail\":…}}` twenty thousand\n * deep (a 220 KB body) overflowed the stack, and a `RangeError` thrown while\n * *building* the error is worse than the error: the caller's `catch` stops\n * receiving a `TempestApiError`, so `isApiError` is false, `describeApiError`\n * has nothing to read and the `401` handling never runs.\n */\nconst MAX_DETAIL_DEPTH = 4;\n\n/**\n * Pull field-level messages out of a validation `detail` **list**.\n *\n * FastAPI's `422` body is `detail: [{ loc, msg, type }]`, which is exactly what\n * a form needs and exactly what the flattened `detail` string destroys. Only the\n * top level is read: a validation error names one field per entry, and following\n * nesting here would invent paths the backend never sent.\n *\n * This is one of two ways a body names a field — see {@link collectFields}, which\n * is the entry point and falls back to the singular keys when the list names\n * nothing addressable.\n *\n * @param raw - The `detail` value from the error body.\n * @returns Field path to message, or undefined when the body is not a\n * validation list (or carries no entry naming a field).\n */\nfunction collectListFields(raw: unknown): Record<string, string> | undefined {\n if (!Array.isArray(raw)) return undefined;\n\n const fields: Record<string, string> = {};\n for (const entry of raw) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const record = entry as Record<string, unknown>;\n const field = formatLoc(record.loc);\n if (field === undefined || field in fields) continue;\n const message = normalizeDetail(record.msg) ?? normalizeDetail(record.message);\n if (message === undefined) continue;\n fields[field] = message;\n }\n\n return Object.keys(fields).length > 0 ? fields : undefined;\n}\n\n/**\n * Narrow a value to a plain object — a record, and not an array.\n *\n * Arrays are excluded because `typeof [] === \"object\"` while a list means\n * something else entirely here: FastAPI's `detail` list is read by\n * {@link collectListFields}, and reading `.field` off it would only ever be\n * undefined.\n *\n * @param value - The candidate value from the error body.\n * @returns The value as a record, or undefined when it is not a plain object.\n */\nfunction plainRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/**\n * Read the field a **singular** error envelope names.\n *\n * A backend built on `tempest-fastapi-sdk` never answers with FastAPI's `detail`\n * list once it owns the handler: it names the guilty field in a key beside the\n * message. Three shapes are seen in the wild, and they are read inner-out:\n *\n * 1. `detail.field` — the field sits in the same object as the message it\n * describes (`{ detail: { detail: \"Cidade não encontrada…\", field: \"city\" } }`),\n * so it is the least ambiguous claim about which message belongs to which input.\n * 2. `field` at the top level — a flattened `RequestValidationError`\n * (`{ detail: \"Value error, … for field 'phone' in 'body'\", field: \"phone\" }`)\n * makes the same claim one level out.\n * 3. `details.field` — `details` is the envelope's free-form context bag, not a\n * validation channel, and its `field` may be about something no input on screen\n * carries (an unknown sort column, say). It answers last for exactly that reason.\n *\n * `location` (`\"body -> phone\"`) is deliberately not parsed: it renders the same\n * path `field` already names, no observed envelope sends it without `field`, and\n * splitting an arrow-separated string would invent a path the backend never sent.\n *\n * @param body - The parsed error body, or null when it was not an object.\n * @returns The field name, or undefined when none of the three keys carried a\n * non-empty string — anything else is not usable as a key on `fields`.\n */\nfunction namedField(body: Record<string, unknown> | null): string | undefined {\n if (body === null) return undefined;\n const candidates: readonly unknown[] = [\n plainRecord(body.detail)?.field,\n body.field,\n plainRecord(body.details)?.field,\n ];\n for (const candidate of candidates) {\n if (typeof candidate === \"string\" && candidate !== \"\") return candidate;\n }\n return undefined;\n}\n\n/**\n * Drop the machine-readable tail a `tempest-fastapi-sdk` backend appends.\n *\n * That backend flattens a field error into\n * `\"CPF ou CNPJ inválido for field 'cpf_cnpj' in 'body'\"` — a finished sentence\n * in the app's language with an English clause glued to the end. The clause\n * carries nothing new: the same two values arrive as `field` and `location` on\n * the envelope, which is where `ApiError.fields` reads them from. Left in, it\n * reaches the user, and every consuming app grew its own regex to shave it off.\n *\n * The trim only fires when the field the tail names is the field the envelope\n * resolved to. That is what keeps it from deleting text it cannot account for:\n * a tail naming some other field is either a different envelope shape or a\n * sentence that genuinely reads that way, and both are left alone.\n *\n * @param message - The readable message, or undefined when the body had none.\n * @param field - The field name {@link namedField} resolved, if any.\n * @returns The message without the tail, or the message unchanged.\n */\nfunction trimFieldSuffix(\n message: string | undefined,\n field: string | undefined,\n): string | undefined {\n if (message === undefined || field === undefined) return message;\n const escaped = field.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const trimmed = message\n .replace(new RegExp(`\\\\s+for field '${escaped}'(?:\\\\s+in\\\\s+'[^']*')?\\\\.?\\\\s*$`), \"\")\n .trim();\n return trimmed === \"\" ? message : trimmed;\n}\n\n/**\n * Index the body's field-level messages, whichever envelope carried them.\n *\n * The single entry point behind `ApiError.fields`, and it applies two rules the\n * tests pin:\n *\n * - FastAPI's `detail` list wins whenever it names at least one addressable\n * field. A plain FastAPI app still answers a schema-level `422` with that list\n * even on a `tempest-fastapi-sdk` backend, so it stays authoritative.\n * - A named field with no readable message produces nothing. The only string\n * left at that point is the synthetic `Erro <status>`, and `{ phone: \"Erro 422\" }`\n * on an input is noise rather than an error message.\n *\n * @param body - The parsed error body, or null when it was not an object.\n * @param message - The readable message the same body produced, before the\n * synthetic fallback — the string that also becomes `ApiError.detail`.\n * @returns Field name to message, or undefined when nothing named a field.\n */\nfunction collectFields(\n body: Record<string, unknown> | null,\n message: string | undefined,\n): Record<string, string> | undefined {\n const listed = collectListFields(body?.detail);\n if (listed !== undefined) return listed;\n const field = namedField(body);\n if (field === undefined || message === undefined) return undefined;\n return { [field]: message };\n}\n\n/**\n * Collapse a backend `detail` of any shape into a single readable line.\n *\n * FastAPI answers a `422` with `detail` as a **list** of\n * `{ loc, msg, type }` entries, not a string. Passing that through `String()`\n * yields `\"[object Object]\"` — an error message that tells the user nothing and\n * hides which field failed. Each entry becomes `\"<field>: <msg>\"` and the\n * entries are joined with `\"; \"`; a nested object is read through its\n * `msg`/`message`/`detail` string.\n *\n * @param raw - The `detail` (or `message`) value from the error body.\n * @param depth - Current nesting level. Past {@link MAX_DETAIL_DEPTH} the value\n * is treated as unreadable instead of followed further.\n * @returns The rendered message, or undefined when nothing readable is there —\n * letting the caller fall back to the synthetic `Erro <status>`.\n */\nfunction normalizeDetail(raw: unknown, depth: number = 0): string | undefined {\n if (raw === null || raw === undefined) return undefined;\n if (typeof raw === \"string\") return raw === \"\" ? undefined : raw;\n if (typeof raw === \"number\" || typeof raw === \"boolean\") return String(raw);\n if (depth >= MAX_DETAIL_DEPTH) return undefined;\n\n if (Array.isArray(raw)) {\n const lines = raw\n .map((entry) => {\n const message = normalizeDetail(entry, depth + 1);\n if (message === undefined) return undefined;\n const field =\n typeof entry === \"object\" && entry !== null\n ? formatLoc((entry as Record<string, unknown>).loc)\n : undefined;\n return field === undefined ? message : `${field}: ${message}`;\n })\n .filter((line): line is string => line !== undefined);\n return lines.length > 0 ? lines.join(\"; \") : undefined;\n }\n\n if (typeof raw === \"object\") {\n const entry = raw as Record<string, unknown>;\n return (\n normalizeDetail(entry.msg, depth + 1) ??\n normalizeDetail(entry.message, depth + 1) ??\n normalizeDetail(entry.detail, depth + 1)\n );\n }\n\n return undefined;\n}\n\n/**\n * Statuses worth a second attempt, as a set for the sub-500 cases.\n *\n * A network failure (status `0`), a request timeout, a too-early replay, and a\n * rate limit — which usually carries the `Retry-After` the backoff honours.\n * Everything else below 500 is the server refusing on purpose.\n */\nconst RETRIABLE_STATUSES: ReadonlySet<number> = new Set([0, 408, 425, 429]);\n\n/**\n * Whether an HTTP status describes a condition a replay can plausibly fix.\n *\n * The single owner of that decision. It used to be spelled out in three places —\n * the client's own policy, the react-query default and the bare `retry()` helper\n * — and they had already drifted: the query default was missing `425`, so the\n * same `425 Too Early` was replayed through `createApiClient({ retry: true })`\n * and not replayed through `useQuery`. Same app, same error, two behaviours, and\n * no test caught it because each file asserted against its own copy.\n *\n * Deliberately about the status and nothing else. Whether a *non*-API error is\n * worth replaying, and whether the request's method may be replayed at all, are\n * the caller's calls: {@link createApiClient} refuses a non-idempotent method,\n * while a bare `retry()` has no method to inspect.\n *\n * @example\n * await api.get(\"/report\", {\n * retry: { shouldRetry: (error) => isApiError(error) && isRetriableStatus(error.status) },\n * });\n *\n * @param status - The HTTP status, where `0` means the request never landed.\n * @returns Whether a retry is worth attempting.\n */\nexport function isRetriableStatus(status: number): boolean {\n return RETRIABLE_STATUSES.has(status) || status >= 500;\n}\n\n/**\n * Detail text synthesised when a response body carries none.\n *\n * Exported because {@link describeApiError} has to recognise it: a detail the\n * server never sent says strictly less than the caller's own fallback, so the\n * funnel drops it. Comparing against a copied literal would silently stop\n * matching the day this sentence is reworded — no type error, no failing test.\n *\n * @param status - The HTTP status of the error.\n * @returns The synthetic detail for that status.\n */\nexport function syntheticDetail(status: number): string {\n return `Erro ${status}`;\n}\n\n/**\n * Parse an error body + response into the Tempest {@link ApiError} envelope.\n *\n * Reads `detail`/`message`, the programmatic `code`, and the correlation id\n * from `details.request_id` (falling back to the `X-Request-ID` header, then\n * the id the client sent).\n *\n * A `422` from FastAPI carries `detail` as a list of `{ loc, msg, type }`\n * entries, so it is flattened to `\"<field>: <msg>; <field>: <msg>\"` instead of\n * being stringified into `\"[object Object]\"`, and the same entries are indexed\n * on `fields` (`{ email: \"Field required\" }`) for a form to consume without\n * parsing that line back apart. The untouched body stays on `body`.\n *\n * A backend that owns its handlers — every `tempest-fastapi-sdk` app — sends no\n * such list, and names the field in a key instead:\n *\n * ```json\n * { \"detail\": \"Value error, … for field 'phone' in 'body'\", \"field\": \"phone\" }\n * { \"detail\": { \"detail\": \"Cidade não encontrada…\", \"field\": \"city\" },\n * \"code\": \"VALIDATION_ERROR\", \"details\": { \"field\": \"city\" } }\n * ```\n *\n * Those are indexed too, keyed by the field the backend named and valued with the\n * same sentence that becomes `detail`. Precedence is the list first, then\n * `detail.field`, `field`, `details.field` — see {@link collectFields}.\n *\n * A flattened `detail` from the list is developer-facing: it carries the\n * backend's field paths and the validator's own wording. `describeApiError` knows\n * not to show it to a person when `fields` is set — which now also covers a\n * business error that named a field, whose `detail` was a finished sentence. That\n * sentence is not lost: it is on `fields`, attached to the input that failed.\n *\n * @param status - HTTP status code.\n * @param body - The parsed error body (object, string, or null).\n * @param headers - The response headers (for the `X-Request-ID` fallback).\n * @param sentRequestId - The id the client sent on the request, if any.\n * @returns A fully-populated `ApiError`.\n *\n * @tempest-limits param-count — the arguments are the response as it arrives\n * (`status`, `body`, `headers`) plus the id the request was sent with, and they are\n * passed at exactly three places, all of them a client's response path\n * (`createApiClient`, `uploadWithProgress`, `createResumableUpload`). Wrapping them\n * in an options object would name each argument twice at every call site to say\n * nothing new.\n */\nexport function buildApiError(\n status: number,\n body: unknown,\n headers?: Headers | { get(name: string): string | null },\n sentRequestId?: string,\n): ApiError {\n const obj =\n typeof body === \"object\" && body !== null ? (body as Record<string, unknown>) : null;\n const message = trimFieldSuffix(\n normalizeDetail(obj?.detail) ?? normalizeDetail(obj?.message),\n namedField(obj),\n );\n const detail = message ?? syntheticDetail(status);\n const code = typeof obj?.code === \"string\" ? obj.code : undefined;\n const details =\n typeof obj?.details === \"object\" && obj.details !== null\n ? (obj.details as Record<string, unknown>)\n : null;\n const requestId =\n (typeof details?.request_id === \"string\" ? details.request_id : undefined) ??\n headers?.get(\"X-Request-ID\") ??\n sentRequestId ??\n undefined;\n\n return {\n status,\n detail,\n code,\n requestId: requestId ?? undefined,\n retryAfter: parseRetryAfter(headers?.get(\"Retry-After\")),\n fields: collectFields(obj, message),\n body,\n };\n}\n\n/**\n * Parse a `Retry-After` header into seconds. Accepts a delta-seconds integer\n * (`\"120\"`) or an HTTP-date (`\"Wed, 21 Oct 2015 07:28:00 GMT\"`).\n *\n * @param value - The raw header value, or null.\n * @returns The delay in seconds (>= 0), or undefined when absent/unparseable.\n */\nexport function parseRetryAfter(value: string | null | undefined): number | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (/^\\d+$/.test(trimmed)) return Number(trimmed);\n const when = Date.parse(trimmed);\n if (Number.isNaN(when)) return undefined;\n return Math.max(0, Math.round((when - Date.now()) / 1000));\n}\n"],"mappings":"AAkBA,IAAa,EAAb,cAAqC,KAA0B,CAC3D,OACA,OACA,KACA,UACA,OACA,KAEA,YAAY,EAAgB,CACxB,MAAM,EAAK,MAAM,EACjB,KAAK,KAAO,kBACZ,KAAK,OAAS,EAAK,OACnB,KAAK,OAAS,EAAK,OACnB,KAAK,KAAO,EAAK,KACjB,KAAK,UAAY,EAAK,UACtB,KAAK,OAAS,EAAK,OACnB,KAAK,KAAO,EAAK,IACrB,CACJ,EA2Ba,EAAb,cAA4C,KAAM,CAC9C,aAAc,CACV,MAAM,8CAA8C,EACpD,KAAK,KAAO,wBAChB,CACJ,EASA,SAAgB,EAAW,EAAmC,CAC1D,OACI,OAAO,GAAU,YACjB,GACA,OAAQ,EAAmB,QAAW,UACtC,OAAQ,EAAmB,QAAW,QAE9C,CAOA,IAAM,EAAiC,IAAI,IAAI,CAAC,OAAQ,QAAS,OAAQ,SAAU,QAAQ,CAAC,EAS5F,SAAS,EAAU,EAAkC,CACjD,GAAI,CAAC,MAAM,QAAQ,CAAG,EAAG,OACzB,IAAM,EAAQ,EACT,OACI,GAAkC,OAAO,GAAS,UAAY,OAAO,GAAS,QACnF,CAAC,CACA,QAAQ,EAAM,IAAU,EAAE,IAAU,GAAK,EAAU,IAAI,OAAO,CAAI,CAAC,EAAE,EAC1E,OAAO,EAAM,OAAS,EAAI,EAAM,KAAK,GAAG,EAAI,IAAA,EAChD,CAaA,IAAM,EAAmB,EAkBzB,SAAS,EAAkB,EAAkD,CACzE,GAAI,CAAC,MAAM,QAAQ,CAAG,EAAG,OAEzB,IAAM,EAAiC,CAAC,EACxC,IAAK,IAAM,KAAS,EAAK,CACrB,GAAI,OAAO,GAAU,WAAY,EAAgB,SACjD,IAAM,EAAS,EACT,EAAQ,EAAU,EAAO,GAAG,EAClC,GAAI,IAAU,IAAA,IAAa,KAAS,EAAQ,SAC5C,IAAM,EAAU,EAAgB,EAAO,GAAG,GAAK,EAAgB,EAAO,OAAO,EACzE,IAAY,IAAA,KAChB,EAAO,GAAS,EACpB,CAEA,OAAO,OAAO,KAAK,CAAM,CAAC,CAAC,OAAS,EAAI,EAAS,IAAA,EACrD,CAaA,SAAS,EAAY,EAAqD,CACtE,OAAO,OAAO,GAAU,UAAY,GAAkB,CAAC,MAAM,QAAQ,CAAK,EACnE,EACD,IAAA,EACV,CA2BA,SAAS,EAAW,EAA0D,CAC1E,GAAI,IAAS,KAAM,OACnB,IAAM,EAAiC,CACnC,EAAY,EAAK,MAAM,CAAC,EAAE,MAC1B,EAAK,MACL,EAAY,EAAK,OAAO,CAAC,EAAE,KAC/B,EACA,IAAK,IAAM,KAAa,EACpB,GAAI,OAAO,GAAc,UAAY,IAAc,GAAI,OAAO,CAGtE,CAqBA,SAAS,EACL,EACA,EACkB,CAClB,GAAI,IAAY,IAAA,IAAa,IAAU,IAAA,GAAW,OAAO,EACzD,IAAM,EAAU,EAAM,QAAQ,sBAAuB,MAAM,EACrD,EAAU,EACX,QAAY,OAAO,kBAAkB,EAAQ,iCAAiC,EAAG,EAAE,CAAC,CACpF,KAAK,EACV,OAAO,IAAY,GAAK,EAAU,CACtC,CAoBA,SAAS,EACL,EACA,EACkC,CAClC,IAAM,EAAS,EAAkB,GAAM,MAAM,EAC7C,GAAI,IAAW,IAAA,GAAW,OAAO,EACjC,IAAM,EAAQ,EAAW,CAAI,EACzB,OAAU,IAAA,IAAa,IAAY,IAAA,GACvC,MAAO,EAAG,GAAQ,CAAQ,CAC9B,CAkBA,SAAS,EAAgB,EAAc,EAAgB,EAAuB,CACtE,MAAQ,KACZ,IAAI,OAAO,GAAQ,SAAU,OAAO,IAAQ,GAAK,IAAA,GAAY,EAC7D,GAAI,OAAO,GAAQ,UAAY,OAAO,GAAQ,UAAW,OAAO,OAAO,CAAG,EACtE,QAAS,GAEb,IAAI,MAAM,QAAQ,CAAG,EAAG,CACpB,IAAM,EAAQ,EACT,IAAK,GAAU,CACZ,IAAM,EAAU,EAAgB,EAAO,EAAQ,CAAC,EAChD,GAAI,IAAY,IAAA,GAAW,OAC3B,IAAM,EACF,OAAO,GAAU,UAAY,EACvB,EAAW,EAAkC,GAAG,EAChD,IAAA,GACV,OAAO,IAAU,IAAA,GAAY,EAAU,GAAG,EAAM,IAAI,GACxD,CAAC,CAAC,CACD,OAAQ,GAAyB,IAAS,IAAA,EAAS,EACxD,OAAO,EAAM,OAAS,EAAI,EAAM,KAAK,IAAI,EAAI,IAAA,EACjD,CAEA,GAAI,OAAO,GAAQ,SAAU,CACzB,IAAM,EAAQ,EACd,OACI,EAAgB,EAAM,IAAK,EAAQ,CAAC,GACpC,EAAgB,EAAM,QAAS,EAAQ,CAAC,GACxC,EAAgB,EAAM,OAAQ,EAAQ,CAAC,CAE/C,CATA,CAjB6D,CA6BjE,CASA,IAAM,EAA0C,IAAI,IAAI,CAAC,EAAG,IAAK,IAAK,GAAG,CAAC,EAyB1E,SAAgB,EAAkB,EAAyB,CACvD,OAAO,EAAmB,IAAI,CAAM,GAAK,GAAU,GACvD,CAaA,SAAgB,EAAgB,EAAwB,CACpD,MAAO,QAAQ,GACnB,CA+CA,SAAgB,EACZ,EACA,EACA,EACA,EACQ,CACR,IAAM,EACF,OAAO,GAAS,UAAY,EAAiB,EAAmC,KAC9E,EAAU,EACZ,EAAgB,GAAK,MAAM,GAAK,EAAgB,GAAK,OAAO,EAC5D,EAAW,CAAG,CAClB,EACM,EAAS,GAAW,EAAgB,CAAM,EAC1C,EAAO,OAAO,GAAK,MAAS,SAAW,EAAI,KAAO,IAAA,GAClD,EACF,OAAO,GAAK,SAAY,UAAY,EAAI,UAAY,KAC7C,EAAI,QACL,KAOV,MAAO,CACH,SACA,SACA,OACA,WATC,OAAO,GAAS,YAAe,SAAW,EAAQ,WAAa,IAAA,KAChE,GAAS,IAAI,cAAc,GAC3B,GACA,IAAA,IAMwB,IAAA,GACxB,WAAY,EAAgB,GAAS,IAAI,aAAa,CAAC,EACvD,OAAQ,EAAc,EAAK,CAAO,EAClC,MACJ,CACJ,CASA,SAAgB,EAAgB,EAAsD,CAClF,GAAI,CAAC,EAAO,OACZ,IAAM,EAAU,EAAM,KAAK,EAC3B,GAAI,QAAQ,KAAK,CAAO,EAAG,OAAO,OAAO,CAAO,EAChD,IAAM,EAAO,KAAK,MAAM,CAAO,EAC3B,WAAO,MAAM,CAAI,EACrB,OAAO,KAAK,IAAI,EAAG,KAAK,OAAO,EAAO,KAAK,IAAI,GAAK,GAAI,CAAC,CAC7D"}
1
+ {"version":3,"file":"errors.cjs","names":["TempestApiError","init","SessionSupersededError","isApiError","error","LOC_ROOTS","formatLoc","loc","parts","part","index","MAX_DETAIL_DEPTH","collectListFields","raw","fields","entry","record","field","message","normalizeDetail","plainRecord","value","namedField","body","candidates","candidate","trimFieldSuffix","escaped","trimmed","collectFields","listed","lines","depth","line","RETRIABLE_STATUSES","isRetriableStatus","status","syntheticDetail","buildApiError","obj","detail","code","details","headers","sentRequestId","parseRetryAfter","when"],"sources":["../../src/http/errors.ts"],"sourcesContent":["import type { ApiError } from \"./types\";\n\n/**\n * Error thrown by {@link createApiClient} / {@link uploadWithProgress} on a\n * non-2xx response. Mirrors the Tempest FastAPI SDK error envelope\n * (`{ detail, code, details.request_id }`) so callers get a typed `code` and a\n * `requestId` for log correlation, while still being a real `Error` (stack\n * trace, `instanceof Error`).\n *\n * @example\n * try {\n * await api.post(\"/users\", { body });\n * } catch (err) {\n * if (isApiError(err) && err.code === \"EMAIL_TAKEN\") {\n * showFieldError(\"email\", err.detail);\n * }\n * }\n */\nexport class TempestApiError extends Error implements ApiError {\n readonly status: number;\n readonly detail: string;\n readonly code?: string;\n readonly requestId?: string;\n readonly fields?: Record<string, string>;\n readonly body?: unknown;\n\n constructor(init: ApiError) {\n super(init.detail);\n this.name = \"TempestApiError\";\n this.status = init.status;\n this.detail = init.detail;\n this.code = init.code;\n this.requestId = init.requestId;\n this.fields = init.fields;\n this.body = init.body;\n }\n}\n\n/**\n * Thrown when the session that started an operation is no longer the current\n * one by the time it settles: a `refresh` hook (rethrown by\n * {@link createApiClient}), or a `createTempestAuth` `login()` whose session\n * was replaced while it waited on the previous session's teardown.\n *\n * A refresh is a network round trip, and the session can end or change hands\n * during it: the user signs out, or signs out and another account signs in. The\n * tokens that refresh brings back belong to the session that ended, so they are\n * discarded instead of installed, and the request that was waiting on them is\n * not replayed — replaying it would send it as whoever is signed in now.\n *\n * This is deliberately not an unauthorized outcome. The client does **not** call\n * `onUnauthorized` for it: that callback ends the session, and the current\n * session — possibly a different account that just signed in — did nothing\n * wrong. Treat it like an aborted request: drop the result, show nothing.\n *\n * @example\n * try {\n * await api.get(\"/api/orders\");\n * } catch (err) {\n * if (err instanceof SessionSupersededError) return;\n * throw err;\n * }\n */\nexport class SessionSupersededError extends Error {\n constructor() {\n super(\"A sessão mudou antes de a operação terminar.\");\n this.name = \"SessionSupersededError\";\n }\n}\n\n/**\n * Type guard for the {@link ApiError} shape. Matches both {@link TempestApiError}\n * instances and plain objects carrying `status` + `detail`.\n *\n * @param error - The unknown value (typically a caught error).\n * @returns Whether `error` conforms to the `ApiError` contract.\n */\nexport function isApiError(error: unknown): error is ApiError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n typeof (error as ApiError).status === \"number\" &&\n typeof (error as ApiError).detail === \"string\"\n );\n}\n\n/**\n * Location prefixes FastAPI puts at the head of a validation error's `loc`,\n * naming the part of the request rather than the field. Dropped from the\n * rendered path, so `[\"body\", \"email\"]` reads as `email`.\n */\nconst LOC_ROOTS: ReadonlySet<string> = new Set([\"body\", \"query\", \"path\", \"header\", \"cookie\"]);\n\n/**\n * Render a FastAPI validation error's `loc` tuple as a dotted field path.\n *\n * @param loc - The raw `loc` value from one validation error entry.\n * @returns The dotted path (`\"items.0.price\"`), or undefined when `loc` carries\n * nothing addressable.\n */\nfunction formatLoc(loc: unknown): string | undefined {\n if (!Array.isArray(loc)) return undefined;\n const parts = loc\n .filter(\n (part): part is string | number => typeof part === \"string\" || typeof part === \"number\",\n )\n .filter((part, index) => !(index === 0 && LOC_ROOTS.has(String(part))));\n return parts.length > 0 ? parts.join(\".\") : undefined;\n}\n\n/**\n * How deep {@link normalizeDetail} follows a nested `detail` before giving up.\n *\n * A real envelope needs two or three levels: the list, an entry, the entry's\n * own `detail`. The cap exists because the body is untrusted input arriving on\n * the error path — a response nesting `{\"detail\":{\"detail\":…}}` twenty thousand\n * deep (a 220 KB body) overflowed the stack, and a `RangeError` thrown while\n * *building* the error is worse than the error: the caller's `catch` stops\n * receiving a `TempestApiError`, so `isApiError` is false, `describeApiError`\n * has nothing to read and the `401` handling never runs.\n */\nconst MAX_DETAIL_DEPTH = 4;\n\n/**\n * Pull field-level messages out of a validation `detail` **list**.\n *\n * FastAPI's `422` body is `detail: [{ loc, msg, type }]`, which is exactly what\n * a form needs and exactly what the flattened `detail` string destroys. Only the\n * top level is read: a validation error names one field per entry, and following\n * nesting here would invent paths the backend never sent.\n *\n * This is one of two ways a body names a field — see {@link collectFields}, which\n * is the entry point and falls back to the singular keys when the list names\n * nothing addressable.\n *\n * @param raw - The `detail` value from the error body.\n * @returns Field path to message, or undefined when the body is not a\n * validation list (or carries no entry naming a field).\n */\nfunction collectListFields(raw: unknown): Record<string, string> | undefined {\n if (!Array.isArray(raw)) return undefined;\n\n const fields: Record<string, string> = {};\n for (const entry of raw) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const record = entry as Record<string, unknown>;\n const field = formatLoc(record.loc);\n if (field === undefined || field in fields) continue;\n const message = normalizeDetail(record.msg) ?? normalizeDetail(record.message);\n if (message === undefined) continue;\n fields[field] = message;\n }\n\n return Object.keys(fields).length > 0 ? fields : undefined;\n}\n\n/**\n * Narrow a value to a plain object — a record, and not an array.\n *\n * Arrays are excluded because `typeof [] === \"object\"` while a list means\n * something else entirely here: FastAPI's `detail` list is read by\n * {@link collectListFields}, and reading `.field` off it would only ever be\n * undefined.\n *\n * @param value - The candidate value from the error body.\n * @returns The value as a record, or undefined when it is not a plain object.\n */\nfunction plainRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/**\n * Read the field a **singular** error envelope names.\n *\n * A backend built on `tempest-fastapi-sdk` never answers with FastAPI's `detail`\n * list once it owns the handler: it names the guilty field in a key beside the\n * message. Three shapes are seen in the wild, and they are read inner-out:\n *\n * 1. `detail.field` — the field sits in the same object as the message it\n * describes (`{ detail: { detail: \"Cidade não encontrada…\", field: \"city\" } }`),\n * so it is the least ambiguous claim about which message belongs to which input.\n * 2. `field` at the top level — a flattened `RequestValidationError`\n * (`{ detail: \"Value error, … for field 'phone' in 'body'\", field: \"phone\" }`)\n * makes the same claim one level out.\n * 3. `details.field` — `details` is the envelope's free-form context bag, not a\n * validation channel, and its `field` may be about something no input on screen\n * carries (an unknown sort column, say). It answers last for exactly that reason.\n *\n * `location` (`\"body -> phone\"`) is deliberately not parsed: it renders the same\n * path `field` already names, no observed envelope sends it without `field`, and\n * splitting an arrow-separated string would invent a path the backend never sent.\n *\n * @param body - The parsed error body, or null when it was not an object.\n * @returns The field name, or undefined when none of the three keys carried a\n * non-empty string — anything else is not usable as a key on `fields`.\n */\nfunction namedField(body: Record<string, unknown> | null): string | undefined {\n if (body === null) return undefined;\n const candidates: readonly unknown[] = [\n plainRecord(body.detail)?.field,\n body.field,\n plainRecord(body.details)?.field,\n ];\n for (const candidate of candidates) {\n if (typeof candidate === \"string\" && candidate !== \"\") return candidate;\n }\n return undefined;\n}\n\n/**\n * Drop the machine-readable tail a `tempest-fastapi-sdk` backend appends.\n *\n * That backend flattens a field error into\n * `\"CPF ou CNPJ inválido for field 'cpf_cnpj' in 'body'\"` — a finished sentence\n * in the app's language with an English clause glued to the end. The clause\n * carries nothing new: the same two values arrive as `field` and `location` on\n * the envelope, which is where `ApiError.fields` reads them from. Left in, it\n * reaches the user, and every consuming app grew its own regex to shave it off.\n *\n * The trim only fires when the field the tail names is the field the envelope\n * resolved to. That is what keeps it from deleting text it cannot account for:\n * a tail naming some other field is either a different envelope shape or a\n * sentence that genuinely reads that way, and both are left alone.\n *\n * @param message - The readable message, or undefined when the body had none.\n * @param field - The field name {@link namedField} resolved, if any.\n * @returns The message without the tail, or the message unchanged.\n */\nfunction trimFieldSuffix(\n message: string | undefined,\n field: string | undefined,\n): string | undefined {\n if (message === undefined || field === undefined) return message;\n const escaped = field.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const trimmed = message\n .replace(new RegExp(`\\\\s+for field '${escaped}'(?:\\\\s+in\\\\s+'[^']*')?\\\\.?\\\\s*$`), \"\")\n .trim();\n return trimmed === \"\" ? message : trimmed;\n}\n\n/**\n * Index the body's field-level messages, whichever envelope carried them.\n *\n * The single entry point behind `ApiError.fields`, and it applies two rules the\n * tests pin:\n *\n * - FastAPI's `detail` list wins whenever it names at least one addressable\n * field. A plain FastAPI app still answers a schema-level `422` with that list\n * even on a `tempest-fastapi-sdk` backend, so it stays authoritative.\n * - A named field with no readable message produces nothing. The only string\n * left at that point is the synthetic `Erro <status>`, and `{ phone: \"Erro 422\" }`\n * on an input is noise rather than an error message.\n *\n * @param body - The parsed error body, or null when it was not an object.\n * @param message - The readable message the same body produced, before the\n * synthetic fallback — the string that also becomes `ApiError.detail`.\n * @returns Field name to message, or undefined when nothing named a field.\n */\nfunction collectFields(\n body: Record<string, unknown> | null,\n message: string | undefined,\n): Record<string, string> | undefined {\n const listed = collectListFields(body?.detail);\n if (listed !== undefined) return listed;\n const field = namedField(body);\n if (field === undefined || message === undefined) return undefined;\n return { [field]: message };\n}\n\n/**\n * Collapse a backend `detail` of any shape into a single readable line.\n *\n * FastAPI answers a `422` with `detail` as a **list** of\n * `{ loc, msg, type }` entries, not a string. Passing that through `String()`\n * yields `\"[object Object]\"` — an error message that tells the user nothing and\n * hides which field failed. Each entry becomes `\"<field>: <msg>\"` and the\n * entries are joined with `\"; \"`; a nested object is read through its\n * `msg`/`message`/`detail` string.\n *\n * @param raw - The `detail` (or `message`) value from the error body.\n * @param depth - Current nesting level. Past {@link MAX_DETAIL_DEPTH} the value\n * is treated as unreadable instead of followed further.\n * @returns The rendered message, or undefined when nothing readable is there —\n * letting the caller fall back to the synthetic `Erro <status>`.\n */\nfunction normalizeDetail(raw: unknown, depth: number = 0): string | undefined {\n if (raw === null || raw === undefined) return undefined;\n if (typeof raw === \"string\") return raw === \"\" ? undefined : raw;\n if (typeof raw === \"number\" || typeof raw === \"boolean\") return String(raw);\n if (depth >= MAX_DETAIL_DEPTH) return undefined;\n\n if (Array.isArray(raw)) {\n const lines = raw\n .map((entry) => {\n const message = normalizeDetail(entry, depth + 1);\n if (message === undefined) return undefined;\n const field =\n typeof entry === \"object\" && entry !== null\n ? formatLoc((entry as Record<string, unknown>).loc)\n : undefined;\n return field === undefined ? message : `${field}: ${message}`;\n })\n .filter((line): line is string => line !== undefined);\n return lines.length > 0 ? lines.join(\"; \") : undefined;\n }\n\n if (typeof raw === \"object\") {\n const entry = raw as Record<string, unknown>;\n return (\n normalizeDetail(entry.msg, depth + 1) ??\n normalizeDetail(entry.message, depth + 1) ??\n normalizeDetail(entry.detail, depth + 1)\n );\n }\n\n return undefined;\n}\n\n/**\n * Statuses worth a second attempt, as a set for the sub-500 cases.\n *\n * A network failure (status `0`), a request timeout, a too-early replay, and a\n * rate limit — which usually carries the `Retry-After` the backoff honours.\n * Everything else below 500 is the server refusing on purpose.\n */\nconst RETRIABLE_STATUSES: ReadonlySet<number> = new Set([0, 408, 425, 429]);\n\n/**\n * Whether an HTTP status describes a condition a replay can plausibly fix.\n *\n * The single owner of that decision. It used to be spelled out in three places —\n * the client's own policy, the react-query default and the bare `retry()` helper\n * — and they had already drifted: the query default was missing `425`, so the\n * same `425 Too Early` was replayed through `createApiClient({ retry: true })`\n * and not replayed through `useQuery`. Same app, same error, two behaviours, and\n * no test caught it because each file asserted against its own copy.\n *\n * Deliberately about the status and nothing else. Whether a *non*-API error is\n * worth replaying, and whether the request's method may be replayed at all, are\n * the caller's calls: {@link createApiClient} refuses a non-idempotent method,\n * while a bare `retry()` has no method to inspect.\n *\n * @example\n * await api.get(\"/report\", {\n * retry: { shouldRetry: (error) => isApiError(error) && isRetriableStatus(error.status) },\n * });\n *\n * @param status - The HTTP status, where `0` means the request never landed.\n * @returns Whether a retry is worth attempting.\n */\nexport function isRetriableStatus(status: number): boolean {\n return RETRIABLE_STATUSES.has(status) || status >= 500;\n}\n\n/**\n * Detail text synthesised when a response body carries none.\n *\n * Exported because {@link describeApiError} has to recognise it: a detail the\n * server never sent says strictly less than the caller's own fallback, so the\n * funnel drops it. Comparing against a copied literal would silently stop\n * matching the day this sentence is reworded — no type error, no failing test.\n *\n * @param status - The HTTP status of the error.\n * @returns The synthetic detail for that status.\n */\nexport function syntheticDetail(status: number): string {\n return `Erro ${status}`;\n}\n\n/**\n * Parse an error body + response into the Tempest {@link ApiError} envelope.\n *\n * Reads `detail`/`message`, the programmatic `code`, and the correlation id\n * from `details.request_id` (falling back to the `X-Request-ID` header, then\n * the id the client sent).\n *\n * A `422` from FastAPI carries `detail` as a list of `{ loc, msg, type }`\n * entries, so it is flattened to `\"<field>: <msg>; <field>: <msg>\"` instead of\n * being stringified into `\"[object Object]\"`, and the same entries are indexed\n * on `fields` (`{ email: \"Field required\" }`) for a form to consume without\n * parsing that line back apart. The untouched body stays on `body`.\n *\n * A backend that owns its handlers — every `tempest-fastapi-sdk` app — sends no\n * such list, and names the field in a key instead:\n *\n * ```json\n * { \"detail\": \"Value error, … for field 'phone' in 'body'\", \"field\": \"phone\" }\n * { \"detail\": { \"detail\": \"Cidade não encontrada…\", \"field\": \"city\" },\n * \"code\": \"VALIDATION_ERROR\", \"details\": { \"field\": \"city\" } }\n * ```\n *\n * Those are indexed too, keyed by the field the backend named and valued with the\n * same sentence that becomes `detail`. Precedence is the list first, then\n * `detail.field`, `field`, `details.field` — see {@link collectFields}.\n *\n * A flattened `detail` from the list is developer-facing: it carries the\n * backend's field paths and the validator's own wording. `describeApiError` knows\n * not to show it to a person when `fields` is set — which now also covers a\n * business error that named a field, whose `detail` was a finished sentence. That\n * sentence is not lost: it is on `fields`, attached to the input that failed.\n *\n * @param status - HTTP status code.\n * @param body - The parsed error body (object, string, or null).\n * @param headers - The response headers (for the `X-Request-ID` fallback).\n * @param sentRequestId - The id the client sent on the request, if any.\n * @returns A fully-populated `ApiError`.\n *\n * @tempest-limits param-count — the arguments are the response as it arrives\n * (`status`, `body`, `headers`) plus the id the request was sent with, and they are\n * passed at exactly three places, all of them a client's response path\n * (`createApiClient`, `uploadWithProgress`, `createResumableUpload`). Wrapping them\n * in an options object would name each argument twice at every call site to say\n * nothing new.\n */\nexport function buildApiError(\n status: number,\n body: unknown,\n headers?: Headers | { get(name: string): string | null },\n sentRequestId?: string,\n): ApiError {\n const obj =\n typeof body === \"object\" && body !== null ? (body as Record<string, unknown>) : null;\n const message = trimFieldSuffix(\n normalizeDetail(obj?.detail) ?? normalizeDetail(obj?.message),\n namedField(obj),\n );\n const detail = message ?? syntheticDetail(status);\n const code = typeof obj?.code === \"string\" ? obj.code : undefined;\n const details =\n typeof obj?.details === \"object\" && obj.details !== null\n ? (obj.details as Record<string, unknown>)\n : null;\n const requestId =\n (typeof details?.request_id === \"string\" ? details.request_id : undefined) ??\n headers?.get(\"X-Request-ID\") ??\n sentRequestId ??\n undefined;\n\n return {\n status,\n detail,\n code,\n requestId: requestId ?? undefined,\n retryAfter: parseRetryAfter(headers?.get(\"Retry-After\")),\n fields: collectFields(obj, message),\n body,\n };\n}\n\n/**\n * Parse a `Retry-After` header into seconds. Accepts a delta-seconds integer\n * (`\"120\"`) or an HTTP-date (`\"Wed, 21 Oct 2015 07:28:00 GMT\"`).\n *\n * @param value - The raw header value, or null.\n * @returns The delay in seconds (>= 0), or undefined when absent/unparseable.\n */\nexport function parseRetryAfter(value: string | null | undefined): number | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (/^\\d+$/.test(trimmed)) return Number(trimmed);\n const when = Date.parse(trimmed);\n if (Number.isNaN(when)) return undefined;\n return Math.max(0, Math.round((when - Date.now()) / 1000));\n}\n"],"mappings":"AAkBA,IAAaA,EAAb,cAAqC,KAA0B,CAC3D,OACA,OACA,KACA,UACA,OACA,KAEA,YAAY,EAAgB,CACxB,MAAMC,EAAK,MAAM,EACjB,KAAK,KAAO,kBACZ,KAAK,OAASA,EAAK,OACnB,KAAK,OAASA,EAAK,OACnB,KAAK,KAAOA,EAAK,KACjB,KAAK,UAAYA,EAAK,UACtB,KAAK,OAASA,EAAK,OACnB,KAAK,KAAOA,EAAK,IACrB,CACJ,EA2BaC,EAAb,cAA4C,KAAM,CAC9C,aAAc,CACV,MAAM,8CAA8C,EACpD,KAAK,KAAO,wBAChB,CACJ,EASA,SAAgBC,EAAW,EAAmC,CAC1D,OACI,OAAOC,GAAU,YACjBA,GACA,OAAQA,EAAmB,QAAW,UACtC,OAAQA,EAAmB,QAAW,QAE9C,CAOA,IAAMC,EAAiC,IAAI,IAAI,CAAC,OAAQ,QAAS,OAAQ,SAAU,QAAQ,CAAC,EAS5F,SAASC,EAAU,EAAkC,CACjD,GAAI,CAAC,MAAM,QAAQC,CAAG,EAAG,OACzB,IAAMC,EAAQD,EACT,OACI,GAAkC,OAAOE,GAAS,UAAY,OAAOA,GAAS,QACnF,CAAC,CACA,QAAQ,EAAM,IAAU,EAAEC,IAAU,GAAKL,EAAU,IAAI,OAAOI,CAAI,CAAC,EAAE,EAC1E,OAAOD,EAAM,OAAS,EAAIA,EAAM,KAAK,GAAG,EAAI,IAAA,EAChD,CAaA,IAAMG,EAAmB,EAkBzB,SAASC,EAAkB,EAAkD,CACzE,GAAI,CAAC,MAAM,QAAQC,CAAG,EAAG,OAEzB,IAAMC,EAAiC,CAAC,EACxC,IAAK,IAAMC,KAASF,EAAK,CACrB,GAAI,OAAOE,GAAU,WAAYA,EAAgB,SACjD,IAAMC,EAASD,EACTE,EAAQX,EAAUU,EAAO,GAAG,EAClC,GAAIC,IAAU,IAAA,IAAaA,KAASH,EAAQ,SAC5C,IAAMI,EAAUC,EAAgBH,EAAO,GAAG,GAAKG,EAAgBH,EAAO,OAAO,EACzEE,IAAY,IAAA,KAChB,EAAOD,GAASC,EACpB,CAEA,OAAO,OAAO,KAAKJ,CAAM,CAAC,CAAC,OAAS,EAAIA,EAAS,IAAA,EACrD,CAaA,SAASM,EAAY,EAAqD,CACtE,OAAO,OAAOC,GAAU,UAAYA,GAAkB,CAAC,MAAM,QAAQA,CAAK,EACnEA,EACD,IAAA,EACV,CA2BA,SAASC,EAAW,EAA0D,CAC1E,GAAIC,IAAS,KAAM,OACnB,IAAMC,EAAiC,CACnCJ,EAAYG,EAAK,MAAM,CAAC,EAAE,MAC1BA,EAAK,MACLH,EAAYG,EAAK,OAAO,CAAC,EAAE,KAC/B,EACA,IAAK,IAAME,KAAaD,EACpB,GAAI,OAAOC,GAAc,UAAYA,IAAc,GAAI,OAAOA,CAGtE,CAqBA,SAASC,EACL,EACA,EACkB,CAClB,GAAIR,IAAY,IAAA,IAAaD,IAAU,IAAA,GAAW,OAAOC,EACzD,IAAMS,EAAUV,EAAM,QAAQ,sBAAuB,MAAM,EACrDW,EAAUV,EACX,QAAY,OAAO,kBAAkBS,EAAQ,iCAAiC,EAAG,EAAE,CAAC,CACpF,KAAK,EACV,OAAOC,IAAY,GAAKV,EAAUU,CACtC,CAoBA,SAASC,EACL,EACA,EACkC,CAClC,IAAMC,EAASlB,EAAkBW,GAAM,MAAM,EAC7C,GAAIO,IAAW,IAAA,GAAW,OAAOA,EACjC,IAAMb,EAAQK,EAAWC,CAAI,EAC7B,GAAIN,IAAU,IAAA,IAAaC,IAAY,IAAA,GACvC,MAAO,EAAGD,GAAQC,CAAQ,CAC9B,CAkBA,SAASC,EAAgB,EAAc,EAAgB,EAAuB,CAC1E,GAAIN,GAAQ,KACZ,IAAI,OAAOA,GAAQ,SAAU,OAAOA,IAAQ,GAAK,IAAA,GAAYA,EAC7D,GAAI,OAAOA,GAAQ,UAAY,OAAOA,GAAQ,UAAW,OAAO,OAAOA,CAAG,EAC1E,GAAI,KAASF,GAEb,IAAI,MAAM,QAAQE,CAAG,EAAG,CACpB,IAAMkB,EAAQlB,EACT,IAAK,GAAU,CACZ,IAAMK,EAAUC,EAAgBJ,EAAOiB,EAAQ,CAAC,EAChD,GAAId,IAAY,IAAA,GAAW,OAC3B,IAAMD,EACF,OAAOF,GAAU,UAAYA,EACvBT,EAAWS,EAAkC,GAAG,EAChD,IAAA,GACV,OAAOE,IAAU,IAAA,GAAYC,EAAU,GAAGD,EAAM,IAAIC,GACxD,CAAC,CAAC,CACD,OAAQ,GAAyBe,IAAS,IAAA,EAAS,EACxD,OAAOF,EAAM,OAAS,EAAIA,EAAM,KAAK,IAAI,EAAI,IAAA,EACjD,CAEA,GAAI,OAAOlB,GAAQ,SAAU,CACzB,IAAME,EAAQF,EACd,OACIM,EAAgBJ,EAAM,IAAKiB,EAAQ,CAAC,GACpCb,EAAgBJ,EAAM,QAASiB,EAAQ,CAAC,GACxCb,EAAgBJ,EAAM,OAAQiB,EAAQ,CAAC,CAE/C,CATA,CAjB6D,CA6BjE,CASA,IAAME,EAA0C,IAAI,IAAI,CAAC,EAAG,IAAK,IAAK,GAAG,CAAC,EAyB1E,SAAgBC,EAAkB,EAAyB,CACvD,OAAOD,EAAmB,IAAIE,CAAM,GAAKA,GAAU,GACvD,CAaA,SAAgBC,EAAgB,EAAwB,CACpD,MAAO,QAAQD,GACnB,CA+CA,SAAgBE,EACZ,EACA,EACA,EACA,EACQ,CACR,IAAMC,EACF,OAAOhB,GAAS,UAAYA,EAAiBA,EAAmC,KAC9EL,EAAUQ,EACZP,EAAgBoB,GAAK,MAAM,GAAKpB,EAAgBoB,GAAK,OAAO,EAC5DjB,EAAWiB,CAAG,CAClB,EACMC,EAAStB,GAAWmB,EAAgBD,CAAM,EAC1CK,EAAO,OAAOF,GAAK,MAAS,SAAWA,EAAI,KAAO,IAAA,GAClDG,EACF,OAAOH,GAAK,SAAY,UAAYA,EAAI,UAAY,KAC7CA,EAAI,QACL,KAOV,MAAO,CACH,SACA,SACA,OACA,WATC,OAAOG,GAAS,YAAe,SAAWA,EAAQ,WAAa,IAAA,KAChEC,GAAS,IAAI,cAAc,GAC3BC,GACA,IAAA,IAMwB,IAAA,GACxB,WAAYC,EAAgBF,GAAS,IAAI,aAAa,CAAC,EACvD,OAAQd,EAAcU,EAAKrB,CAAO,EAClC,MACJ,CACJ,CASA,SAAgB2B,EAAgB,EAAsD,CAClF,GAAI,CAACxB,EAAO,OACZ,IAAMO,EAAUP,EAAM,KAAK,EAC3B,GAAI,QAAQ,KAAKO,CAAO,EAAG,OAAO,OAAOA,CAAO,EAChD,IAAMkB,EAAO,KAAK,MAAMlB,CAAO,EAC/B,GAAI,QAAO,MAAMkB,CAAI,EACrB,OAAO,KAAK,IAAI,EAAG,KAAK,OAAOA,EAAO,KAAK,IAAI,GAAK,GAAI,CAAC,CAC7D,C"}