@atproto/oauth-provider 0.5.2 → 0.6.1

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 (310) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/account/account-manager.d.ts +7 -5
  3. package/dist/account/account-manager.d.ts.map +1 -1
  4. package/dist/account/account-manager.js +34 -25
  5. package/dist/account/account-manager.js.map +1 -1
  6. package/dist/account/account-store.d.ts +7 -0
  7. package/dist/account/account-store.d.ts.map +1 -1
  8. package/dist/account/account-store.js.map +1 -1
  9. package/dist/account/account.d.ts +1 -11
  10. package/dist/account/account.d.ts.map +1 -1
  11. package/dist/account/{sign-up-data.d.ts → sign-up-input.d.ts} +3 -3
  12. package/dist/account/sign-up-input.d.ts.map +1 -0
  13. package/dist/account/{sign-up-data.js → sign-up-input.js} +3 -3
  14. package/dist/account/sign-up-input.js.map +1 -0
  15. package/dist/assets/assets-middleware.d.ts +2 -0
  16. package/dist/assets/assets-middleware.d.ts.map +1 -1
  17. package/dist/assets/assets-middleware.js +12 -14
  18. package/dist/assets/assets-middleware.js.map +1 -1
  19. package/dist/lib/csp/index.d.ts +5 -6
  20. package/dist/lib/csp/index.d.ts.map +1 -1
  21. package/dist/lib/csp/index.js +14 -11
  22. package/dist/lib/csp/index.js.map +1 -1
  23. package/dist/lib/hcaptcha.d.ts +15 -12
  24. package/dist/lib/hcaptcha.d.ts.map +1 -1
  25. package/dist/lib/hcaptcha.js +11 -7
  26. package/dist/lib/hcaptcha.js.map +1 -1
  27. package/dist/lib/html/build-document.d.ts +2 -2
  28. package/dist/lib/html/build-document.d.ts.map +1 -1
  29. package/dist/lib/html/build-document.js +11 -7
  30. package/dist/lib/html/build-document.js.map +1 -1
  31. package/dist/lib/html/html.d.ts.map +1 -1
  32. package/dist/lib/html/html.js +10 -13
  33. package/dist/lib/html/html.js.map +1 -1
  34. package/dist/lib/html/util.d.ts +0 -1
  35. package/dist/lib/html/util.d.ts.map +1 -1
  36. package/dist/lib/html/util.js +0 -4
  37. package/dist/lib/html/util.js.map +1 -1
  38. package/dist/lib/http/response.d.ts +3 -1
  39. package/dist/lib/http/response.d.ts.map +1 -1
  40. package/dist/lib/http/response.js +3 -0
  41. package/dist/lib/http/response.js.map +1 -1
  42. package/dist/lib/http/security-headers.d.ts +48 -0
  43. package/dist/lib/http/security-headers.d.ts.map +1 -0
  44. package/dist/lib/http/security-headers.js +62 -0
  45. package/dist/lib/http/security-headers.js.map +1 -0
  46. package/dist/lib/util/type.d.ts +8 -0
  47. package/dist/lib/util/type.d.ts.map +1 -1
  48. package/dist/lib/util/type.js.map +1 -1
  49. package/dist/oauth-hooks.d.ts +4 -25
  50. package/dist/oauth-hooks.d.ts.map +1 -1
  51. package/dist/oauth-provider.js +2 -2
  52. package/dist/oauth-provider.js.map +1 -1
  53. package/dist/output/backend-data.d.ts +4 -0
  54. package/dist/output/backend-data.d.ts.map +1 -0
  55. package/dist/output/backend-data.js +19 -0
  56. package/dist/output/backend-data.js.map +1 -0
  57. package/dist/output/build-authorize-data.d.ts +3 -19
  58. package/dist/output/build-authorize-data.d.ts.map +1 -1
  59. package/dist/output/build-authorize-data.js.map +1 -1
  60. package/dist/output/build-customization-data.d.ts +11 -18
  61. package/dist/output/build-customization-data.d.ts.map +1 -1
  62. package/dist/output/build-customization-data.js +1 -1
  63. package/dist/output/build-customization-data.js.map +1 -1
  64. package/dist/output/build-error-data.d.ts +3 -0
  65. package/dist/output/build-error-data.d.ts.map +1 -0
  66. package/dist/output/build-error-data.js +10 -0
  67. package/dist/output/build-error-data.js.map +1 -0
  68. package/dist/output/build-error-payload.d.ts +2 -1
  69. package/dist/output/build-error-payload.d.ts.map +1 -1
  70. package/dist/output/build-error-payload.js.map +1 -1
  71. package/dist/output/output-manager.d.ts +10 -4
  72. package/dist/output/output-manager.d.ts.map +1 -1
  73. package/dist/output/output-manager.js +68 -39
  74. package/dist/output/output-manager.js.map +1 -1
  75. package/dist/output/send-web-page.d.ts +6 -10
  76. package/dist/output/send-web-page.d.ts.map +1 -1
  77. package/dist/output/send-web-page.js +27 -47
  78. package/dist/output/send-web-page.js.map +1 -1
  79. package/dist/signer/signed-token-payload.d.ts +3 -3
  80. package/dist/signer/signer.d.ts +2 -2
  81. package/package.json +8 -41
  82. package/src/account/account-manager.ts +55 -34
  83. package/src/account/account-store.ts +8 -0
  84. package/src/account/account.ts +1 -14
  85. package/src/account/{sign-up-data.ts → sign-up-input.ts} +2 -2
  86. package/src/assets/assets-middleware.ts +11 -17
  87. package/src/lib/csp/index.ts +16 -13
  88. package/src/lib/hcaptcha.ts +14 -10
  89. package/src/lib/html/build-document.ts +15 -8
  90. package/src/lib/html/html.ts +11 -18
  91. package/src/lib/html/util.ts +0 -4
  92. package/src/lib/http/response.ts +9 -1
  93. package/src/lib/http/security-headers.ts +91 -0
  94. package/src/lib/util/type.ts +18 -0
  95. package/src/oauth-hooks.ts +4 -25
  96. package/src/oauth-provider.ts +2 -2
  97. package/src/output/backend-data.ts +18 -0
  98. package/src/output/build-authorize-data.ts +3 -26
  99. package/src/output/build-customization-data.ts +2 -13
  100. package/src/output/build-error-data.ts +8 -0
  101. package/src/output/build-error-payload.ts +4 -2
  102. package/src/output/output-manager.ts +86 -47
  103. package/src/output/send-web-page.ts +29 -58
  104. package/tsconfig.backend.json +1 -2
  105. package/tsconfig.backend.tsbuildinfo +1 -1
  106. package/tsconfig.json +1 -5
  107. package/.linguirc +0 -57
  108. package/dist/account/sign-up-data.d.ts.map +0 -1
  109. package/dist/account/sign-up-data.js.map +0 -1
  110. package/dist/assets/app/bundle-manifest.json +0 -614
  111. package/dist/assets/app/index-DZHZ9kCP.js +0 -36
  112. package/dist/assets/app/index-DZHZ9kCP.js.map +0 -1
  113. package/dist/assets/app/main-B_dNxQo_.js +0 -4
  114. package/dist/assets/app/main-B_dNxQo_.js.map +0 -1
  115. package/dist/assets/app/main-Dr6y26KY.css +0 -3
  116. package/dist/assets/app/main-Dr6y26KY.js +0 -306
  117. package/dist/assets/app/main-Dr6y26KY.js.map +0 -1
  118. package/dist/assets/app/messages-6_mYuGzB.js +0 -4
  119. package/dist/assets/app/messages-6_mYuGzB.js.map +0 -1
  120. package/dist/assets/app/messages-7wdeBTpD.js +0 -4
  121. package/dist/assets/app/messages-7wdeBTpD.js.map +0 -1
  122. package/dist/assets/app/messages-B-YFoWKc.js +0 -4
  123. package/dist/assets/app/messages-B-YFoWKc.js.map +0 -1
  124. package/dist/assets/app/messages-B10DUOE-.js +0 -4
  125. package/dist/assets/app/messages-B10DUOE-.js.map +0 -1
  126. package/dist/assets/app/messages-B4AwFEeZ.js +0 -4
  127. package/dist/assets/app/messages-B4AwFEeZ.js.map +0 -1
  128. package/dist/assets/app/messages-BDP8MyEC.js +0 -4
  129. package/dist/assets/app/messages-BDP8MyEC.js.map +0 -1
  130. package/dist/assets/app/messages-BIS87lxQ.js +0 -4
  131. package/dist/assets/app/messages-BIS87lxQ.js.map +0 -1
  132. package/dist/assets/app/messages-BI_Wbjdt.js +0 -4
  133. package/dist/assets/app/messages-BI_Wbjdt.js.map +0 -1
  134. package/dist/assets/app/messages-BMAouhRx.js +0 -4
  135. package/dist/assets/app/messages-BMAouhRx.js.map +0 -1
  136. package/dist/assets/app/messages-BdckMnJj.js +0 -4
  137. package/dist/assets/app/messages-BdckMnJj.js.map +0 -1
  138. package/dist/assets/app/messages-BgBLzc46.js +0 -4
  139. package/dist/assets/app/messages-BgBLzc46.js.map +0 -1
  140. package/dist/assets/app/messages-BobD78yK.js +0 -4
  141. package/dist/assets/app/messages-BobD78yK.js.map +0 -1
  142. package/dist/assets/app/messages-BtThT9UZ.js +0 -4
  143. package/dist/assets/app/messages-BtThT9UZ.js.map +0 -1
  144. package/dist/assets/app/messages-BwKHkbeh.js +0 -4
  145. package/dist/assets/app/messages-BwKHkbeh.js.map +0 -1
  146. package/dist/assets/app/messages-C417YUvA.js +0 -4
  147. package/dist/assets/app/messages-C417YUvA.js.map +0 -1
  148. package/dist/assets/app/messages-C4CxO4bO.js +0 -4
  149. package/dist/assets/app/messages-C4CxO4bO.js.map +0 -1
  150. package/dist/assets/app/messages-C5vd04e6.js +0 -4
  151. package/dist/assets/app/messages-C5vd04e6.js.map +0 -1
  152. package/dist/assets/app/messages-CAri2Wnz.js +0 -4
  153. package/dist/assets/app/messages-CAri2Wnz.js.map +0 -1
  154. package/dist/assets/app/messages-CPtWTZeG.js +0 -4
  155. package/dist/assets/app/messages-CPtWTZeG.js.map +0 -1
  156. package/dist/assets/app/messages-CiaM5zm8.js +0 -4
  157. package/dist/assets/app/messages-CiaM5zm8.js.map +0 -1
  158. package/dist/assets/app/messages-CkL-L2R6.js +0 -4
  159. package/dist/assets/app/messages-CkL-L2R6.js.map +0 -1
  160. package/dist/assets/app/messages-Cy_4XLNe.js +0 -4
  161. package/dist/assets/app/messages-Cy_4XLNe.js.map +0 -1
  162. package/dist/assets/app/messages-D5_ad-Eo.js +0 -4
  163. package/dist/assets/app/messages-D5_ad-Eo.js.map +0 -1
  164. package/dist/assets/app/messages-DChMl9mT.js +0 -4
  165. package/dist/assets/app/messages-DChMl9mT.js.map +0 -1
  166. package/dist/assets/app/messages-DWX-DIfv.js +0 -4
  167. package/dist/assets/app/messages-DWX-DIfv.js.map +0 -1
  168. package/dist/assets/app/messages-DgfsOphe.js +0 -4
  169. package/dist/assets/app/messages-DgfsOphe.js.map +0 -1
  170. package/dist/assets/app/messages-Dj5B_DR6.js +0 -4
  171. package/dist/assets/app/messages-Dj5B_DR6.js.map +0 -1
  172. package/dist/assets/app/messages-Dwzqo4eA.js +0 -4
  173. package/dist/assets/app/messages-Dwzqo4eA.js.map +0 -1
  174. package/dist/assets/app/messages-ESCIXJR7.js +0 -4
  175. package/dist/assets/app/messages-ESCIXJR7.js.map +0 -1
  176. package/dist/assets/app/messages-dglB2edb.js +0 -4
  177. package/dist/assets/app/messages-dglB2edb.js.map +0 -1
  178. package/dist/assets/app/messages-e_ClRrWc.js +0 -4
  179. package/dist/assets/app/messages-e_ClRrWc.js.map +0 -1
  180. package/dist/assets/app/messages-evvDxmrP.js +0 -4
  181. package/dist/assets/app/messages-evvDxmrP.js.map +0 -1
  182. package/dist/assets/app/messages-pPbdLb5B.js +0 -4
  183. package/dist/assets/app/messages-pPbdLb5B.js.map +0 -1
  184. package/dist/assets/app/messages-tJv8gHL2.js +0 -4
  185. package/dist/assets/app/messages-tJv8gHL2.js.map +0 -1
  186. package/dist/assets/app/messages-vLRVEw96.js +0 -4
  187. package/dist/assets/app/messages-vLRVEw96.js.map +0 -1
  188. package/dist/assets/asset.d.ts +0 -9
  189. package/dist/assets/asset.d.ts.map +0 -1
  190. package/dist/assets/asset.js +0 -3
  191. package/dist/assets/asset.js.map +0 -1
  192. package/dist/assets/index.d.ts +0 -5
  193. package/dist/assets/index.d.ts.map +0 -1
  194. package/dist/assets/index.js +0 -78
  195. package/dist/assets/index.js.map +0 -1
  196. package/rollup.config.js +0 -98
  197. package/src/assets/app/app.tsx +0 -43
  198. package/src/assets/app/backend-data.ts +0 -27
  199. package/src/assets/app/backend-types.ts +0 -66
  200. package/src/assets/app/components/forms/button-toggle-visibility.tsx +0 -43
  201. package/src/assets/app/components/forms/button.tsx +0 -60
  202. package/src/assets/app/components/forms/fieldset.tsx +0 -55
  203. package/src/assets/app/components/forms/form-card-async.tsx +0 -103
  204. package/src/assets/app/components/forms/form-card.tsx +0 -49
  205. package/src/assets/app/components/forms/input-checkbox.tsx +0 -78
  206. package/src/assets/app/components/forms/input-container.tsx +0 -107
  207. package/src/assets/app/components/forms/input-email-address.tsx +0 -65
  208. package/src/assets/app/components/forms/input-new-password.tsx +0 -62
  209. package/src/assets/app/components/forms/input-password.tsx +0 -87
  210. package/src/assets/app/components/forms/input-text.tsx +0 -82
  211. package/src/assets/app/components/forms/input-token.tsx +0 -94
  212. package/src/assets/app/components/forms/wizard-card.tsx +0 -116
  213. package/src/assets/app/components/layouts/layout-title-page.tsx +0 -77
  214. package/src/assets/app/components/layouts/layout-welcome.tsx +0 -73
  215. package/src/assets/app/components/utils/account-identifier.tsx +0 -23
  216. package/src/assets/app/components/utils/account-image.tsx +0 -33
  217. package/src/assets/app/components/utils/admonition.tsx +0 -52
  218. package/src/assets/app/components/utils/client-name.tsx +0 -45
  219. package/src/assets/app/components/utils/error-card.tsx +0 -93
  220. package/src/assets/app/components/utils/error-message.tsx +0 -88
  221. package/src/assets/app/components/utils/help-card.tsx +0 -46
  222. package/src/assets/app/components/utils/icons.tsx +0 -88
  223. package/src/assets/app/components/utils/link-anchor.tsx +0 -28
  224. package/src/assets/app/components/utils/link-title.tsx +0 -26
  225. package/src/assets/app/components/utils/multi-lang-string.tsx +0 -56
  226. package/src/assets/app/components/utils/password-strength-label.tsx +0 -37
  227. package/src/assets/app/components/utils/password-strength-meter.tsx +0 -58
  228. package/src/assets/app/components/utils/url-viewer.tsx +0 -73
  229. package/src/assets/app/cookies.ts +0 -11
  230. package/src/assets/app/hooks/use-api.ts +0 -178
  231. package/src/assets/app/hooks/use-async-action.ts +0 -120
  232. package/src/assets/app/hooks/use-bound-dispatch.ts +0 -5
  233. package/src/assets/app/hooks/use-browser-color-scheme.ts +0 -31
  234. package/src/assets/app/hooks/use-csrf-token.ts +0 -5
  235. package/src/assets/app/hooks/use-random-string.ts +0 -37
  236. package/src/assets/app/hooks/use-stepper.ts +0 -87
  237. package/src/assets/app/index.html +0 -182
  238. package/src/assets/app/lib/api.ts +0 -289
  239. package/src/assets/app/lib/clsx.ts +0 -6
  240. package/src/assets/app/lib/json-client.ts +0 -94
  241. package/src/assets/app/lib/password.ts +0 -98
  242. package/src/assets/app/lib/ref.ts +0 -17
  243. package/src/assets/app/lib/util.ts +0 -13
  244. package/src/assets/app/locales/an/messages.po +0 -490
  245. package/src/assets/app/locales/ast/messages.po +0 -490
  246. package/src/assets/app/locales/ca/messages.po +0 -490
  247. package/src/assets/app/locales/da/messages.po +0 -490
  248. package/src/assets/app/locales/de/messages.po +0 -490
  249. package/src/assets/app/locales/el/messages.po +0 -490
  250. package/src/assets/app/locales/en/messages.po +0 -490
  251. package/src/assets/app/locales/en-GB/messages.po +0 -490
  252. package/src/assets/app/locales/es/messages.po +0 -490
  253. package/src/assets/app/locales/eu/messages.po +0 -490
  254. package/src/assets/app/locales/fi/messages.po +0 -490
  255. package/src/assets/app/locales/fr/messages.po +0 -490
  256. package/src/assets/app/locales/ga/messages.po +0 -490
  257. package/src/assets/app/locales/gl/messages.po +0 -490
  258. package/src/assets/app/locales/hi/messages.po +0 -490
  259. package/src/assets/app/locales/hu/messages.po +0 -490
  260. package/src/assets/app/locales/ia/messages.po +0 -490
  261. package/src/assets/app/locales/id/messages.po +0 -490
  262. package/src/assets/app/locales/it/messages.po +0 -490
  263. package/src/assets/app/locales/ja/messages.po +0 -490
  264. package/src/assets/app/locales/km/messages.po +0 -490
  265. package/src/assets/app/locales/ko/messages.po +0 -490
  266. package/src/assets/app/locales/load.ts +0 -8
  267. package/src/assets/app/locales/locale-context.ts +0 -19
  268. package/src/assets/app/locales/locale-provider.tsx +0 -112
  269. package/src/assets/app/locales/locale-selector.tsx +0 -58
  270. package/src/assets/app/locales/locales.ts +0 -168
  271. package/src/assets/app/locales/ne/messages.po +0 -490
  272. package/src/assets/app/locales/nl/messages.po +0 -490
  273. package/src/assets/app/locales/pl/messages.po +0 -490
  274. package/src/assets/app/locales/pt-BR/messages.po +0 -490
  275. package/src/assets/app/locales/ro/messages.po +0 -490
  276. package/src/assets/app/locales/ru/messages.po +0 -490
  277. package/src/assets/app/locales/sv/messages.po +0 -490
  278. package/src/assets/app/locales/th/messages.po +0 -490
  279. package/src/assets/app/locales/tr/messages.po +0 -490
  280. package/src/assets/app/locales/uk/messages.po +0 -490
  281. package/src/assets/app/locales/vi/messages.po +0 -490
  282. package/src/assets/app/locales/zh-CN/messages.po +0 -490
  283. package/src/assets/app/locales/zh-HK/messages.po +0 -490
  284. package/src/assets/app/locales/zh-TW/messages.po +0 -490
  285. package/src/assets/app/main.css +0 -33
  286. package/src/assets/app/main.tsx +0 -44
  287. package/src/assets/app/views/authorize/accept/accept-form.tsx +0 -150
  288. package/src/assets/app/views/authorize/accept/accept-view.tsx +0 -70
  289. package/src/assets/app/views/authorize/authorize-view.tsx +0 -180
  290. package/src/assets/app/views/authorize/reset-password/reset-password-confirm-form.tsx +0 -88
  291. package/src/assets/app/views/authorize/reset-password/reset-password-request-form.tsx +0 -80
  292. package/src/assets/app/views/authorize/reset-password/reset-password-view.tsx +0 -127
  293. package/src/assets/app/views/authorize/sign-in/sign-in-form.tsx +0 -242
  294. package/src/assets/app/views/authorize/sign-in/sign-in-picker.tsx +0 -116
  295. package/src/assets/app/views/authorize/sign-in/sign-in-view.tsx +0 -145
  296. package/src/assets/app/views/authorize/sign-up/sign-up-account-form.tsx +0 -142
  297. package/src/assets/app/views/authorize/sign-up/sign-up-disclaimer.tsx +0 -51
  298. package/src/assets/app/views/authorize/sign-up/sign-up-handle-form.tsx +0 -287
  299. package/src/assets/app/views/authorize/sign-up/sign-up-hcaptcha-form.tsx +0 -108
  300. package/src/assets/app/views/authorize/sign-up/sign-up-view.tsx +0 -158
  301. package/src/assets/app/views/authorize/welcome/welcome-view.tsx +0 -56
  302. package/src/assets/app/views/error/error-view.tsx +0 -31
  303. package/src/assets/asset.ts +0 -9
  304. package/src/assets/index.ts +0 -86
  305. package/tailwind.config.js +0 -31
  306. package/tsconfig.frontend.json +0 -11
  307. package/tsconfig.frontend.tsbuildinfo +0 -1
  308. package/tsconfig.tools.json +0 -8
  309. package/tsconfig.tools.tsbuildinfo +0 -1
  310. package/vite.config.mjs +0 -16
