@atproto/oauth-provider 0.3.1 → 0.5.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 (404) hide show
  1. package/.linguirc +57 -0
  2. package/CHANGELOG.md +29 -0
  3. package/LICENSE.txt +1 -1
  4. package/dist/account/account-manager.d.ts +17 -3
  5. package/dist/account/account-manager.d.ts.map +1 -1
  6. package/dist/account/account-manager.js +102 -8
  7. package/dist/account/account-manager.js.map +1 -1
  8. package/dist/account/account-store.d.ts +81 -15
  9. package/dist/account/account-store.d.ts.map +1 -1
  10. package/dist/account/account-store.js +70 -19
  11. package/dist/account/account-store.js.map +1 -1
  12. package/dist/account/sign-in-data.d.ts +28 -0
  13. package/dist/account/sign-in-data.d.ts.map +1 -0
  14. package/dist/account/sign-in-data.js +16 -0
  15. package/dist/account/sign-in-data.js.map +1 -0
  16. package/dist/account/sign-up-data.d.ts +26 -0
  17. package/dist/account/sign-up-data.d.ts.map +1 -0
  18. package/dist/account/sign-up-data.js +11 -0
  19. package/dist/account/sign-up-data.js.map +1 -0
  20. package/dist/assets/app/bundle-manifest.json +598 -6
  21. package/dist/assets/app/index-ItwwtJ8r.js +36 -0
  22. package/dist/assets/app/index-ItwwtJ8r.js.map +1 -0
  23. package/dist/assets/app/main-B_dNxQo_.js +4 -0
  24. package/dist/assets/app/main-B_dNxQo_.js.map +1 -0
  25. package/dist/assets/app/main-CSatvmRR.css +3 -0
  26. package/dist/assets/app/main-CSatvmRR.js +306 -0
  27. package/dist/assets/app/main-CSatvmRR.js.map +1 -0
  28. package/dist/assets/app/messages-BQeltXSF.js +4 -0
  29. package/dist/assets/app/messages-BQeltXSF.js.map +1 -0
  30. package/dist/assets/app/messages-BQkEhfjg.js +4 -0
  31. package/dist/assets/app/messages-BQkEhfjg.js.map +1 -0
  32. package/dist/assets/app/messages-BUjKj_UJ.js +4 -0
  33. package/dist/assets/app/messages-BUjKj_UJ.js.map +1 -0
  34. package/dist/assets/app/messages-BWIQa8fO.js +4 -0
  35. package/dist/assets/app/messages-BWIQa8fO.js.map +1 -0
  36. package/dist/assets/app/messages-BaNVb0bp.js +4 -0
  37. package/dist/assets/app/messages-BaNVb0bp.js.map +1 -0
  38. package/dist/assets/app/messages-BaizVXcF.js +4 -0
  39. package/dist/assets/app/messages-BaizVXcF.js.map +1 -0
  40. package/dist/assets/app/messages-BfoClA1Y.js +4 -0
  41. package/dist/assets/app/messages-BfoClA1Y.js.map +1 -0
  42. package/dist/assets/app/messages-BsKGDZnC.js +4 -0
  43. package/dist/assets/app/messages-BsKGDZnC.js.map +1 -0
  44. package/dist/assets/app/messages-Bu-TJhml.js +4 -0
  45. package/dist/assets/app/messages-Bu-TJhml.js.map +1 -0
  46. package/dist/assets/app/messages-BvOKnBQk.js +4 -0
  47. package/dist/assets/app/messages-BvOKnBQk.js.map +1 -0
  48. package/dist/assets/app/messages-BxDzCiWz.js +4 -0
  49. package/dist/assets/app/messages-BxDzCiWz.js.map +1 -0
  50. package/dist/assets/app/messages-CDgFOy4S.js +4 -0
  51. package/dist/assets/app/messages-CDgFOy4S.js.map +1 -0
  52. package/dist/assets/app/messages-CLbTz0o9.js +4 -0
  53. package/dist/assets/app/messages-CLbTz0o9.js.map +1 -0
  54. package/dist/assets/app/messages-CNwSh0t7.js +4 -0
  55. package/dist/assets/app/messages-CNwSh0t7.js.map +1 -0
  56. package/dist/assets/app/messages-CSMNJ6P8.js +4 -0
  57. package/dist/assets/app/messages-CSMNJ6P8.js.map +1 -0
  58. package/dist/assets/app/messages-CZQUw3mp.js +4 -0
  59. package/dist/assets/app/messages-CZQUw3mp.js.map +1 -0
  60. package/dist/assets/app/messages-CZT41oVp.js +4 -0
  61. package/dist/assets/app/messages-CZT41oVp.js.map +1 -0
  62. package/dist/assets/app/messages-C_b-d3t8.js +4 -0
  63. package/dist/assets/app/messages-C_b-d3t8.js.map +1 -0
  64. package/dist/assets/app/messages-C_u3MTc2.js +4 -0
  65. package/dist/assets/app/messages-C_u3MTc2.js.map +1 -0
  66. package/dist/assets/app/messages-Cn8nHZic.js +4 -0
  67. package/dist/assets/app/messages-Cn8nHZic.js.map +1 -0
  68. package/dist/assets/app/messages-CtDywJUm.js +4 -0
  69. package/dist/assets/app/messages-CtDywJUm.js.map +1 -0
  70. package/dist/assets/app/messages-CurtIjBF.js +4 -0
  71. package/dist/assets/app/messages-CurtIjBF.js.map +1 -0
  72. package/dist/assets/app/messages-Cv6zIbaP.js +4 -0
  73. package/dist/assets/app/messages-Cv6zIbaP.js.map +1 -0
  74. package/dist/assets/app/messages-D1eLQuPE.js +4 -0
  75. package/dist/assets/app/messages-D1eLQuPE.js.map +1 -0
  76. package/dist/assets/app/messages-D8vHEaYW.js +4 -0
  77. package/dist/assets/app/messages-D8vHEaYW.js.map +1 -0
  78. package/dist/assets/app/messages-DJ1Q4GeC.js +4 -0
  79. package/dist/assets/app/messages-DJ1Q4GeC.js.map +1 -0
  80. package/dist/assets/app/messages-DRL3exqd.js +4 -0
  81. package/dist/assets/app/messages-DRL3exqd.js.map +1 -0
  82. package/dist/assets/app/messages-DWLPQRTp.js +4 -0
  83. package/dist/assets/app/messages-DWLPQRTp.js.map +1 -0
  84. package/dist/assets/app/messages-DjVaE9YE.js +4 -0
  85. package/dist/assets/app/messages-DjVaE9YE.js.map +1 -0
  86. package/dist/assets/app/messages-DqpMfFJR.js +4 -0
  87. package/dist/assets/app/messages-DqpMfFJR.js.map +1 -0
  88. package/dist/assets/app/messages-ETjhJBEN.js +4 -0
  89. package/dist/assets/app/messages-ETjhJBEN.js.map +1 -0
  90. package/dist/assets/app/messages-EUKrgrGn.js +4 -0
  91. package/dist/assets/app/messages-EUKrgrGn.js.map +1 -0
  92. package/dist/assets/app/messages-QQrOUcPW.js +4 -0
  93. package/dist/assets/app/messages-QQrOUcPW.js.map +1 -0
  94. package/dist/assets/app/messages-e2QGqFL6.js +4 -0
  95. package/dist/assets/app/messages-e2QGqFL6.js.map +1 -0
  96. package/dist/assets/app/messages-p61py7gD.js +4 -0
  97. package/dist/assets/app/messages-p61py7gD.js.map +1 -0
  98. package/dist/assets/asset.d.ts +1 -0
  99. package/dist/assets/asset.d.ts.map +1 -1
  100. package/dist/assets/assets-middleware.d.ts.map +1 -1
  101. package/dist/assets/assets-middleware.js +12 -7
  102. package/dist/assets/assets-middleware.js.map +1 -1
  103. package/dist/assets/index.d.ts +3 -2
  104. package/dist/assets/index.d.ts.map +1 -1
  105. package/dist/assets/index.js +13 -1
  106. package/dist/assets/index.js.map +1 -1
  107. package/dist/client/client-store.d.ts +3 -3
  108. package/dist/client/client-store.d.ts.map +1 -1
  109. package/dist/client/client-store.js +6 -5
  110. package/dist/client/client-store.js.map +1 -1
  111. package/dist/device/device-manager.d.ts +12 -13
  112. package/dist/device/device-manager.d.ts.map +1 -1
  113. package/dist/device/device-manager.js +5 -3
  114. package/dist/device/device-manager.js.map +1 -1
  115. package/dist/device/device-store.d.ts +3 -3
  116. package/dist/device/device-store.d.ts.map +1 -1
  117. package/dist/device/device-store.js +10 -9
  118. package/dist/device/device-store.js.map +1 -1
  119. package/dist/dpop/dpop-manager.d.ts +15 -7
  120. package/dist/dpop/dpop-manager.d.ts.map +1 -1
  121. package/dist/dpop/dpop-manager.js +17 -3
  122. package/dist/dpop/dpop-manager.js.map +1 -1
  123. package/dist/dpop/dpop-nonce.d.ts +11 -5
  124. package/dist/dpop/dpop-nonce.d.ts.map +1 -1
  125. package/dist/dpop/dpop-nonce.js +47 -38
  126. package/dist/dpop/dpop-nonce.js.map +1 -1
  127. package/dist/errors/handle-unavailable-error.d.ts +11 -0
  128. package/dist/errors/handle-unavailable-error.d.ts.map +1 -0
  129. package/dist/errors/handle-unavailable-error.js +19 -0
  130. package/dist/errors/handle-unavailable-error.js.map +1 -0
  131. package/dist/errors/invalid-request-error.d.ts +6 -8
  132. package/dist/errors/invalid-request-error.d.ts.map +1 -1
  133. package/dist/errors/invalid-request-error.js +10 -8
  134. package/dist/errors/invalid-request-error.js.map +1 -1
  135. package/dist/lib/csp/index.d.ts +18 -0
  136. package/dist/lib/csp/index.d.ts.map +1 -0
  137. package/dist/lib/csp/index.js +72 -0
  138. package/dist/lib/csp/index.js.map +1 -0
  139. package/dist/lib/hcaptcha.d.ts +177 -0
  140. package/dist/lib/hcaptcha.d.ts.map +1 -0
  141. package/dist/lib/hcaptcha.js +155 -0
  142. package/dist/lib/hcaptcha.js.map +1 -0
  143. package/dist/lib/html/build-document.d.ts +11 -3
  144. package/dist/lib/html/build-document.d.ts.map +1 -1
  145. package/dist/lib/html/build-document.js +51 -15
  146. package/dist/lib/html/build-document.js.map +1 -1
  147. package/dist/lib/http/middleware.d.ts.map +1 -1
  148. package/dist/lib/http/middleware.js +4 -1
  149. package/dist/lib/http/middleware.js.map +1 -1
  150. package/dist/lib/http/request.d.ts +18 -3
  151. package/dist/lib/http/request.d.ts.map +1 -1
  152. package/dist/lib/http/request.js +56 -23
  153. package/dist/lib/http/request.js.map +1 -1
  154. package/dist/lib/http/response.d.ts +4 -2
  155. package/dist/lib/http/response.d.ts.map +1 -1
  156. package/dist/lib/http/response.js +23 -5
  157. package/dist/lib/http/response.js.map +1 -1
  158. package/dist/lib/locale.d.ts +15 -0
  159. package/dist/lib/locale.d.ts.map +1 -0
  160. package/dist/lib/locale.js +17 -0
  161. package/dist/lib/locale.js.map +1 -0
  162. package/dist/lib/util/function.d.ts +2 -2
  163. package/dist/lib/util/function.d.ts.map +1 -1
  164. package/dist/lib/util/function.js.map +1 -1
  165. package/dist/lib/util/type.d.ts +88 -1
  166. package/dist/lib/util/type.d.ts.map +1 -1
  167. package/dist/lib/util/type.js +41 -0
  168. package/dist/lib/util/type.js.map +1 -1
  169. package/dist/metadata/build-metadata.d.ts +2 -2
  170. package/dist/metadata/build-metadata.d.ts.map +1 -1
  171. package/dist/metadata/build-metadata.js.map +1 -1
  172. package/dist/oauth-errors.d.ts +1 -0
  173. package/dist/oauth-errors.d.ts.map +1 -1
  174. package/dist/oauth-errors.js +3 -1
  175. package/dist/oauth-errors.js.map +1 -1
  176. package/dist/oauth-hooks.d.ts +60 -3
  177. package/dist/oauth-hooks.d.ts.map +1 -1
  178. package/dist/oauth-hooks.js +3 -3
  179. package/dist/oauth-hooks.js.map +1 -1
  180. package/dist/oauth-provider.d.ts +28 -22
  181. package/dist/oauth-provider.d.ts.map +1 -1
  182. package/dist/oauth-provider.js +212 -211
  183. package/dist/oauth-provider.js.map +1 -1
  184. package/dist/oauth-verifier.d.ts +1 -1
  185. package/dist/oauth-verifier.d.ts.map +1 -1
  186. package/dist/oauth-verifier.js +2 -1
  187. package/dist/oauth-verifier.js.map +1 -1
  188. package/dist/output/build-authorize-data.d.ts +0 -1
  189. package/dist/output/build-authorize-data.d.ts.map +1 -1
  190. package/dist/output/build-authorize-data.js +0 -1
  191. package/dist/output/build-authorize-data.js.map +1 -1
  192. package/dist/output/build-customization-data.d.ts +232 -0
  193. package/dist/output/build-customization-data.d.ts.map +1 -0
  194. package/dist/output/build-customization-data.js +145 -0
  195. package/dist/output/build-customization-data.js.map +1 -0
  196. package/dist/output/output-manager.d.ts +16 -9
  197. package/dist/output/output-manager.d.ts.map +1 -1
  198. package/dist/output/output-manager.js +78 -42
  199. package/dist/output/output-manager.js.map +1 -1
  200. package/dist/output/send-authorize-redirect.d.ts +9 -6
  201. package/dist/output/send-authorize-redirect.d.ts.map +1 -1
  202. package/dist/output/send-authorize-redirect.js +20 -14
  203. package/dist/output/send-authorize-redirect.js.map +1 -1
  204. package/dist/output/send-web-page.d.ts +7 -2
  205. package/dist/output/send-web-page.d.ts.map +1 -1
  206. package/dist/output/send-web-page.js +37 -21
  207. package/dist/output/send-web-page.js.map +1 -1
  208. package/dist/request/request-manager.d.ts +1 -1
  209. package/dist/request/request-manager.d.ts.map +1 -1
  210. package/dist/request/request-manager.js +4 -4
  211. package/dist/request/request-manager.js.map +1 -1
  212. package/dist/request/request-store.d.ts +3 -3
  213. package/dist/request/request-store.d.ts.map +1 -1
  214. package/dist/request/request-store.js +11 -10
  215. package/dist/request/request-store.js.map +1 -1
  216. package/dist/token/token-store.d.ts +4 -4
  217. package/dist/token/token-store.d.ts.map +1 -1
  218. package/dist/token/token-store.js +13 -12
  219. package/dist/token/token-store.js.map +1 -1
  220. package/package.json +46 -21
  221. package/rollup.config.js +61 -17
  222. package/src/account/account-manager.ts +159 -8
  223. package/src/account/account-store.ts +127 -32
  224. package/src/account/sign-in-data.ts +15 -0
  225. package/src/account/sign-up-data.ts +11 -0
  226. package/src/assets/app/app.tsx +31 -16
  227. package/src/assets/app/backend-data.ts +15 -60
  228. package/src/assets/app/backend-types.ts +66 -0
  229. package/src/assets/app/components/forms/button-toggle-visibility.tsx +43 -0
  230. package/src/assets/app/components/forms/button.tsx +60 -0
  231. package/src/assets/app/components/forms/fieldset.tsx +55 -0
  232. package/src/assets/app/components/forms/form-card-async.tsx +103 -0
  233. package/src/assets/app/components/forms/form-card.tsx +49 -0
  234. package/src/assets/app/components/forms/input-checkbox.tsx +73 -0
  235. package/src/assets/app/components/forms/input-container.tsx +107 -0
  236. package/src/assets/app/components/forms/input-email-address.tsx +66 -0
  237. package/src/assets/app/components/forms/input-new-password.tsx +62 -0
  238. package/src/assets/app/components/forms/input-password.tsx +88 -0
  239. package/src/assets/app/components/forms/input-text.tsx +76 -0
  240. package/src/assets/app/components/forms/input-token.tsx +94 -0
  241. package/src/assets/app/components/forms/wizard-card.tsx +116 -0
  242. package/src/assets/app/components/layouts/layout-title-page.tsx +77 -0
  243. package/src/assets/app/components/layouts/layout-welcome.tsx +73 -0
  244. package/src/assets/app/components/utils/account-identifier.tsx +23 -0
  245. package/src/assets/app/components/utils/account-image.tsx +33 -0
  246. package/src/assets/app/components/utils/admonition.tsx +52 -0
  247. package/src/assets/app/components/utils/client-name.tsx +45 -0
  248. package/src/assets/app/components/utils/error-card.tsx +93 -0
  249. package/src/assets/app/components/utils/error-message.tsx +62 -0
  250. package/src/assets/app/components/utils/help-card.tsx +46 -0
  251. package/src/assets/app/components/utils/icons.tsx +88 -0
  252. package/src/assets/app/components/utils/link-anchor.tsx +28 -0
  253. package/src/assets/app/components/utils/link-title.tsx +26 -0
  254. package/src/assets/app/components/utils/multi-lang-string.tsx +56 -0
  255. package/src/assets/app/components/utils/password-strength-label.tsx +37 -0
  256. package/src/assets/app/components/utils/password-strength-meter.tsx +58 -0
  257. package/src/assets/app/components/{url-viewer.tsx → utils/url-viewer.tsx} +9 -6
  258. package/src/assets/app/hooks/use-api.ts +128 -55
  259. package/src/assets/app/hooks/use-async-action.ts +120 -0
  260. package/src/assets/app/hooks/use-browser-color-scheme.ts +31 -0
  261. package/src/assets/app/hooks/use-csrf-token.ts +1 -1
  262. package/src/assets/app/hooks/use-random-string.ts +37 -0
  263. package/src/assets/app/hooks/use-stepper.ts +87 -0
  264. package/src/assets/app/index.html +182 -0
  265. package/src/assets/app/lib/api.ts +248 -79
  266. package/src/assets/app/lib/clsx.ts +5 -8
  267. package/src/assets/app/lib/json-client.ts +94 -0
  268. package/src/assets/app/lib/password.ts +98 -0
  269. package/src/assets/app/lib/ref.ts +17 -0
  270. package/src/assets/app/locales/an/messages.po +492 -0
  271. package/src/assets/app/locales/ast/messages.po +492 -0
  272. package/src/assets/app/locales/ca/messages.po +492 -0
  273. package/src/assets/app/locales/da/messages.po +492 -0
  274. package/src/assets/app/locales/de/messages.po +492 -0
  275. package/src/assets/app/locales/el/messages.po +492 -0
  276. package/src/assets/app/locales/en/messages.po +492 -0
  277. package/src/assets/app/locales/en-GB/messages.po +492 -0
  278. package/src/assets/app/locales/es/messages.po +492 -0
  279. package/src/assets/app/locales/eu/messages.po +492 -0
  280. package/src/assets/app/locales/fi/messages.po +492 -0
  281. package/src/assets/app/locales/fr/messages.po +492 -0
  282. package/src/assets/app/locales/ga/messages.po +492 -0
  283. package/src/assets/app/locales/gl/messages.po +492 -0
  284. package/src/assets/app/locales/hi/messages.po +492 -0
  285. package/src/assets/app/locales/hu/messages.po +492 -0
  286. package/src/assets/app/locales/ia/messages.po +492 -0
  287. package/src/assets/app/locales/id/messages.po +492 -0
  288. package/src/assets/app/locales/it/messages.po +492 -0
  289. package/src/assets/app/locales/ja/messages.po +492 -0
  290. package/src/assets/app/locales/km/messages.po +492 -0
  291. package/src/assets/app/locales/ko/messages.po +492 -0
  292. package/src/assets/app/locales/load.ts +8 -0
  293. package/src/assets/app/locales/locale-context.ts +19 -0
  294. package/src/assets/app/locales/locale-provider.tsx +112 -0
  295. package/src/assets/app/locales/locale-selector.tsx +58 -0
  296. package/src/assets/app/locales/locales.ts +168 -0
  297. package/src/assets/app/locales/ne/messages.po +492 -0
  298. package/src/assets/app/locales/nl/messages.po +492 -0
  299. package/src/assets/app/locales/pl/messages.po +492 -0
  300. package/src/assets/app/locales/pt-BR/messages.po +492 -0
  301. package/src/assets/app/locales/ro/messages.po +492 -0
  302. package/src/assets/app/locales/ru/messages.po +492 -0
  303. package/src/assets/app/locales/sv/messages.po +492 -0
  304. package/src/assets/app/locales/th/messages.po +492 -0
  305. package/src/assets/app/locales/tr/messages.po +492 -0
  306. package/src/assets/app/locales/uk/messages.po +492 -0
  307. package/src/assets/app/locales/vi/messages.po +492 -0
  308. package/src/assets/app/locales/zh-CN/messages.po +492 -0
  309. package/src/assets/app/locales/zh-HK/messages.po +492 -0
  310. package/src/assets/app/locales/zh-TW/messages.po +492 -0
  311. package/src/assets/app/main.css +23 -2
  312. package/src/assets/app/main.tsx +24 -8
  313. package/src/assets/app/views/authorize/accept/accept-form.tsx +150 -0
  314. package/src/assets/app/views/authorize/accept/accept-view.tsx +70 -0
  315. package/src/assets/app/views/authorize/authorize-view.tsx +180 -0
  316. package/src/assets/app/views/authorize/reset-password/reset-password-confirm-form.tsx +88 -0
  317. package/src/assets/app/views/authorize/reset-password/reset-password-request-form.tsx +80 -0
  318. package/src/assets/app/views/authorize/reset-password/reset-password-view.tsx +127 -0
  319. package/src/assets/app/views/authorize/sign-in/sign-in-form.tsx +244 -0
  320. package/src/assets/app/views/authorize/sign-in/sign-in-picker.tsx +116 -0
  321. package/src/assets/app/views/authorize/sign-in/sign-in-view.tsx +145 -0
  322. package/src/assets/app/views/authorize/sign-up/sign-up-account-form.tsx +140 -0
  323. package/src/assets/app/views/authorize/sign-up/sign-up-disclaimer.tsx +51 -0
  324. package/src/assets/app/views/authorize/sign-up/sign-up-handle-form.tsx +289 -0
  325. package/src/assets/app/views/authorize/sign-up/sign-up-hcaptcha-form.tsx +108 -0
  326. package/src/assets/app/views/authorize/sign-up/sign-up-view.tsx +158 -0
  327. package/src/assets/app/views/authorize/welcome/welcome-view.tsx +56 -0
  328. package/src/assets/app/views/error/error-view.tsx +31 -0
  329. package/src/assets/asset.ts +1 -0
  330. package/src/assets/assets-middleware.ts +13 -8
  331. package/src/assets/index.ts +15 -2
  332. package/src/client/client-store.ts +10 -12
  333. package/src/device/device-manager.ts +14 -15
  334. package/src/device/device-store.ts +9 -15
  335. package/src/dpop/dpop-manager.ts +20 -8
  336. package/src/dpop/dpop-nonce.ts +58 -40
  337. package/src/errors/handle-unavailable-error.ts +18 -0
  338. package/src/errors/invalid-request-error.ts +10 -8
  339. package/src/lib/csp/index.ts +98 -0
  340. package/src/lib/hcaptcha.ts +182 -0
  341. package/src/lib/html/build-document.ts +60 -16
  342. package/src/lib/http/middleware.ts +4 -3
  343. package/src/lib/http/request.ts +81 -28
  344. package/src/lib/http/response.ts +22 -9
  345. package/src/lib/locale.ts +21 -0
  346. package/src/lib/util/function.ts +0 -3
  347. package/src/lib/util/type.ts +130 -1
  348. package/src/metadata/build-metadata.ts +2 -1
  349. package/src/oauth-errors.ts +1 -0
  350. package/src/oauth-hooks.ts +69 -3
  351. package/src/oauth-provider.ts +410 -315
  352. package/src/oauth-verifier.ts +3 -1
  353. package/src/output/build-authorize-data.ts +1 -3
  354. package/src/output/build-customization-data.ts +189 -0
  355. package/src/output/output-manager.ts +111 -48
  356. package/src/output/send-authorize-redirect.ts +43 -36
  357. package/src/output/send-web-page.ts +40 -26
  358. package/src/request/request-manager.ts +4 -4
  359. package/src/request/request-store.ts +12 -16
  360. package/src/token/token-store.ts +14 -18
  361. package/tailwind.config.js +5 -0
  362. package/tsconfig.backend.tsbuildinfo +1 -1
  363. package/tsconfig.frontend.tsbuildinfo +1 -1
  364. package/tsconfig.tools.tsbuildinfo +1 -1
  365. package/vite.config.mjs +16 -0
  366. package/.postcssrc.yml +0 -3
  367. package/dist/assets/app/main.css +0 -3
  368. package/dist/assets/app/main.js +0 -20
  369. package/dist/assets/app/main.js.map +0 -1
  370. package/dist/output/customization.d.ts +0 -27
  371. package/dist/output/customization.d.ts.map +0 -1
  372. package/dist/output/customization.js +0 -88
  373. package/dist/output/customization.js.map +0 -1
  374. package/src/assets/app/components/accept-form.tsx +0 -137
  375. package/src/assets/app/components/account-identifier.tsx +0 -18
  376. package/src/assets/app/components/account-picker.tsx +0 -127
  377. package/src/assets/app/components/button.tsx +0 -34
  378. package/src/assets/app/components/client-name.tsx +0 -37
  379. package/src/assets/app/components/fieldset.tsx +0 -26
  380. package/src/assets/app/components/form-card.tsx +0 -47
  381. package/src/assets/app/components/help-card.tsx +0 -42
  382. package/src/assets/app/components/icons/alert-icon.tsx +0 -5
  383. package/src/assets/app/components/icons/at-symbol-icon.tsx +0 -5
  384. package/src/assets/app/components/icons/caret-right-icon.tsx +0 -5
  385. package/src/assets/app/components/icons/lock-icon.tsx +0 -5
  386. package/src/assets/app/components/icons/token-icon.tsx +0 -5
  387. package/src/assets/app/components/icons/util.tsx +0 -17
  388. package/src/assets/app/components/info-card.tsx +0 -45
  389. package/src/assets/app/components/input-checkbox.tsx +0 -47
  390. package/src/assets/app/components/input-container.tsx +0 -37
  391. package/src/assets/app/components/input-layout.tsx +0 -47
  392. package/src/assets/app/components/input-text.tsx +0 -69
  393. package/src/assets/app/components/layout-title-page.tsx +0 -60
  394. package/src/assets/app/components/layout-welcome.tsx +0 -74
  395. package/src/assets/app/components/sign-in-form.tsx +0 -337
  396. package/src/assets/app/components/sign-up-account-form.tsx +0 -194
  397. package/src/assets/app/components/sign-up-disclaimer.tsx +0 -44
  398. package/src/assets/app/views/accept-view.tsx +0 -55
  399. package/src/assets/app/views/authorize-view.tsx +0 -106
  400. package/src/assets/app/views/error-view.tsx +0 -36
  401. package/src/assets/app/views/sign-in-view.tsx +0 -111
  402. package/src/assets/app/views/sign-up-view.tsx +0 -86
  403. package/src/assets/app/views/welcome-view.tsx +0 -54
  404. package/src/output/customization.ts +0 -118
