@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,98 +1,267 @@
1
- import { FetchResponseError, Json } from '@atproto-labs/fetch'
2
- import { Account, Session } from '../backend-data'
1
+ import { Account } from '../backend-types.ts'
2
+ import {
3
+ JsonClient,
4
+ JsonErrorPayload,
5
+ JsonErrorResponse,
6
+ } from './json-client.ts'
3
7
 
4
- export class Api {
5
- constructor(
6
- private requestUri: string,
7
- private clientId: string,
8
- private csrfToken: string,
9
- private newSessionsRequireConsent: boolean,
10
- ) {}
11
-
12
- async signIn(credentials: {
13
- username: string
14
- password: string
15
- remember?: boolean
16
- }): Promise<Session> {
17
- const response = await fetch('/oauth/authorize/sign-in', {
18
- method: 'POST',
19
- headers: { 'Content-Type': 'application/json' },
20
- mode: 'same-origin',
21
- body: JSON.stringify({
22
- csrf_token: this.csrfToken,
23
- request_uri: this.requestUri,
24
- client_id: this.clientId,
25
- credentials,
26
- }),
27
- })
28
-
29
- const json: Json = await response.json()
30
-
31
- if (response.ok) {
32
- const data = json as {
33
- account: Account
34
- consentRequired: boolean
35
- }
36
-
37
- return {
38
- account: data.account,
39
-
40
- selected: true,
41
- loginRequired: false,
42
- consentRequired: this.newSessionsRequireConsent || data.consentRequired,
43
- }
44
- } else if (
45
- response.status === 400 &&
46
- json?.['error'] === 'invalid_request' &&
47
- json?.['error_description'] === 'Invalid credentials'
48
- ) {
49
- throw new InvalidCredentialsError()
50
- } else if (
51
- response.status === 401 &&
52
- json?.['error'] === 'second_authentication_factor_required'
53
- ) {
54
- const data = json as {
55
- type: 'emailOtp'
56
- hint: string
57
- }
58
-
59
- throw new SecondAuthenticationFactorRequiredError(data.type, data.hint)
60
- } else {
61
- throw new FetchResponseError(response)
62
- }
8
+ export type { Options } from './json-client.ts'
9
+
10
+ export type AcceptData = {
11
+ sub: string
12
+ }
13
+
14
+ export type SignInData = {
15
+ locale: string
16
+ username: string
17
+ password: string
18
+ emailOtp?: string
19
+ remember?: boolean
20
+ }
21
+
22
+ export type SignUpData = {
23
+ locale: string
24
+ handle: string
25
+ email: string
26
+ password: string
27
+ inviteCode?: string
28
+ hcaptchaToken?: string
29
+ }
30
+
31
+ export type InitiatePasswordResetData = {
32
+ locale: string
33
+ email: string
34
+ }
35
+
36
+ export type ConfirmResetPasswordData = {
37
+ token: string
38
+ password: string
39
+ }
40
+
41
+ export type VerifyHandleAvailabilityData = {
42
+ handle: string
43
+ }
44
+
45
+ export type SessionResponse = {
46
+ account: Account
47
+ consentRequired: boolean
48
+ }
49
+
50
+ export class Api extends JsonClient<{
51
+ '/verify-handle-availability': {
52
+ input: VerifyHandleAvailabilityData
53
+ output: void
54
+ }
55
+ '/sign-up': {
56
+ input: SignUpData
57
+ output: SessionResponse
58
+ }
59
+ '/sign-in': {
60
+ input: SignInData
61
+ output: SessionResponse
62
+ }
63
+ '/reset-password-request': {
64
+ input: InitiatePasswordResetData
65
+ output: void
66
+ }
67
+ '/reset-password-confirm': {
68
+ input: ConfirmResetPasswordData
69
+ output: void
70
+ }
71
+ }> {
72
+ constructor(csrfToken: string) {
73
+ const baseUrl = new URL('/oauth/authorize', window.origin).toString()
74
+ super(baseUrl, csrfToken)
63
75
  }
64
76
 
65
- async accept(account: Account): Promise<URL> {
66
- const url = new URL('/oauth/authorize/accept', window.origin)
67
- url.searchParams.set('request_uri', this.requestUri)
68
- url.searchParams.set('account_sub', account.sub)
69
- url.searchParams.set('client_id', this.clientId)
77
+ public buildAcceptUrl(data: AcceptData): URL {
78
+ const url = new URL(`${this.baseUrl}/accept`)
79
+ url.searchParams.set('account_sub', data.sub)
70
80
  url.searchParams.set('csrf_token', this.csrfToken)
71
-
72
81
  return url
73
82
  }
74
83
 
75
- async reject(): Promise<URL> {
76
- const url = new URL('/oauth/authorize/reject', window.origin)
77
- url.searchParams.set('request_uri', this.requestUri)
78
- url.searchParams.set('client_id', this.clientId)
84
+ public buildRejectUrl(): URL {
85
+ const url = new URL(`${this.baseUrl}/reject`)
79
86
  url.searchParams.set('csrf_token', this.csrfToken)
80
-
81
87
  return url
82
88
  }
89
+
90
+ public static override parseError(
91
+ json: unknown,
92
+ ): undefined | JsonErrorResponse {
93
+ // @NOTE Most specific errors first !
94
+ if (SecondAuthenticationFactorRequiredError.is(json)) {
95
+ return new SecondAuthenticationFactorRequiredError(json)
96
+ }
97
+ if (InvalidCredentialsError.is(json)) {
98
+ return new InvalidCredentialsError(json)
99
+ }
100
+ if (HandleUnavailableError.is(json)) {
101
+ return new HandleUnavailableError(json)
102
+ }
103
+ if (EmailTakenError.is(json)) {
104
+ return new EmailTakenError(json)
105
+ }
106
+ if (RequestExpiredError.is(json)) {
107
+ return new RequestExpiredError(json)
108
+ }
109
+ if (UnknownRequestUriError.is(json)) {
110
+ return new UnknownRequestUriError(json)
111
+ }
112
+ if (InvalidRequestError.is(json)) {
113
+ return new InvalidRequestError(json)
114
+ }
115
+ if (AccessDeniedError.is(json)) {
116
+ return new AccessDeniedError(json)
117
+ }
118
+ return super.parseError(json)
119
+ }
120
+ }
121
+
122
+ export type AccessDeniedPayload = JsonErrorPayload<'access_denied'>
123
+ export class AccessDeniedError<
124
+ P extends AccessDeniedPayload = AccessDeniedPayload,
125
+ > extends JsonErrorResponse<P> {
126
+ constructor(
127
+ payload: P,
128
+ message = payload.error_description || 'Access denied',
129
+ ) {
130
+ super(payload, message)
131
+ }
132
+
133
+ static is(json: unknown): json is AccessDeniedPayload {
134
+ return super.is(json) && json.error === 'access_denied'
135
+ }
136
+ }
137
+
138
+ export type InvalidRequestPayload = JsonErrorPayload<'invalid_request'>
139
+ export class InvalidRequestError<
140
+ P extends InvalidRequestPayload = InvalidRequestPayload,
141
+ > extends JsonErrorResponse<P> {
142
+ constructor(
143
+ payload: P,
144
+ message = payload.error_description || 'Invalid request',
145
+ ) {
146
+ super(payload, message)
147
+ }
148
+
149
+ static is(json: unknown): json is InvalidRequestPayload {
150
+ return super.is(json) && json.error === 'invalid_request'
151
+ }
152
+ }
153
+
154
+ export type RequestExpiredPayload = AccessDeniedPayload & {
155
+ error_description: 'This request has expired'
156
+ }
157
+ export class RequestExpiredError<
158
+ P extends RequestExpiredPayload = RequestExpiredPayload,
159
+ > extends AccessDeniedError<P> {
160
+ static is(json: unknown): json is RequestExpiredPayload {
161
+ return (
162
+ super.is(json) && json.error_description === 'This request has expired'
163
+ )
164
+ }
165
+ }
166
+
167
+ export type InvalidCredentialsPayload = InvalidRequestPayload & {
168
+ error_description: 'Invalid identifier or password'
169
+ }
170
+ export class InvalidCredentialsError<
171
+ P extends InvalidCredentialsPayload = InvalidCredentialsPayload,
172
+ > extends InvalidRequestError<P> {
173
+ static is(json: unknown): json is InvalidCredentialsPayload {
174
+ return (
175
+ super.is(json) &&
176
+ json.error_description === 'Invalid identifier or password'
177
+ )
178
+ }
179
+ }
180
+
181
+ export type UnknownRequestPayload = InvalidRequestPayload & {
182
+ error_description: 'Unknown request_uri'
183
+ }
184
+ export class UnknownRequestUriError<
185
+ P extends UnknownRequestPayload = UnknownRequestPayload,
186
+ > extends InvalidRequestError<P> {
187
+ static is(json: unknown): json is UnknownRequestPayload {
188
+ return super.is(json) && json.error_description === 'Unknown request_uri'
189
+ }
190
+ }
191
+ export type EmailTakenPayload = InvalidRequestPayload & {
192
+ error_description: 'Email already taken'
193
+ }
194
+ export class EmailTakenError<
195
+ P extends EmailTakenPayload = EmailTakenPayload,
196
+ > extends InvalidRequestError<P> {
197
+ static is(json: unknown): json is EmailTakenPayload {
198
+ return super.is(json) && json.error_description === 'Email already taken'
199
+ }
83
200
  }
84
201
 
85
- export class InvalidCredentialsError extends Error {
86
- constructor() {
87
- super('Invalid credentials')
202
+ export type HandleUnavailablePayload =
203
+ JsonErrorPayload<'handle_unavailable'> & {
204
+ reason: 'syntax' | 'domain' | 'slur' | 'taken'
205
+ }
206
+ export class HandleUnavailableError<
207
+ P extends HandleUnavailablePayload = HandleUnavailablePayload,
208
+ > extends JsonErrorResponse<P> {
209
+ constructor(
210
+ payload: P,
211
+ message = payload.error_description || 'That handle cannot be used',
212
+ ) {
213
+ super(payload, message)
214
+ }
215
+
216
+ get reason() {
217
+ return this.payload.reason
218
+ }
219
+
220
+ static is(json: unknown): json is HandleUnavailablePayload {
221
+ return (
222
+ super.is(json) &&
223
+ json.error === 'handle_unavailable' &&
224
+ 'reason' in json &&
225
+ (json.reason === 'syntax' ||
226
+ json.reason === 'domain' ||
227
+ json.reason === 'slur' ||
228
+ json.reason === 'taken')
229
+ )
88
230
  }
89
231
  }
90
232
 
91
- export class SecondAuthenticationFactorRequiredError extends Error {
233
+ export type SecondAuthenticationFactorRequiredPayload =
234
+ JsonErrorPayload<'second_authentication_factor_required'> & {
235
+ type: 'emailOtp'
236
+ hint: string
237
+ }
238
+ export class SecondAuthenticationFactorRequiredError<
239
+ P extends
240
+ SecondAuthenticationFactorRequiredPayload = SecondAuthenticationFactorRequiredPayload,
241
+ > extends JsonErrorResponse<P> {
92
242
  constructor(
93
- public type: 'emailOtp',
94
- public hint: string,
243
+ payload: P,
244
+ message = payload.error_description ||
245
+ `${payload.type} authentication factor required (hint: ${payload.hint})`,
95
246
  ) {
96
- super(`${type} authentication factor required (hint: ${hint})`)
247
+ super(payload, message)
248
+ }
249
+
250
+ get type() {
251
+ return this.payload.type
252
+ }
253
+ get hint() {
254
+ return this.payload.hint
255
+ }
256
+
257
+ static is(json: unknown): json is SecondAuthenticationFactorRequiredPayload {
258
+ return (
259
+ super.is(json) &&
260
+ json.error === 'second_authentication_factor_required' &&
261
+ 'type' in json &&
262
+ json.type === 'emailOtp' &&
263
+ 'hint' in json &&
264
+ typeof json.hint === 'string'
265
+ )
97
266
  }
98
267
  }
@@ -1,9 +1,6 @@
1
- export function clsx(
2
- a?: string,
3
- ...args: readonly (string | undefined)[]
4
- ): string | undefined {
5
- if (args.length === 0) return a
6
- const b = clsx(...args)
7
- if (a && b) return `${a} ${b}`
8
- return a || b
1
+ type ClsxArg = string | false | undefined
2
+
3
+ export function clsx(...args: [ClsxArg, ...ClsxArg[]]): string | undefined {
4
+ const filtered = args.filter(Boolean) as string[]
5
+ return filtered.length > 0 ? filtered.join(' ') : undefined
9
6
  }
@@ -0,0 +1,94 @@
1
+ // Using a type import to avoid bundling this lib
2
+ import type { Json } from '@atproto-labs/fetch'
3
+
4
+ export { type Json }
5
+
6
+ export type Options = {
7
+ signal?: AbortSignal
8
+ }
9
+
10
+ export type EndpointDefinition = {
11
+ input: Json
12
+ output: Json | void
13
+ }
14
+
15
+ export class JsonClient<E extends { [Path: string]: EndpointDefinition }> {
16
+ constructor(
17
+ protected readonly baseUrl: string,
18
+ protected readonly csrfToken: string,
19
+ ) {}
20
+
21
+ public async fetch<P extends string & keyof E>(
22
+ path: P,
23
+ payload: E[P]['input'],
24
+ options?: Options,
25
+ ): Promise<E[P]['output']> {
26
+ const response = await fetch(`${this.baseUrl}${path}`, {
27
+ method: 'POST',
28
+ headers: {
29
+ 'Content-Type': 'application/json',
30
+ 'X-CSRF-Token': this.csrfToken,
31
+ },
32
+ mode: 'same-origin',
33
+ body: JSON.stringify(payload),
34
+ signal: options?.signal,
35
+ })
36
+
37
+ if (response.status === 204) {
38
+ return undefined
39
+ }
40
+
41
+ return response.json().then((json: Json) => {
42
+ if (response.ok) return json as E[P]['output']
43
+ else throw this.parseError(response, json)
44
+ })
45
+ }
46
+
47
+ protected parseError(response: Response, json: Json): Error {
48
+ const Class = this.constructor as typeof JsonClient
49
+ const error = Class.parseError(json)
50
+ if (error) return error
51
+
52
+ return new Error('Invalid JSON response', { cause: response })
53
+ }
54
+
55
+ public static parseError(json: unknown): undefined | JsonErrorResponse {
56
+ if (JsonErrorResponse.is(json)) {
57
+ return new JsonErrorResponse(json)
58
+ }
59
+ }
60
+ }
61
+
62
+ export type JsonErrorPayload<E extends string = string> = {
63
+ error: E
64
+ error_description?: string
65
+ }
66
+
67
+ export class JsonErrorResponse<
68
+ P extends JsonErrorPayload = JsonErrorPayload,
69
+ > extends Error {
70
+ constructor(
71
+ public readonly payload: P,
72
+ message = payload.error_description,
73
+ ) {
74
+ super(message || `Error "${payload.error}"`)
75
+ }
76
+
77
+ get error(): string {
78
+ return this.payload.error
79
+ }
80
+
81
+ get description(): string | undefined {
82
+ return this.payload.error_description
83
+ }
84
+
85
+ static is(json: unknown): json is JsonErrorPayload {
86
+ return (
87
+ json != null &&
88
+ typeof json === 'object' &&
89
+ typeof json['error'] === 'string' &&
90
+ (json['error_description'] === undefined ||
91
+ typeof json['error_description'] === 'string')
92
+ )
93
+ }
94
+ }
@@ -0,0 +1,98 @@
1
+ export const MIN_PASSWORD_LENGTH = 8
2
+
3
+ const EMOJI =
4
+ /(\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/
5
+ const UPPER = /[A-Z]/
6
+ const LOWER = /[a-z]/
7
+ const DEC = /[0-9]/
8
+ const SPECIAL = /[^a-zA-Z0-9]/
9
+
10
+ export enum PasswordStrength {
11
+ weak = 1,
12
+ moderate = 2,
13
+ strong = 3,
14
+ extra = 4,
15
+ }
16
+
17
+ export function getPasswordStrength(pwd: string): PasswordStrength {
18
+ if (pwd.length < MIN_PASSWORD_LENGTH) {
19
+ return PasswordStrength.weak
20
+ }
21
+
22
+ // Very long passwords
23
+ if (pwd.length >= MIN_PASSWORD_LENGTH + 12) {
24
+ return PasswordStrength.extra
25
+ }
26
+
27
+ // Long passwords
28
+ if (pwd.length >= MIN_PASSWORD_LENGTH + 8) {
29
+ if (matches(pwd, [SPECIAL])) {
30
+ return PasswordStrength.extra
31
+ }
32
+ if (matches(pwd, [UPPER, LOWER, DEC], 2)) {
33
+ return PasswordStrength.extra
34
+ }
35
+ return PasswordStrength.strong
36
+ }
37
+
38
+ // Emojis make passwords strong
39
+ if (pwd.length >= MIN_PASSWORD_LENGTH) {
40
+ if (matches(pwd, [EMOJI])) {
41
+ return PasswordStrength.strong
42
+ }
43
+ }
44
+
45
+ // Pretty long passwords
46
+ if (pwd.length >= MIN_PASSWORD_LENGTH + 6) {
47
+ if (matches(pwd, [SPECIAL])) {
48
+ return PasswordStrength.strong
49
+ }
50
+ if (matches(pwd, [UPPER, LOWER, DEC], 2)) {
51
+ return PasswordStrength.strong
52
+ }
53
+ // Only 1 type of alpha-num characters
54
+ return PasswordStrength.moderate
55
+ }
56
+
57
+ // Longish password
58
+ if (pwd.length >= MIN_PASSWORD_LENGTH + 4) {
59
+ if (matches(pwd, [SPECIAL])) {
60
+ return PasswordStrength.moderate
61
+ }
62
+ if (matches(pwd, [UPPER, LOWER, DEC], 2)) {
63
+ return PasswordStrength.moderate
64
+ }
65
+
66
+ // Only 1 type of alpha-num characters
67
+ return PasswordStrength.weak
68
+ }
69
+
70
+ // Short password (8-11 characters)
71
+ if (pwd.length >= MIN_PASSWORD_LENGTH) {
72
+ if (matches(pwd, [SPECIAL])) {
73
+ return PasswordStrength.moderate
74
+ }
75
+ if (matches(pwd, [UPPER, LOWER, DEC])) {
76
+ return PasswordStrength.moderate
77
+ }
78
+ }
79
+
80
+ return PasswordStrength.weak
81
+ }
82
+
83
+ function matches(
84
+ pwd: string,
85
+ regexps: RegExp[],
86
+ regexpsCountToMatch: number = regexps.length,
87
+ ): boolean {
88
+ if (regexpsCountToMatch < 1 || regexpsCountToMatch > regexps.length) {
89
+ throw new TypeError('Invalid regexpsCountToMatch')
90
+ }
91
+ for (const regexp of regexps) {
92
+ if (regexp.test(pwd)) {
93
+ regexpsCountToMatch--
94
+ if (regexpsCountToMatch === 0) return true
95
+ }
96
+ }
97
+ return false
98
+ }
@@ -0,0 +1,17 @@
1
+ import { ForwardedRef } from 'react'
2
+
3
+ export function updateRef<T>(ref: ForwardedRef<T>, value: T | null) {
4
+ if (typeof ref === 'function') {
5
+ ref(value)
6
+ } else if (ref) {
7
+ ref.current = value
8
+ }
9
+ }
10
+
11
+ export function mergeRefs<T>(refs: readonly (ForwardedRef<T> | undefined)[]) {
12
+ return (value: T | null) => {
13
+ for (const ref of refs) {
14
+ if (ref) updateRef(ref, value)
15
+ }
16
+ }
17
+ }