@@ -1,37 +0,0 @@
1
- import { Trans, useLingui } from '@lingui/react/macro'
2
- import { JSX } from 'react'
3
- import { PasswordStrength, getPasswordStrength } from '../../lib/password.ts'
4
- import { Override } from '../../lib/util.ts'
5
-
6
- export type PasswordStrengthLabelProps = Override<
7
- Omit<JSX.IntrinsicElements['span'], 'children' | 'aria-label'>,
8
- {
9
- password: string
10
- }
11
- >
12
-
13
- export function PasswordStrengthLabel({
14
- password,
15
-
16
- // span
17
- ...props
18
- }: PasswordStrengthLabelProps) {
19
- const { t } = useLingui()
20
- const strength = getPasswordStrength(password)
21
-
22
- return (
23
- <span {...props} aria-label={t`Password strength`}>
24
- {strength === PasswordStrength.extra ? (
25
- <Trans>Extra</Trans>
26
- ) : strength === PasswordStrength.strong ? (
27
- <Trans>Strong</Trans>
28
- ) : strength === PasswordStrength.moderate ? (
29
- <Trans>Moderate</Trans>
30
- ) : password ? (
31
- <Trans>Weak</Trans>
32
- ) : (
33
- <Trans>Missing</Trans>
34
- )}
35
- </span>
36
- )
37
- }
@@ -1,58 +0,0 @@
1
- import { useLingui } from '@lingui/react/macro'
2
- import { JSX } from 'react'
3
- import { clsx } from '../../lib/clsx.ts'
4
- import { PasswordStrength, getPasswordStrength } from '../../lib/password.ts'
5
- import { Override } from '../../lib/util.ts'
6
-
7
- export type PasswordStrengthMeterProps = Override<
8
- Omit<
9
- JSX.IntrinsicElements['div'],
10
- | 'children'
11
- | 'role'
12
- | 'aria-label'
13
- | 'aria-valuemin'
14
- | 'aria-valuemax'
15
- | 'aria-valuenow'
16
- >,
17
- {
18
- password: string
19
- }
20
- >
21
-
22
- export function PasswordStrengthMeter({
23
- password,
24
-
25
- // div
26
- className,
27
- ...props
28
- }: PasswordStrengthMeterProps) {
29
- const { t } = useLingui()
30
- const strength = password ? getPasswordStrength(password) : 0
31
-
32
- const colorBg = 'bg-gray-300 dark:bg-slate-500'
33
- const color =
34
- strength === PasswordStrength.extra || strength === PasswordStrength.strong
35
- ? 'bg-success'
36
- : strength === PasswordStrength.moderate
37
- ? 'bg-warning'
38
- : 'bg-error'
39
-
40
- return (
41
- <div
42
- {...props}
43
- className={clsx('w-full h-1 flex space-x-2', className)}
44
- role="meter"
45
- aria-label={t`Password strength indicator`}
46
- aria-valuemin={0}
47
- aria-valuemax={PasswordStrength.extra}
48
- aria-valuenow={strength}
49
- >
50
- {Array.from({ length: 4 }, (_, i) => (
51
- <div
52
- key={i}
53
- className={`rounded h-1 w-1/4 ${strength > i ? color : colorBg}`}
54
- />
55
- ))}
56
- </div>
57
- )
58
- }
@@ -1,73 +0,0 @@
1
- import { JSX, useMemo } from 'react'
2
- import { Override } from '../../lib/util.ts'
3
-
4
- export type UrlPartRenderingOptions = {
5
- faded?: boolean
6
- bold?: boolean
7
- }
8
-
9
- export type UrlRendererProps = {
10
- url: string | URL
11
- proto?: boolean | UrlPartRenderingOptions
12
- host?: boolean | UrlPartRenderingOptions
13
- path?: boolean | UrlPartRenderingOptions
14
- query?: boolean | UrlPartRenderingOptions
15
- hash?: boolean | UrlPartRenderingOptions
16
- as?: string
17
- }
18
-
19
- export function UrlViewer<As extends keyof JSX.IntrinsicElements = 'span'>({
20
- url,
21
- proto = false,
22
- host = true,
23
- path = false,
24
- query = false,
25
- hash = false,
26
- as: As = 'span',
27
-
28
- // Element
29
- ...props
30
- }: Override<JSX.IntrinsicElements[As], UrlRendererProps>) {
31
- const urlObj = useMemo(() => new URL(url), [url])
32
-
33
- return (
34
- <As {...props}>
35
- {proto && (
36
- <UrlPartViewer
37
- value={`${urlObj.protocol}//`}
38
- {...(proto === true ? null : proto)}
39
- />
40
- )}
41
- {host && (
42
- <UrlPartViewer
43
- value={urlObj.host}
44
- {...(host === true ? { faded: false, bold: true } : host)}
45
- />
46
- )}
47
- {path && (
48
- <UrlPartViewer
49
- value={urlObj.pathname}
50
- {...(path === true ? null : path)}
51
- />
52
- )}
53
- {query && (
54
- <UrlPartViewer
55
- value={urlObj.search}
56
- {...(query === true ? null : query)}
57
- />
58
- )}
59
- {hash && (
60
- <UrlPartViewer value={urlObj.hash} {...(hash === true ? null : hash)} />
61
- )}
62
- </As>
63
- )
64
- }
65
-
66
- function UrlPartViewer({
67
- value,
68
- faded = true,
69
- bold = false,
70
- }: { value: string } & UrlPartRenderingOptions) {
71
- const Comp = bold ? 'b' : 'span'
72
- return <Comp className={faded ? 'opacity-50' : ''}>{value}</Comp>
73
- }
@@ -1,11 +0,0 @@
1
- export const parseCookieString = (
2
- cookie: string,
3
- ): Record<string, string | undefined> =>
4
- Object.fromEntries(
5
- cookie
6
- .split(';')
7
- .filter(Boolean)
8
- .map((str) => str.split('=', 2).map((s) => decodeURIComponent(s.trim()))),
9
- )
10
-
11
- export const cookies = parseCookieString(document.cookie)
@@ -1,178 +0,0 @@
1
- import { useLingui } from '@lingui/react/macro'
2
- import { useCallback, useMemo, useState } from 'react'
3
- import { useErrorBoundary } from 'react-error-boundary'
4
- import { Session } from '../backend-types.ts'
5
- import {
6
- AcceptData,
7
- Api,
8
- ConfirmResetPasswordData,
9
- InitiatePasswordResetData,
10
- SessionResponse,
11
- SignInData,
12
- SignUpData,
13
- UnknownRequestUriError,
14
- VerifyHandleAvailabilityData,
15
- } from '../lib/api.ts'
16
- import { upsert } from '../lib/util.ts'
17
- import { useCsrfToken } from './use-csrf-token.ts'
18
-
19
- /**
20
- * Any function wrapped with this helper will automatically show the error
21
- * boundary when an `UnknownRequestUriError` is thrown. This typically happens
22
- * in development, or if the user left its browser session open for a (very)
23
- * long time.
24
- *
25
- * @note Requires an error boundary to be present in the component tree.
26
- */
27
- function useSafeCallback<F extends (...a: any) => any>(fn: F, deps: unknown[]) {
28
- const { showBoundary } = useErrorBoundary<UnknownRequestUriError>()
29
-
30
- return useCallback(
31
- async (...args: Parameters<F>): Promise<Awaited<ReturnType<F>>> => {
32
- try {
33
- return await fn(...args)
34
- } catch (error) {
35
- if (error instanceof UnknownRequestUriError) showBoundary(error)
36
- throw error
37
- }
38
- },
39
- deps.concat(showBoundary),
40
- )
41
- }
42
-
43
- export type UseApiOptions = {
44
- requestUri: string
45
- sessions?: readonly Session[]
46
- newSessionsRequireConsent?: boolean
47
- onRedirected?: () => void
48
- }
49
-
50
- export function useApi({
51
- requestUri,
52
- sessions: sessionsInit = [],
53
- newSessionsRequireConsent = true,
54
- onRedirected,
55
- }: UseApiOptions) {
56
- const csrfToken = useCsrfToken(`csrf-${requestUri}`)
57
- if (!csrfToken) throw new Error('CSRF token is missing')
58
-
59
- const api = useMemo(() => new Api(csrfToken), [csrfToken])
60
- const [sessions, setSessions] = useState(sessionsInit)
61
-
62
- const { i18n } = useLingui()
63
- const { locale } = i18n
64
-
65
- const selectSub = useCallback(
66
- (sub: string | null) => {
67
- setSessions((sessions) =>
68
- sub === (sessions.find((s) => s.selected)?.account.sub || null)
69
- ? sessions
70
- : sessions.map((s) => ({ ...s, selected: s.account.sub === sub })),
71
- )
72
- },
73
- [setSessions],
74
- )
75
-
76
- const upsertSession = useCallback(
77
- ({ account, consentRequired }: SessionResponse) => {
78
- const session: Session = {
79
- account,
80
- selected: true,
81
- loginRequired: false,
82
- consentRequired: newSessionsRequireConsent || consentRequired,
83
- }
84
-
85
- setSessions((sessions) =>
86
- upsert(sessions, session, (s) => s.account.sub === account.sub).map(
87
- // Make sure to de-select any other selected session
88
- (s) => (s === session || !s.selected ? s : { ...s, selected: false }),
89
- ),
90
- )
91
- },
92
- [setSessions, newSessionsRequireConsent],
93
- )
94
-
95
- const performRedirect = useCallback(
96
- (url: URL) => {
97
- window.location.href = String(url)
98
- if (onRedirected) setTimeout(onRedirected)
99
- },
100
- [onRedirected],
101
- )
102
-
103
- const doSignIn = useSafeCallback(
104
- async (data: Omit<SignInData, 'locale'>, signal?: AbortSignal) => {
105
- const response = await api.fetch(
106
- '/sign-in',
107
- { ...data, locale },
108
- { signal },
109
- )
110
- upsertSession(response)
111
- },
112
- [api, locale, upsertSession],
113
- )
114
-
115
- const doInitiatePasswordReset = useSafeCallback(
116
- async (
117
- data: Omit<InitiatePasswordResetData, 'locale'>,
118
- signal?: AbortSignal,
119
- ) => {
120
- await api.fetch(
121
- '/reset-password-request',
122
- { ...data, locale },
123
- { signal },
124
- )
125
- },
126
- [api, locale],
127
- )
128
-
129
- const doConfirmResetPassword = useSafeCallback(
130
- async (data: ConfirmResetPasswordData, signal?: AbortSignal) => {
131
- await api.fetch('/reset-password-confirm', data, { signal })
132
- },
133
- [api],
134
- )
135
-
136
- const doValidateNewHandle = useSafeCallback(
137
- async (data: VerifyHandleAvailabilityData, signal?: AbortSignal) => {
138
- await api.fetch('/verify-handle-availability', data, { signal })
139
- },
140
- [api],
141
- )
142
-
143
- const doSignUp = useSafeCallback(
144
- async (data: Omit<SignUpData, 'locale'>, signal?: AbortSignal) => {
145
- const response = await api.fetch(
146
- '/sign-up',
147
- { ...data, locale },
148
- { signal },
149
- )
150
- upsertSession(response)
151
- },
152
- [api, locale, upsertSession],
153
- )
154
-
155
- const doAccept = useSafeCallback(
156
- async (data: AcceptData) => {
157
- performRedirect(api.buildAcceptUrl(data))
158
- },
159
- [api, performRedirect],
160
- )
161
-
162
- const doReject = useSafeCallback(async () => {
163
- performRedirect(api.buildRejectUrl())
164
- }, [api, performRedirect])
165
-
166
- return {
167
- sessions,
168
- selectSub,
169
-
170
- doSignIn,
171
- doInitiatePasswordReset,
172
- doConfirmResetPassword,
173
- doValidateNewHandle,
174
- doSignUp,
175
- doAccept,
176
- doReject,
177
- }
178
- }
@@ -1,120 +0,0 @@
1
- import {
2
- ForwardedRef,
3
- useCallback,
4
- useEffect,
5
- useImperativeHandle,
6
- useRef,
7
- useState,
8
- } from 'react'
9
-
10
- export type AsyncActionController = {
11
- reset: () => void
12
- }
13
-
14
- export type UseAsyncActionOptions = {
15
- ref?: ForwardedRef<AsyncActionController>
16
- onLoading?: (loading: boolean) => void
17
- onError?: (error: Error | undefined) => void
18
- }
19
-
20
- export function useAsyncAction(
21
- fn: (signal: AbortSignal) => void | PromiseLike<void>,
22
- { ref, onLoading, onError }: UseAsyncActionOptions = {},
23
- ) {
24
- const [loading, setLoading] = useState(false)
25
- const [error, setError] = useState<Error | undefined>()
26
-
27
- const doSetError = useCallback(
28
- (error: Error | undefined) => {
29
- setError(error)
30
- onError?.(error)
31
- },
32
- [onError],
33
- )
34
-
35
- const doSetLoading = useCallback(
36
- (loading: boolean) => {
37
- setLoading(loading)
38
- onLoading?.(loading)
39
- },
40
- [onLoading],
41
- )
42
-
43
- const controllerRef = useRef<AbortController>(null)
44
-
45
- const resetRef = useRef<() => void>(null)
46
- useEffect(() => {
47
- resetRef.current = () => {
48
- controllerRef.current?.abort()
49
- controllerRef.current = null
50
- doSetError(undefined)
51
- doSetLoading(false)
52
- }
53
- return () => {
54
- resetRef.current = null
55
- }
56
- }, [doSetError, doSetLoading])
57
-
58
- useImperativeHandle(
59
- ref,
60
- (): AsyncActionController => ({
61
- reset: () => resetRef.current?.(),
62
- }),
63
- [],
64
- )
65
-
66
- // Cancel pending action when unmounted
67
- useEffect(() => {
68
- return () => {
69
- controllerRef.current?.abort()
70
- controllerRef.current = null
71
- }
72
- }, [])
73
-
74
- const run = useCallback(async (): Promise<void> => {
75
- // Cancel previous run
76
- controllerRef.current?.abort()
77
-
78
- doSetLoading(true)
79
- doSetError(undefined)
80
-
81
- const controller = new AbortController()
82
- const { signal } = controller
83
-
84
- controllerRef.current = controller
85
-
86
- try {
87
- await fn(signal)
88
- } catch (err) {
89
- if (controller === controllerRef.current) {
90
- doSetError(err instanceof Error ? err : new Error(String(err)))
91
- } else {
92
- if (!isAbortReason(signal, err)) {
93
- console.warn('Async action error after abort', err)
94
- }
95
- }
96
- } finally {
97
- if (controller === controllerRef.current) {
98
- controllerRef.current = null
99
- doSetLoading(false)
100
- }
101
-
102
- controller.abort()
103
- }
104
- }, [fn, doSetLoading, doSetError])
105
-
106
- return {
107
- loading,
108
- error,
109
- run,
110
- }
111
- }
112
-
113
- function isAbortReason(signal: AbortSignal, err: unknown): boolean {
114
- return (
115
- signal.aborted &&
116
- (signal.reason === err ||
117
- signal.reason === err?.['cause'] ||
118
- (err instanceof DOMException && err.name === 'AbortError'))
119
- )
120
- }
@@ -1,5 +0,0 @@
1
- import { Dispatch, useCallback } from 'react'
2
-
3
- export function useBoundDispatch<A>(dispatch: Dispatch<A>, value: A) {
4
- return useCallback(() => dispatch(value), [dispatch, value])
5
- }
@@ -1,31 +0,0 @@
1
- import { useEffect, useState } from 'react'
2
-
3
- const query =
4
- typeof window === 'undefined'
5
- ? null
6
- : window.matchMedia('(prefers-color-scheme: dark)')
7
-
8
- export function useBrowserColorScheme() {
9
- const [theme, setTheme] = useState<'light' | 'dark'>(
10
- query?.matches ? 'dark' : 'light',
11
- )
12
-
13
- useEffect(() => {
14
- if (!query) return
15
-
16
- const listener = () => {
17
- setTheme(query.matches ? 'dark' : 'light')
18
- }
19
-
20
- query.addEventListener('change', listener)
21
-
22
- return () => {
23
- query.removeEventListener('change', listener)
24
- }
25
-
26
- // @NOTE "query" is a global constant and does not need to be part of the
27
- // array bellow:
28
- }, [])
29
-
30
- return theme
31
- }
@@ -1,5 +0,0 @@
1
- import { cookies } from '../cookies.ts'
2
-
3
- export function useCsrfToken(cookieName: string) {
4
- return cookies[cookieName]
5
- }
@@ -1,37 +0,0 @@
1
- import { useEffect, useState } from 'react'
2
-
3
- export const UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
4
- export const LOWER = UPPER.toLowerCase() as Lowercase<typeof UPPER>
5
- export const DIGITS = '0123456789'
6
-
7
- export const ALPHANUMERIC = `${UPPER}${LOWER}${DIGITS}` as const
8
-
9
- export type UseRandomStringOptions = BuildRandomStringOptions & {
10
- prefix?: string
11
- suffix?: string
12
- }
13
-
14
- export function useRandomString(options?: UseRandomStringOptions) {
15
- const [state, setState] = useState(() => buildRandomString(options))
16
- useEffect(() => {
17
- setState(buildRandomString(options))
18
- }, [options?.length, options?.alphabet])
19
-
20
- return `${options?.prefix ?? ''}${state}${options?.suffix ?? ''}`
21
- }
22
-
23
- type BuildRandomStringOptions = {
24
- length?: number
25
- alphabet?: string
26
- }
27
-
28
- function buildRandomString({
29
- length = 16,
30
- alphabet = ALPHANUMERIC,
31
- }: BuildRandomStringOptions = {}) {
32
- return Array.from({ length }, () => getRandomCharFrom(alphabet)).join('')
33
- }
34
-
35
- function getRandomCharFrom(alphabet: string) {
36
- return alphabet.charAt((Math.random() * alphabet.length) | 0)
37
- }
@@ -1,87 +0,0 @@
1
- import { useCallback, useEffect, useState } from 'react'
2
-
3
- export type DisabledStep = false | null | undefined
4
- export type Step = {
5
- invalid: boolean
6
- }
7
-
8
- const isEnabled = <S extends Step | DisabledStep>(
9
- s: S,
10
- ): s is S extends DisabledStep ? never : S => s != null && s !== false
11
- const isRequired = <S extends Step | DisabledStep>(
12
- s: S,
13
- ): s is S extends DisabledStep ? never : S & { invalid: true } =>
14
- isEnabled(s) && s.invalid === true
15
- const isCompleted = <S extends Step | DisabledStep>(
16
- s: S,
17
- ): s is S extends DisabledStep ? S : S & { invalid: false } =>
18
- !isEnabled(s) || s.invalid === false
19
-
20
- export function useStepper<const S extends Step>(
21
- steps: readonly (S | DisabledStep)[],
22
- ) {
23
- const firstIdx = steps.findIndex(isEnabled)
24
- const lastIdx = steps.findLastIndex(isEnabled)
25
- const requiredIdx = steps.findIndex(isRequired)
26
-
27
- const [currentIdx, setCurrentIdx] = useState<number>(firstIdx)
28
-
29
- const to = useCallback(
30
- (idx: number) => {
31
- if (idx !== -1 && steps[idx]) {
32
- setCurrentIdx(idx)
33
- return true
34
- } else {
35
- return false
36
- }
37
- },
38
- [steps.map(isEnabled).join()],
39
- )
40
-
41
- const prevIdx = steps.findLastIndex((s, i) => isEnabled(s) && i < currentIdx)
42
- const nextIdx = steps.findIndex((s, i) => isEnabled(s) && i > currentIdx)
43
-
44
- const toFirst = useCallback(() => to(firstIdx), [to, firstIdx])
45
- const toLast = useCallback(() => to(lastIdx), [to, lastIdx])
46
- const toPrev = useCallback(() => to(prevIdx), [to, prevIdx])
47
- const toNext = useCallback(() => to(nextIdx), [to, nextIdx])
48
- const toRequired = useCallback(() => to(requiredIdx), [to, requiredIdx])
49
-
50
- // Step number in user friendly terms (accounting for disabled steps)
51
- const currentPosition =
52
- currentIdx +
53
- // use "1 indexed position" (for user friendliness):
54
- 1 +
55
- // Adjust the position by counting the number of disabled steps before the
56
- // current step (if any):
57
- steps.reduce(
58
- (acc, s, i) => (i >= currentIdx || isEnabled(s) ? acc : acc - 1),
59
- 0,
60
- )
61
-
62
- const count = steps.filter(isEnabled).length
63
- const completed = steps.every(isCompleted)
64
-
65
- const current =
66
- currentIdx === -1 || !steps[currentIdx] ? undefined : steps[currentIdx]
67
-
68
- // Fool-proof (reset current step in case the current step becomes disabled)
69
- const broken = currentIdx === -1
70
- useEffect(() => {
71
- if (broken) toFirst()
72
- }, [broken])
73
-
74
- return {
75
- current,
76
- currentPosition,
77
- count,
78
- completed,
79
- atFirst: currentPosition === 1,
80
- atLast: currentPosition === count,
81
- toFirst,
82
- toLast,
83
- toPrev,
84
- toNext,
85
- toRequired,
86
- }
87
- }