@@ -0,0 +1,94 @@
1
+ import { useLingui } from '@lingui/react/macro'
2
+ import { ChangeEvent, useState } from 'react'
3
+ import { Override } from '../../lib/util.ts'
4
+ import { TokenIcon } from '../utils/icons.tsx'
5
+ import { InputText, InputTextProps } from './input-text.tsx'
6
+
7
+ export type InputTokenProps = Override<
8
+ Omit<
9
+ InputTextProps,
10
+ | 'type'
11
+ | 'pattern'
12
+ | 'autoCapitalize'
13
+ | 'autoCorrect'
14
+ | 'autoComplete'
15
+ | 'spellCheck'
16
+ | 'minLength'
17
+ | 'maxLength'
18
+ | 'placeholder'
19
+ | 'dir'
20
+ >,
21
+ {
22
+ example?: string
23
+ onToken?: (code: string | null) => void
24
+ }
25
+ >
26
+
27
+ export const OTP_CODE_EXAMPLE = 'XXXXX-XXXXX'
28
+
29
+ export function InputToken({
30
+ example = OTP_CODE_EXAMPLE,
31
+ onToken,
32
+
33
+ // InputTextProps
34
+ icon = <TokenIcon className="w-5" />,
35
+ title = example,
36
+ onChange,
37
+ value,
38
+ defaultValue = value,
39
+ ...props
40
+ }: InputTokenProps) {
41
+ const { t } = useLingui()
42
+ const [token, setToken] = useState<string>(
43
+ typeof defaultValue === 'string' ? defaultValue : '',
44
+ )
45
+
46
+ return (
47
+ <InputText
48
+ {...props}
49
+ type="text"
50
+ autoCapitalize="none"
51
+ autoCorrect="off"
52
+ autoComplete="off"
53
+ spellCheck="false"
54
+ minLength={11}
55
+ maxLength={11}
56
+ dir="auto"
57
+ icon={icon}
58
+ pattern="^[A-Z2-7]{5}-[A-Z2-7]{5}$"
59
+ placeholder={t`Looks like ${example}`}
60
+ title={title}
61
+ value={token}
62
+ onChange={(event: ChangeEvent<HTMLInputElement>) => {
63
+ const { value, selectionEnd, selectionStart } = event.currentTarget
64
+
65
+ const fixedValue = fix(value)
66
+
67
+ event.currentTarget.value = fixedValue
68
+
69
+ // Move the cursor back where it was relative to the original value
70
+ const pos = selectionEnd ?? selectionStart
71
+ if (pos != null) {
72
+ const fixedSlicedValue = fix(value.slice(0, pos))
73
+ event.currentTarget.selectionStart =
74
+ event.currentTarget.selectionEnd = fixedSlicedValue.length
75
+ }
76
+
77
+ setToken(fixedValue)
78
+ onChange?.(event)
79
+
80
+ if (!event.isDefaultPrevented()) {
81
+ onToken?.(fixedValue.length === 11 ? fixedValue : null)
82
+ }
83
+ }}
84
+ />
85
+ )
86
+ }
87
+
88
+ function fix(value: string) {
89
+ const normalized = value.toUpperCase().replaceAll(/[^A-Z2-7]/g, '')
90
+
91
+ if (normalized.length <= 5) return normalized
92
+
93
+ return `${normalized.slice(0, 5)}-${normalized.slice(5, 10)}`
94
+ }
@@ -0,0 +1,116 @@
1
+ import { Trans } from '@lingui/react/macro'
2
+ import { JSX, ReactNode, useCallback } from 'react'
3
+ import { DisabledStep, Step, useStepper } from '../../hooks/use-stepper.ts'
4
+ import { clsx } from '../../lib/clsx.ts'
5
+ import { Override } from '../../lib/util.ts'
6
+
7
+ export type DoneFn = (...a: any) => unknown
8
+
9
+ export type WizardRenderProps<TDone extends DoneFn> = {
10
+ /**
11
+ * Indicates wether the render function being invoked corresponds to the step
12
+ * currently active. The steps titles could, for example, be rendered in a
13
+ * list of links, where the current step is highlighted (based on `current`).
14
+ *
15
+ * Another use for this is to render the next/previous steps in order to
16
+ * provide animated transitions between steps. In this case, `current` would
17
+ * be used to disable any form interaction with the form transitioning in/out.
18
+ */
19
+ current: boolean
20
+ invalid: boolean
21
+
22
+ prev?: () => void
23
+ prevLabel: ReactNode
24
+
25
+ // On the last step, the "next()" function will actually be the done function
26
+ next: (() => void) | TDone
27
+ nextLabel: ReactNode
28
+ }
29
+
30
+ export type WizardRenderFn<TDone extends DoneFn> = (
31
+ data: WizardRenderProps<TDone>,
32
+ ) => ReactNode
33
+
34
+ export type WizardStep<TDone extends DoneFn> = Step & {
35
+ titleRender?: WizardRenderFn<TDone>
36
+ contentRender: WizardRenderFn<TDone>
37
+ }
38
+
39
+ export type WizardCardProps<TDone extends DoneFn> = Override<
40
+ Omit<JSX.IntrinsicElements['div'], 'children'>,
41
+ {
42
+ prevLabel?: ReactNode
43
+ nextLabel?: ReactNode
44
+
45
+ onBack?: () => void
46
+ backLabel?: ReactNode
47
+
48
+ onDone: TDone
49
+ doneLabel?: ReactNode
50
+
51
+ steps: readonly (WizardStep<TDone> | DisabledStep)[]
52
+ }
53
+ >
54
+
55
+ export function WizardCard<TDone extends DoneFn>({
56
+ prevLabel,
57
+ nextLabel,
58
+
59
+ onBack,
60
+ backLabel,
61
+
62
+ onDone,
63
+ doneLabel,
64
+
65
+ steps,
66
+ className,
67
+
68
+ ...props
69
+ }: WizardCardProps<TDone>) {
70
+ const {
71
+ atFirst,
72
+ atLast,
73
+ count,
74
+ current,
75
+ currentPosition,
76
+ completed,
77
+ toNext,
78
+ toPrev,
79
+ toRequired,
80
+ } = useStepper(steps)
81
+
82
+ // Memoized to avoid re-renders in child (rendered) components
83
+ const onNext = useCallback(() => {
84
+ // If already at last step, go to the first incomplete (required) step
85
+ if (!toNext()) toRequired()
86
+ }, [toNext, toRequired])
87
+
88
+ const data: WizardRenderProps<TDone> = {
89
+ // The current UI only displays the current title & content.
90
+ current: true,
91
+ invalid: current ? current.invalid : false,
92
+
93
+ prevLabel: (atFirst && backLabel) || prevLabel || <Trans>Back</Trans>,
94
+ prev: atFirst ? onBack : toPrev,
95
+
96
+ nextLabel: (atLast && doneLabel) || nextLabel || <Trans>Next</Trans>,
97
+ next: atLast && completed ? onDone : onNext,
98
+ }
99
+
100
+ const stepTitle = current?.titleRender?.(data)
101
+ const stepContent = current?.contentRender?.(data)
102
+
103
+ return (
104
+ <div className={clsx(className, 'flex flex-col')} {...props}>
105
+ <p className="text-slate-500 dark:text-slate-400">
106
+ <Trans>
107
+ Step {currentPosition} of {count}
108
+ </Trans>
109
+ </p>
110
+
111
+ {stepTitle && <h2 className="font-medium text-xl mb-4">{stepTitle}</h2>}
112
+
113
+ {stepContent}
114
+ </div>
115
+ )
116
+ }
@@ -0,0 +1,77 @@
1
+ import { JSX, ReactNode } from 'react'
2
+ import { clsx } from '../../lib/clsx.ts'
3
+ import { Override } from '../../lib/util.ts'
4
+ import { LocaleSelector } from '../../locales/locale-selector.tsx'
5
+
6
+ export type LayoutTitlePageProps = Override<
7
+ JSX.IntrinsicElements['div'],
8
+ {
9
+ title?: string
10
+ subtitle?: ReactNode
11
+ children?: ReactNode
12
+ }
13
+ >
14
+
15
+ export function LayoutTitlePage({
16
+ children,
17
+ title,
18
+ subtitle,
19
+
20
+ // HTMLDivElement
21
+ className,
22
+ ...props
23
+ }: LayoutTitlePageProps) {
24
+ return (
25
+ <div
26
+ {...props}
27
+ className={clsx(
28
+ className,
29
+ 'flex flex-col items-center',
30
+ 'md:flex md:flex-row md:justify-stretch md:items-center',
31
+ 'min-h-screen min-w-screen',
32
+ 'bg-white text-slate-900',
33
+ 'dark:bg-slate-900 dark:text-slate-100',
34
+ )}
35
+ >
36
+ {title && <title>{title}</title>}
37
+
38
+ <div
39
+ className={clsx(
40
+ 'px-6 pt-4',
41
+ 'w-full',
42
+ 'md:max-w-lg',
43
+ 'flex flex-row md:flex-col',
44
+ 'md:self-stretch',
45
+ 'md:w-1/2 md:max-w-fix md:p-4',
46
+ 'md:text-right',
47
+ 'md:dark:border-r md:dark:border-slate-700',
48
+ 'md:bg-slate-100 md:dark:bg-slate-800',
49
+ )}
50
+ >
51
+ <div className="flex-grow grid content-center md:justify-items-end">
52
+ {title && (
53
+ <h1
54
+ key="title"
55
+ className="text-xl md:text-2xl lg:text-5xl md:my-4 font-semibold text-brand"
56
+ >
57
+ {title}
58
+ </h1>
59
+ )}
60
+
61
+ {subtitle && (
62
+ <p
63
+ key="subtitle"
64
+ className="hidden md:block max-w-xs text-slate-600 dark:text-slate-400"
65
+ >
66
+ {subtitle}
67
+ </p>
68
+ )}
69
+ </div>
70
+
71
+ <LocaleSelector key="localeSelector" className="m-1 md:m-2" />
72
+ </div>
73
+
74
+ <main className="w-full p-6 md:max-w-3xl md:px-12">{children}</main>
75
+ </div>
76
+ )
77
+ }
@@ -0,0 +1,73 @@
1
+ import { JSX } from 'react'
2
+ import { CustomizationData } from '../../backend-types.ts'
3
+ import { clsx } from '../../lib/clsx.ts'
4
+ import { Override } from '../../lib/util.ts'
5
+ import { LocaleSelector } from '../../locales/locale-selector.tsx'
6
+ import { LinkAnchor } from '../utils/link-anchor.tsx'
7
+
8
+ export type LayoutWelcomeProps = Override<
9
+ JSX.IntrinsicElements['div'],
10
+ {
11
+ customizationData: CustomizationData | undefined
12
+ title?: string
13
+ }
14
+ >
15
+
16
+ export function LayoutWelcome({
17
+ customizationData: { logo, name, links } = {},
18
+ title = name,
19
+
20
+ // div
21
+ className,
22
+ children,
23
+ ...props
24
+ }: LayoutWelcomeProps) {
25
+ return (
26
+ <div
27
+ {...props}
28
+ className={clsx(
29
+ 'min-h-screen w-full',
30
+ 'flex items-center justify-center flex-col',
31
+ 'bg-white text-slate-900',
32
+ 'dark:bg-slate-900 dark:text-slate-100',
33
+ className,
34
+ )}
35
+ >
36
+ {title && <title>{title}</title>}
37
+
38
+ <main className="w-full overflow-hidden flex-grow flex flex-col items-center justify-center p-6">
39
+ {logo && (
40
+ <img
41
+ src={logo}
42
+ alt={name || `Logo`}
43
+ aria-hidden
44
+ className="w-16 h-16 md:w-24 md:h-24 mb-4 md:mb-8"
45
+ />
46
+ )}
47
+
48
+ {name && (
49
+ <h1 className="text-2xl md:text-4xl mb-4 md:mb-8 mx-4 text-center font-bold">
50
+ {name}
51
+ </h1>
52
+ )}
53
+
54
+ {children}
55
+ </main>
56
+
57
+ <nav className="w-full overflow-hidden border-t border-t-slate-200 dark:border-t-slate-700 flex flex-wrap justify-center content-center">
58
+ {links?.map((link, i) => (
59
+ <LinkAnchor
60
+ key={i}
61
+ link={link}
62
+ className="m-2 md:m-4 text-xs md:text-sm text-brand hover:underline"
63
+ />
64
+ ))}
65
+
66
+ <LocaleSelector
67
+ className="m-1 md:m-2 text-xs md:text-sm"
68
+ key="localeSelector"
69
+ />
70
+ </nav>
71
+ </div>
72
+ )
73
+ }
@@ -0,0 +1,23 @@
1
+ import { JSX } from 'react'
2
+ import { Account } from '../../backend-types.ts'
3
+ import { Override } from '../../lib/util.ts'
4
+
5
+ export type AccountIdentifierProps = Override<
6
+ Omit<JSX.IntrinsicElements['b'], 'children'>,
7
+ {
8
+ account: Account
9
+ }
10
+ >
11
+
12
+ export function AccountIdentifier({
13
+ account,
14
+
15
+ // b
16
+ ...props
17
+ }: AccountIdentifierProps) {
18
+ return (
19
+ <b {...props}>
20
+ {account.preferred_username || account.email || account.sub}
21
+ </b>
22
+ )
23
+ }
@@ -0,0 +1,33 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { AccountIcon } from './icons.tsx'
3
+
4
+ export type AccountIconProps = {
5
+ src?: string
6
+ alt: string
7
+ }
8
+
9
+ export function AccountImage({ src, alt }: AccountIconProps) {
10
+ const [errored, setErrored] = useState(false)
11
+
12
+ useEffect(() => {
13
+ setErrored(false)
14
+ }, [src])
15
+
16
+ return src && !errored ? (
17
+ <img
18
+ aria-hidden
19
+ crossOrigin="anonymous"
20
+ src={src}
21
+ alt={alt}
22
+ className="-ml-1 w-6 h-6 rounded-full"
23
+ onError={() => setErrored(true)}
24
+ />
25
+ ) : (
26
+ <div
27
+ aria-hidden
28
+ className="h-6 w-6 text-white bg-brand rounded-full border-solid border-2 border-brand overflow-hidden"
29
+ >
30
+ <AccountIcon className="-mx-1 -mb-1" />
31
+ </div>
32
+ )
33
+ }
@@ -0,0 +1,52 @@
1
+ import { JSX, memo } from 'react'
2
+ import { clsx } from '../../lib/clsx.ts'
3
+ import { Override } from '../../lib/util.ts'
4
+ import { AlertIcon, EyeIcon } from './icons.tsx'
5
+
6
+ export type AdmonitionProps = Override<
7
+ JSX.IntrinsicElements['div'],
8
+ {
9
+ role: 'alert' | 'status' | 'info'
10
+ }
11
+ >
12
+
13
+ export const Admonition = memo(function Admonition({
14
+ role = 'alert',
15
+ children,
16
+ className,
17
+ ...props
18
+ }: AdmonitionProps) {
19
+ return (
20
+ <div
21
+ {...props}
22
+ role={role}
23
+ className={clsx(
24
+ 'flex flex-row',
25
+ 'gap-2',
26
+ 'p-3',
27
+ 'rounded-lg',
28
+ 'border',
29
+ 'border-gray-300 dark:border-gray-700',
30
+ role === 'alert' && 'bg-error text-error-c',
31
+ className,
32
+ )}
33
+ >
34
+ {role === 'info' ? (
35
+ <EyeIcon
36
+ aria-hidden
37
+ className={clsx('fill-current h-6 w-6', 'text-brand')}
38
+ />
39
+ ) : (
40
+ <AlertIcon
41
+ aria-hidden
42
+ className={clsx(
43
+ 'fill-current h-6 w-6',
44
+ role === 'alert' ? 'text-inherit' : 'text-brand',
45
+ )}
46
+ />
47
+ )}
48
+
49
+ <div className="flex flex-1 flex-col">{children}</div>
50
+ </div>
51
+ )
52
+ })
@@ -0,0 +1,45 @@
1
+ import { Trans } from '@lingui/react/macro'
2
+ import { JSX } from 'react'
3
+ import type { OAuthClientMetadata } from '@atproto/oauth-types'
4
+ import { Override } from '../../lib/util.ts'
5
+ import { UrlViewer } from './url-viewer.tsx'
6
+
7
+ export type ClientNameProps = Override<
8
+ Omit<JSX.IntrinsicElements['span'], 'children'>,
9
+ {
10
+ clientId: string
11
+ clientMetadata: OAuthClientMetadata
12
+ clientTrusted: boolean
13
+ }
14
+ >
15
+
16
+ export function ClientName({
17
+ clientId,
18
+ clientMetadata,
19
+ clientTrusted,
20
+
21
+ // span
22
+ ...attrs
23
+ }: ClientNameProps) {
24
+ if (clientTrusted && clientMetadata.client_name) {
25
+ return <span {...attrs}>{clientMetadata.client_name}</span>
26
+ }
27
+
28
+ // @NOTE: not using isOAuthClientIdLoopback & isOAuthClientIdDiscoverable from
29
+ // @atproto/oauth-types here because 1) we don't need to validate here and 2)
30
+ // we prefer not to import un-necessary code to improve bundle size.
31
+
32
+ if (clientId.startsWith('http://')) {
33
+ return (
34
+ <span {...attrs}>
35
+ <Trans>An application on your device</Trans>
36
+ </span>
37
+ )
38
+ }
39
+
40
+ if (clientId.startsWith('https://')) {
41
+ return <UrlViewer {...attrs} url={clientId} path />
42
+ }
43
+
44
+ return <span {...attrs}>{clientId}</span>
45
+ }
@@ -0,0 +1,93 @@
1
+ import { Trans } from '@lingui/react/macro'
2
+ import { memo, useEffect, useMemo, useState } from 'react'
3
+ import { useRandomString } from '../../hooks/use-random-string.ts'
4
+ import { Api } from '../../lib/api.ts'
5
+ import { JsonErrorResponse } from '../../lib/json-client.ts'
6
+ import { Override } from '../../lib/util.ts'
7
+ import { Admonition, AdmonitionProps } from './admonition.tsx'
8
+ import { ErrorMessage } from './error-message.tsx'
9
+
10
+ export type ErrorCardProps = Override<
11
+ Omit<AdmonitionProps, 'role'>,
12
+ {
13
+ error: unknown
14
+ }
15
+ >
16
+ export const ErrorCard = memo(function ErrorCard({
17
+ error,
18
+
19
+ // Admonition
20
+ children,
21
+ onClick,
22
+ onKeyDown,
23
+ ...props
24
+ }: ErrorCardProps) {
25
+ const [inputCount, setInputCount] = useState(0)
26
+ // Every 5th input will toggle showing the details
27
+ const showDetails = ((inputCount / 5) | 0) % 2 === 1
28
+
29
+ const detailsDivId = useRandomString('error-card-')
30
+
31
+ const parsedError = useMemo(
32
+ () =>
33
+ error instanceof JsonErrorResponse
34
+ ? // Already parsed:
35
+ error
36
+ : // If "error" is a json object, try parsing it as a JsonErrorResponse:
37
+ Api.parseError(error) ?? error,
38
+ [error],
39
+ )
40
+
41
+ useEffect(() => {
42
+ // For debugging purposes
43
+ console.warn('Displayed error details:', parsedError)
44
+
45
+ // Reset the input count when the error changes
46
+ setInputCount(0)
47
+ }, [parsedError])
48
+
49
+ return (
50
+ <Admonition
51
+ role="alert"
52
+ aria-controls={detailsDivId}
53
+ tabIndex={0}
54
+ onKeyDown={(event) => {
55
+ onKeyDown?.(event)
56
+ if (!event.defaultPrevented) {
57
+ setInputCount((c) => c + 1)
58
+ }
59
+ }}
60
+ onClick={(event) => {
61
+ onClick?.(event)
62
+ if (!event.defaultPrevented) {
63
+ setInputCount((c) => c + 1)
64
+ }
65
+ }}
66
+ {...props}
67
+ >
68
+ <ErrorMessage error={parsedError} />
69
+
70
+ {children && <div className="mt-2">{children}</div>}
71
+
72
+ <div hidden={!showDetails} id={detailsDivId} aria-hidden={!showDetails}>
73
+ {parsedError instanceof JsonErrorResponse ? (
74
+ <dl className="mt-2 grid grid-cols-[auto,1fr] gap-x-2 text-sm">
75
+ <dt className="font-semibold">
76
+ <Trans>Code</Trans>
77
+ </dt>
78
+ <dd>
79
+ <code>{parsedError.error}</code>
80
+ </dd>
81
+
82
+ <dt className="font-semibold">
83
+ <Trans>Description</Trans>
84
+ </dt>
85
+ <dd>{parsedError.description}</dd>
86
+ </dl>
87
+ ) : (
88
+ <pre className="text-xs">{JSON.stringify(parsedError, null, 2)}</pre>
89
+ )}
90
+ </div>
91
+ </Admonition>
92
+ )
93
+ })
@@ -0,0 +1,62 @@
1
+ import { Trans } from '@lingui/react/macro'
2
+ import { ReactNode, memo } from 'react'
3
+ import {
4
+ EmailTakenError,
5
+ HandleUnavailableError,
6
+ InvalidCredentialsError,
7
+ RequestExpiredError,
8
+ SecondAuthenticationFactorRequiredError,
9
+ UnknownRequestUriError,
10
+ } from '../../lib/api.ts'
11
+ import { JsonErrorResponse } from '../../lib/json-client.ts'
12
+
13
+ export type ApiErrorMessageProps = {
14
+ error: unknown
15
+ }
16
+
17
+ export const ErrorMessage = memo(function ErrorMessage({
18
+ error,
19
+ }: ApiErrorMessageProps): ReactNode {
20
+ if (error instanceof InvalidCredentialsError) {
21
+ return <Trans>Wrong identifier or password</Trans>
22
+ }
23
+
24
+ if (error instanceof EmailTakenError) {
25
+ return <Trans>This email is already used</Trans>
26
+ }
27
+
28
+ if (error instanceof HandleUnavailableError) {
29
+ switch (error.reason) {
30
+ case 'syntax':
31
+ return <Trans>The handle is invalid</Trans>
32
+ case 'domain':
33
+ return <Trans>The domain name is not allowed</Trans>
34
+ case 'slur':
35
+ return <Trans>The handle contains inappropriate language</Trans>
36
+ case 'taken':
37
+ if (error.description === 'Reserved handle') {
38
+ return <Trans>This handle is reserved</Trans>
39
+ }
40
+ return <Trans>The handle is already in use</Trans>
41
+ default:
42
+ return <Trans>That handle cannot be used</Trans>
43
+ }
44
+ }
45
+
46
+ if (error instanceof SecondAuthenticationFactorRequiredError) {
47
+ return <Trans>A second authentication factor is required</Trans>
48
+ }
49
+
50
+ if (
51
+ error instanceof UnknownRequestUriError ||
52
+ error instanceof RequestExpiredError
53
+ ) {
54
+ return <Trans>This sign-in session has expired</Trans>
55
+ }
56
+
57
+ if (error instanceof JsonErrorResponse) {
58
+ return <Trans>Unexpected server response</Trans>
59
+ }
60
+
61
+ return <Trans>An unknown error occurred</Trans>
62
+ })