@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
@@ -1,25 +1,86 @@
1
+ import { isEmailValid } from '@hapi/address'
2
+ import { isDisposableEmail } from 'disposable-email-domains-js'
1
3
  import { z } from 'zod'
2
4
  import { ClientId } from '../client/client-id.js'
3
5
  import { DeviceId } from '../device/device-id.js'
4
- import { Awaitable } from '../lib/util/type.js'
6
+ import { localeSchema } from '../lib/locale.js'
7
+ import { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'
8
+ import {
9
+ HandleUnavailableError,
10
+ InvalidRequestError,
11
+ SecondAuthenticationFactorRequiredError,
12
+ } from '../oauth-errors.js'
5
13
  import { Sub } from '../oidc/sub.js'
6
14
  import { Account } from './account.js'
7
15
 
8
- export const signInCredentialsSchema = z.object({
9
- username: z.string(),
10
- password: z.string(),
16
+ // @NOTE Change the length here to force stronger passwords (through a reset)
17
+ export const oldPasswordSchema = z.string().min(1)
18
+ export const newPasswordSchema = z.string().min(8)
19
+ export const tokenSchema = z.string().regex(/^[A-Z2-7]{5}-[A-Z2-7]{5}$/)
20
+ export const handleSchema = z
21
+ .string()
22
+ .min(3)
23
+ .max(30)
24
+ .regex(/^[a-z0-9][a-z0-9-]+[a-z0-9](?:\.[a-z0-9][a-z0-9-]+[a-z0-9])+$/)
25
+ export const emailSchema = z
26
+ .string()
27
+ .email()
28
+ // @NOTE using @hapi/address here, in addition to the email() check to ensure
29
+ // compatibility with the current email validation in the PDS's account
30
+ // manager
31
+ .refine(isEmailValid, {
32
+ message: 'Invalid email address',
33
+ })
34
+ .refine((email) => !isDisposableEmail(email), {
35
+ message: 'Disposable email addresses are not allowed',
36
+ })
11
37
 
12
- /**
13
- * If false, the account must not be returned from
14
- * {@link AccountStore.listDeviceAccounts}. Note that this only makes sense when
15
- * used with a device ID.
16
- */
17
- remember: z.boolean().optional().default(false),
38
+ export const authenticateAccountDataSchema = z
39
+ .object({
40
+ locale: localeSchema,
41
+ username: z.string(),
42
+ password: oldPasswordSchema,
43
+ emailOtp: z.string().optional(),
44
+ })
45
+ .strict()
46
+
47
+ export type AuthenticateAccountData = z.TypeOf<
48
+ typeof authenticateAccountDataSchema
49
+ >
50
+
51
+ export const createAccountDataSchema = z
52
+ .object({
53
+ locale: localeSchema,
54
+ handle: handleSchema,
55
+ email: emailSchema,
56
+ password: z.intersection(oldPasswordSchema, newPasswordSchema),
57
+ inviteCode: tokenSchema.optional(),
58
+ })
59
+ .strict()
60
+
61
+ export type CreateAccountData = z.TypeOf<typeof createAccountDataSchema>
62
+
63
+ export const resetPasswordRequestDataSchema = z
64
+ .object({
65
+ locale: localeSchema,
66
+ email: emailSchema,
67
+ })
68
+ .strict()
69
+
70
+ export type ResetPasswordRequestData = z.TypeOf<
71
+ typeof resetPasswordRequestDataSchema
72
+ >
18
73
 
19
- emailOtp: z.string().optional(),
20
- })
74
+ export const resetPasswordConfirmDataSchema = z
75
+ .object({
76
+ token: tokenSchema,
77
+ password: z.intersection(oldPasswordSchema, newPasswordSchema),
78
+ })
79
+ .strict()
21
80
 
22
- export type SignInCredentials = z.TypeOf<typeof signInCredentialsSchema>
81
+ export type ResetPasswordConfirmData = z.TypeOf<
82
+ typeof resetPasswordConfirmDataSchema
83
+ >
23
84
 
24
85
  export type DeviceAccountInfo = {
25
86
  remembered: boolean
@@ -28,7 +89,14 @@ export type DeviceAccountInfo = {
28
89
  }
29
90
 
30
91
  // Export all types needed to implement the AccountStore interface
31
- export type { Account, DeviceId, Sub }
92
+ export {
93
+ type Account,
94
+ type DeviceId,
95
+ HandleUnavailableError,
96
+ InvalidRequestError,
97
+ SecondAuthenticationFactorRequiredError,
98
+ type Sub,
99
+ }
32
100
 
33
101
  export type AccountInfo = {
34
102
  account: Account
@@ -36,10 +104,17 @@ export type AccountInfo = {
36
104
  }
37
105
 
38
106
  export interface AccountStore {
39
- authenticateAccount(
40
- credentials: SignInCredentials,
41
- deviceId: DeviceId,
42
- ): Awaitable<AccountInfo | null>
107
+ /**
108
+ * @throws {HandleUnavailableError} - To indicate that the handle is already taken
109
+ * @throws {InvalidRequestError} - To indicate that some data is invalid
110
+ */
111
+ createAccount(data: CreateAccountData): Awaitable<Account>
112
+
113
+ /**
114
+ * @throws {InvalidRequestError} - When the credentials are not valid
115
+ * @throws {SecondAuthenticationFactorRequiredError} - To indicate that an {@link SecondAuthenticationFactorRequiredError.type} is required in the credentials
116
+ */
117
+ authenticateAccount(data: AuthenticateAccountData): Awaitable<Account>
43
118
 
44
119
  addAuthorizedClient(
45
120
  deviceId: DeviceId,
@@ -47,6 +122,19 @@ export interface AccountStore {
47
122
  clientId: ClientId,
48
123
  ): Awaitable<void>
49
124
 
125
+ /**
126
+ * @param remember If false, the account must not be returned from
127
+ * {@link AccountStore.listDeviceAccounts}.
128
+ */
129
+ addDeviceAccount(
130
+ deviceId: DeviceId,
131
+ sub: Sub,
132
+ remember: boolean,
133
+ ): Awaitable<DeviceAccountInfo>
134
+
135
+ /**
136
+ * @returns The account info, whether the account, even if remember was false.
137
+ */
50
138
  getDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<AccountInfo | null>
51
139
  removeDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<void>
52
140
 
@@ -55,23 +143,30 @@ export interface AccountStore {
55
143
  * be returned. The others will be ignored.
56
144
  */
57
145
  listDeviceAccounts(deviceId: DeviceId): Awaitable<AccountInfo[]>
58
- }
59
146
 
60
- export function isAccountStore(
61
- implementation: Record<string, unknown> & Partial<AccountStore>,
62
- ): implementation is Record<string, unknown> & AccountStore {
63
- return (
64
- typeof implementation.authenticateAccount === 'function' &&
65
- typeof implementation.getDeviceAccount === 'function' &&
66
- typeof implementation.addAuthorizedClient === 'function' &&
67
- typeof implementation.listDeviceAccounts === 'function' &&
68
- typeof implementation.removeDeviceAccount === 'function'
69
- )
147
+ resetPasswordRequest(data: ResetPasswordRequestData): Awaitable<void>
148
+ resetPasswordConfirm(data: ResetPasswordConfirmData): Awaitable<void>
149
+
150
+ /**
151
+ * @throws {HandleUnavailableError} - To indicate that the handle is already taken
152
+ */
153
+ verifyHandleAvailability(handle: string): Awaitable<void>
70
154
  }
71
155
 
72
- export function asAccountStore(
73
- implementation?: Record<string, unknown> & Partial<AccountStore>,
74
- ): AccountStore {
156
+ export const isAccountStore = buildInterfaceChecker<AccountStore>([
157
+ 'createAccount',
158
+ 'authenticateAccount',
159
+ 'addAuthorizedClient',
160
+ 'addDeviceAccount',
161
+ 'getDeviceAccount',
162
+ 'removeDeviceAccount',
163
+ 'listDeviceAccounts',
164
+ 'resetPasswordRequest',
165
+ 'resetPasswordConfirm',
166
+ 'verifyHandleAvailability',
167
+ ])
168
+
169
+ export function asAccountStore<V>(implementation: V): V & AccountStore {
75
170
  if (!implementation || !isAccountStore(implementation)) {
76
171
  throw new Error('Invalid AccountStore implementation')
77
172
  }
@@ -0,0 +1,15 @@
1
+ import { z } from 'zod'
2
+ import { authenticateAccountDataSchema } from './account-store.js'
3
+
4
+ export const signInDataSchema = authenticateAccountDataSchema
5
+ .extend({
6
+ /**
7
+ * If false, the account must not be returned from
8
+ * {@link AccountStore.listDeviceAccounts}. Note that this only makes sense when
9
+ * used with a device ID.
10
+ */
11
+ remember: z.boolean().optional().default(false),
12
+ })
13
+ .strict()
14
+
15
+ export type SignInData = z.TypeOf<typeof signInDataSchema>
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod'
2
+ import { hcaptchaTokenSchema } from '../lib/hcaptcha.js'
3
+ import { createAccountDataSchema } from './account-store.js'
4
+
5
+ export const signUpDataSchema = createAccountDataSchema
6
+ .extend({
7
+ hcaptchaToken: hcaptchaTokenSchema.optional(),
8
+ })
9
+ .strict()
10
+
11
+ export type SignUpData = z.TypeOf<typeof signUpDataSchema>
@@ -1,28 +1,43 @@
1
+ import { ErrorBoundary } from 'react-error-boundary'
1
2
  import type {
2
3
  AuthorizeData,
4
+ AvailableLocales,
3
5
  CustomizationData,
4
6
  ErrorData,
5
- } from './backend-data'
6
- import { AuthorizeView } from './views/authorize-view'
7
- import { ErrorView } from './views/error-view'
7
+ } from './backend-types.ts'
8
+ import { LocaleProvider } from './locales/locale-provider.tsx'
9
+ import { AuthorizeView } from './views/authorize/authorize-view.tsx'
10
+ import { ErrorView } from './views/error/error-view.tsx'
8
11
 
9
12
  export type AppProps = {
13
+ availableLocales?: AvailableLocales
10
14
  authorizeData?: AuthorizeData
11
15
  customizationData?: CustomizationData
12
16
  errorData?: ErrorData
13
17
  }
14
18
 
15
- export function App({ authorizeData, customizationData, errorData }: AppProps) {
16
- if (authorizeData && !errorData) {
17
- return (
18
- <AuthorizeView
19
- customizationData={customizationData}
20
- authorizeData={authorizeData}
21
- />
22
- )
23
- } else {
24
- return (
25
- <ErrorView customizationData={customizationData} errorData={errorData} />
26
- )
27
- }
19
+ export function App({
20
+ availableLocales,
21
+ authorizeData,
22
+ customizationData,
23
+ errorData,
24
+ }: AppProps) {
25
+ return (
26
+ <LocaleProvider availableLocales={availableLocales}>
27
+ <ErrorBoundary
28
+ fallbackRender={({ error }) => (
29
+ <ErrorView error={error} customizationData={customizationData} />
30
+ )}
31
+ >
32
+ {errorData || !authorizeData ? (
33
+ <ErrorView error={errorData} customizationData={customizationData} />
34
+ ) : (
35
+ <AuthorizeView
36
+ customizationData={customizationData}
37
+ authorizeData={authorizeData}
38
+ />
39
+ )}
40
+ </ErrorBoundary>
41
+ </LocaleProvider>
42
+ )
28
43
  }
@@ -1,72 +1,27 @@
1
- import { OAuthClientMetadata } from '@atproto/oauth-types'
2
-
3
- // TODO: Find a way to share these types with the backend code
4
-
5
- export type Account = {
6
- sub: string
7
- aud: string
8
-
9
- email?: string
10
- name?: string
11
- preferred_username?: string
12
- picture?: string
13
- }
14
-
15
- export type Session = {
16
- account: Account
17
- info?: never // Prevent relying on this in the frontend
18
-
19
- selected: boolean
20
- loginRequired: boolean
21
- consentRequired: boolean
22
- }
23
-
24
- export type LinkDefinition = {
25
- title: string
26
- href: string
27
- rel?: string
28
- }
29
-
30
- export type CustomizationData = {
31
- name?: string
32
- logo?: string
33
- links?: LinkDefinition[]
34
- }
35
-
36
- export type ErrorData = {
37
- error: string
38
- error_description: string
39
- }
40
-
41
- export type ScopeDetail = {
42
- scope: string
43
- description?: string
44
- }
45
-
46
- export type AuthorizeData = {
47
- clientId: string
48
- clientMetadata: OAuthClientMetadata
49
- clientTrusted: boolean
50
- requestUri: string
51
- csrfCookie: string
52
- loginHint?: string
53
- scopeDetails?: ScopeDetail[]
54
- newSessionsRequireConsent: boolean
55
- sessions: Session[]
56
- }
57
-
58
- // see "declareBackendData()" in the backend
59
- const readBackendData = <T>(key: string): T | undefined => {
1
+ import {
2
+ AuthorizeData,
3
+ AvailableLocales,
4
+ CustomizationData,
5
+ ErrorData,
6
+ } from './backend-types.ts'
7
+
8
+ function readBackendData<T>(key: string): T | undefined {
60
9
  const value = window[key] as T | undefined
61
10
  delete window[key] // Prevent accidental usage / potential leaks to dependencies
62
11
  return value
63
12
  }
64
13
 
65
14
  // These values are injected by the backend when it builds the
66
- // page HTML.
15
+ // page HTML. See "declareBackendData()" in the backend.
67
16
 
17
+ /** @deprecated Do not import directly. Only import this from main.tsx */
18
+ export const availableLocales =
19
+ readBackendData<AvailableLocales>('__availableLocales')
20
+ /** @deprecated Do not import directly. Only import this from main.tsx */
68
21
  export const customizationData = readBackendData<CustomizationData>(
69
22
  '__customizationData',
70
23
  )
24
+ /** @deprecated Do not import directly. Only import this from main.tsx */
71
25
  export const errorData = readBackendData<ErrorData>('__errorData')
26
+ /** @deprecated Do not import directly. Only import this from main.tsx */
72
27
  export const authorizeData = readBackendData<AuthorizeData>('__authorizeData')
@@ -0,0 +1,66 @@
1
+ import type { OAuthClientMetadata } from '@atproto/oauth-types'
2
+
3
+ // @TODO: Find a way to share these types with the backend code
4
+
5
+ export type Account = {
6
+ sub: string
7
+ aud: string | [string, ...string[]]
8
+
9
+ email?: string
10
+ email_verified?: boolean
11
+ name?: string
12
+ preferred_username?: string
13
+ picture?: string
14
+ }
15
+
16
+ export type Session = {
17
+ account: Account
18
+ info?: never // Prevent relying on this in the frontend
19
+
20
+ selected: boolean
21
+ loginRequired: boolean
22
+ consentRequired: boolean
23
+ }
24
+
25
+ export type LocalizedString = string | ({ en: string } & Record<string, string>)
26
+
27
+ export type AvailableLocales = readonly string[]
28
+
29
+ export type LinkDefinition = {
30
+ title: LocalizedString
31
+ href: string
32
+ rel?: string
33
+ }
34
+
35
+ export type CustomizationData = {
36
+ // Functional customization
37
+ hcaptchaSiteKey?: string
38
+ inviteCodeRequired?: boolean
39
+ availableUserDomains?: string[]
40
+
41
+ // Aesthetic customization
42
+ name?: string
43
+ logo?: string
44
+ links?: LinkDefinition[]
45
+ }
46
+
47
+ export type ErrorData = {
48
+ error: string
49
+ error_description: string
50
+ }
51
+
52
+ export type ScopeDetail = {
53
+ scope: string
54
+ description?: string
55
+ }
56
+
57
+ export type AuthorizeData = {
58
+ clientId: string
59
+ clientMetadata: OAuthClientMetadata
60
+ clientTrusted: boolean
61
+ requestUri: string
62
+ loginHint?: string
63
+ scopeDetails?: ScopeDetail[]
64
+ newSessionsRequireConsent: boolean
65
+ sessions: Session[]
66
+ }
@@ -0,0 +1,43 @@
1
+ import { useLingui } from '@lingui/react/macro'
2
+ import { Override } from '../../lib/util.ts'
3
+ import { EyeIcon, EyeSlashIcon } from '../utils/icons.tsx'
4
+ import { Button, ButtonProps } from './button.tsx'
5
+
6
+ export type ButtonToggleVisibilityProps = Override<
7
+ Omit<ButtonProps, 'aria-label' | 'square'>,
8
+ {
9
+ visible: boolean
10
+ toggleVisible: () => void
11
+ }
12
+ >
13
+
14
+ /**
15
+ * Generic button to toggle visibility of an item (e.g. password).
16
+ */
17
+ export function ButtonToggleVisibility({
18
+ visible,
19
+ toggleVisible,
20
+
21
+ // button
22
+ onClick,
23
+ ...props
24
+ }: ButtonToggleVisibilityProps) {
25
+ const { t } = useLingui()
26
+ return (
27
+ <Button
28
+ {...props}
29
+ square
30
+ onClick={(event) => {
31
+ onClick?.(event)
32
+ if (!event.defaultPrevented) toggleVisible()
33
+ }}
34
+ aria-label={visible ? t`Hide` : t`Make visible`}
35
+ >
36
+ {visible ? (
37
+ <EyeIcon className="w-5" aria-hidden />
38
+ ) : (
39
+ <EyeSlashIcon className="w-5" aria-hidden />
40
+ )}
41
+ </Button>
42
+ )
43
+ }
@@ -0,0 +1,60 @@
1
+ import { JSX } from 'react'
2
+ import { clsx } from '../../lib/clsx.ts'
3
+ import { Override } from '../../lib/util.ts'
4
+
5
+ export type ButtonProps = Override<
6
+ JSX.IntrinsicElements['button'],
7
+ {
8
+ color?: 'brand' | 'grey'
9
+ loading?: boolean
10
+ transparent?: boolean
11
+ square?: boolean
12
+ }
13
+ >
14
+
15
+ export function Button({
16
+ color = 'grey',
17
+ transparent = false,
18
+ loading = undefined,
19
+ square = false,
20
+
21
+ // button
22
+ children,
23
+ className,
24
+ type = 'button',
25
+ role = 'Button',
26
+ disabled = false,
27
+ ...props
28
+ }: ButtonProps) {
29
+ return (
30
+ <button
31
+ role={role}
32
+ type={type}
33
+ disabled={disabled || loading === true}
34
+ {...props}
35
+ className={clsx(
36
+ 'rounded-lg truncate cursor-pointer touch-manipulation tracking-wide overflow-hidden',
37
+ square ? 'p-2' : 'py-2 px-6',
38
+ color === 'brand'
39
+ ? clsx(
40
+ 'accent-slate-100',
41
+ transparent
42
+ ? 'bg-transparent text-brand'
43
+ : 'bg-brand text-brand-c',
44
+ )
45
+ : color === 'grey'
46
+ ? clsx(
47
+ 'accent-brand',
48
+ 'text-slate-600 dark:text-slate-300',
49
+ 'hover:bg-gray-200 dark:hover:bg-gray-700',
50
+ transparent ? 'bg-transparent' : 'bg-gray-100 dark:bg-gray-800',
51
+ )
52
+ : undefined,
53
+ 'disabled:opacity-50',
54
+ className,
55
+ )}
56
+ >
57
+ {children}
58
+ </button>
59
+ )
60
+ }
@@ -0,0 +1,55 @@
1
+ import { JSX, ReactNode, createContext, useMemo } from 'react'
2
+ import { useRandomString } from '../../hooks/use-random-string.ts'
3
+ import { Override } from '../../lib/util.ts'
4
+
5
+ export type FieldsetContextValue = {
6
+ disabled: boolean
7
+ labelId?: string
8
+ }
9
+
10
+ export const FieldsetContext = createContext<FieldsetContextValue>({
11
+ disabled: false,
12
+ })
13
+ FieldsetContext.displayName = 'FieldsetContext'
14
+
15
+ export type FieldsetCardProps = Override<
16
+ Omit<JSX.IntrinsicElements['fieldset'], 'aria-labelledby'>,
17
+ {
18
+ label?: ReactNode
19
+ }
20
+ >
21
+
22
+ export function Fieldset({
23
+ label,
24
+ children,
25
+ disabled,
26
+ ...props
27
+ }: FieldsetCardProps) {
28
+ const labelId = useRandomString({ prefix: 'fieldset-' })
29
+
30
+ const contextValue = useMemo(
31
+ () => ({
32
+ disabled: disabled ?? false,
33
+ labelId: label ? labelId : undefined,
34
+ }),
35
+ [disabled, label, labelId],
36
+ )
37
+
38
+ return (
39
+ <fieldset {...props} aria-labelledby={labelId} disabled={disabled}>
40
+ {label && (
41
+ <legend
42
+ id={labelId}
43
+ key="title"
44
+ className="mb-1 text-slate-600 dark:text-slate-400 text-sm font-medium"
45
+ >
46
+ {label}
47
+ </legend>
48
+ )}
49
+
50
+ <div className="flex flex-col space-y-4">
51
+ <FieldsetContext value={contextValue}>{children}</FieldsetContext>
52
+ </div>
53
+ </fieldset>
54
+ )
55
+ }