@atproto/oauth-provider 0.5.2 → 0.6.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 (310) hide show
  1. package/CHANGELOG.md +31 -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 +5 -3
  24. package/dist/lib/hcaptcha.d.ts.map +1 -1
  25. package/dist/lib/hcaptcha.js +7 -4
  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 +7 -40
  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 +10 -7
  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,287 +0,0 @@
1
- import { Trans, useLingui } from '@lingui/react/macro'
2
- import { JSX, ReactNode, useCallback, useEffect, useRef, useState } from 'react'
3
- import {
4
- AsyncActionController,
5
- FormCardAsync,
6
- FormCardAsyncProps,
7
- } from '../../../components/forms/form-card-async.tsx'
8
- import { InputText } from '../../../components/forms/input-text.tsx'
9
- import { Admonition } from '../../../components/utils/admonition.tsx'
10
- import {
11
- AtSymbolIcon,
12
- CheckMarkIcon,
13
- XMarkIcon,
14
- } from '../../../components/utils/icons.tsx'
15
- import { clsx } from '../../../lib/clsx.ts'
16
- import { mergeRefs } from '../../../lib/ref.ts'
17
- import { Override } from '../../../lib/util.ts'
18
-
19
- /**
20
- * Spec limit is 63, but in practice, we've limited it to 18 in our implementations.
21
- *
22
- * @see {@link https://atproto.com/specs/handle | ATProto Handle Spec}
23
- */
24
- const MAX_LENGTH = 18
25
-
26
- /**
27
- * Spec limit is 1, but in practice, we've targeted at least 3 characters in handles.
28
- *
29
- * @see {@link https://atproto.com/specs/handle | ATProto Handle Spec}
30
- */
31
- const MIN_LENGTH = 3
32
-
33
- /**
34
- * Spec limit is 253, but in practice, we've targeted 30 characters in handles.
35
- *
36
- * @see {@link https://atproto.com/specs/handle | ATProto Handle Spec}
37
- */
38
- const MAX_FULL_LENGTH = 30
39
-
40
- type ValidDomain = `.${string}`
41
- const isValidDomain = (domain: string): domain is ValidDomain =>
42
- // Ignore domains that are so long that they would make the handle smaller
43
- // than MIN_LENGTH characters
44
- MIN_LENGTH + domain.length <= MAX_FULL_LENGTH &&
45
- // Basic validation here
46
- domain.startsWith('.') &&
47
- !domain.endsWith('.')
48
-
49
- function useSegmentValidator(domain: ValidDomain) {
50
- const minLen = MIN_LENGTH
51
- const maxLen = Math.min(MAX_LENGTH, MAX_FULL_LENGTH - domain.length)
52
-
53
- const validateSegment = useCallback(
54
- (segment: string) => {
55
- const validLength = segment.length >= minLen && segment.length <= maxLen
56
- const validCharset = /^[a-z0-9][a-z0-9-]+[a-z0-9]$/g.test(segment)
57
-
58
- return { validLength, validCharset, valid: validLength && validCharset }
59
- },
60
- [maxLen, minLen],
61
- )
62
-
63
- return {
64
- minLength: minLen,
65
- maxLength: maxLen,
66
- validateSegment,
67
- }
68
- }
69
-
70
- export type SignUpHandleFormProps = Override<
71
- Omit<
72
- FormCardAsyncProps,
73
- 'append' | 'onCancel' | 'cancelLabel' | 'onSubmit' | 'submitLabel'
74
- >,
75
- {
76
- domains: string[]
77
-
78
- onNext: (signal: AbortSignal) => void | PromiseLike<void>
79
- nextLabel?: ReactNode
80
-
81
- onPrev?: () => void
82
- prevLabel?: ReactNode
83
-
84
- handle?: string
85
- onHandle?: (handle: string | undefined) => void
86
- }
87
- >
88
-
89
- export function SignUpHandleForm({
90
- domains: availableDomains,
91
-
92
- onNext,
93
- nextLabel,
94
-
95
- onPrev,
96
- prevLabel,
97
-
98
- handle: handleInit,
99
- onHandle,
100
-
101
- // FormCardProps
102
- invalid,
103
- children,
104
- ref,
105
- ...props
106
- }: SignUpHandleFormProps) {
107
- const { t } = useLingui()
108
- const domains = availableDomains.filter(isValidDomain)
109
-
110
- const formRef = useRef<AsyncActionController>(null)
111
-
112
- const [domainIdx, setDomainIdx] = useState(() => {
113
- const idx = domains.findIndex((d) => handleInit?.endsWith(d))
114
- return idx === -1 ? 0 : idx
115
- })
116
- const [segment, setSegment] = useState(() => handleInit?.split('.')[0] || '')
117
-
118
- // Automatically update the domain index when the list length changes
119
- useEffect(() => {
120
- setDomainIdx((v) => Math.min(v, domains.length - 1))
121
- }, [domains.length])
122
-
123
- const domain: ValidDomain | null = domains[domainIdx] || domains[0] || null
124
-
125
- const { minLength, maxLength, validateSegment } = useSegmentValidator(domain)
126
-
127
- const validity = validateSegment(segment)
128
- const handle = domain && validity.valid ? `${segment}${domain}` : undefined
129
- useEffect(() => {
130
- // Whenever the user changes the handle, abort any pending form action
131
- formRef.current?.reset()
132
- onHandle?.(handle)
133
- }, [onHandle, handle])
134
-
135
- const inputRef = useRef<HTMLInputElement>(null)
136
-
137
- const preview = `@${segment}${domain}`
138
-
139
- return (
140
- <FormCardAsync
141
- {...props}
142
- ref={mergeRefs([ref, formRef])}
143
- onCancel={onPrev}
144
- cancelLabel={prevLabel}
145
- onSubmit={onNext}
146
- submitLabel={nextLabel}
147
- invalid={invalid || !handle}
148
- append={children}
149
- >
150
- <div>
151
- <ValidationMessage hasValue={!!segment} valid={validity.validLength}>
152
- <Trans>
153
- Between {minLength} and {maxLength} characters
154
- </Trans>
155
- </ValidationMessage>
156
- <ValidationMessage hasValue={!!segment} valid={validity.validCharset}>
157
- <Trans>Only letters, numbers, and hyphens</Trans>
158
- </ValidationMessage>
159
- </div>
160
-
161
- <InputText
162
- ref={inputRef}
163
- icon={<AtSymbolIcon className="w-5" />}
164
- name="handle"
165
- type="text"
166
- title={t`Type your desired username`}
167
- pattern="[a-z0-9][a-z0-9\-]+[a-z0-9]"
168
- minLength={minLength}
169
- maxLength={maxLength}
170
- autoCapitalize="none"
171
- autoCorrect="off"
172
- autoComplete="off"
173
- dir="auto"
174
- enterKeyHint="done"
175
- autoFocus
176
- required
177
- value={segment}
178
- onChange={(event) => {
179
- const segment = event.target.value.toLowerCase()
180
-
181
- // Ensure the input is always lowercase
182
- const selectionStart = event.target.selectionStart
183
- const selectionEnd = event.target.selectionEnd
184
- event.target.value = segment
185
- event.target.setSelectionRange(selectionStart, selectionEnd)
186
-
187
- setSegment(segment)
188
- }}
189
- append={
190
- // @TODO refactor this to a separate component
191
- domains.length > 1 && (
192
- <select
193
- onClick={(event) => event.stopPropagation()}
194
- onMouseDown={(event) => event.stopPropagation()}
195
- value={domainIdx}
196
- aria-label={t`Select domain`}
197
- onChange={(event) => {
198
- setDomainIdx(Number(event.target.value))
199
- inputRef.current?.focus()
200
- }}
201
- className={clsx(
202
- 'block w-full',
203
- 'text-sm',
204
- 'rounded-lg p-2',
205
- 'bg-white dark:bg-slate-600',
206
- )}
207
- >
208
- {domains.map((domain, idx) => (
209
- <option key={domain} value={idx}>
210
- {domain}
211
- </option>
212
- ))}
213
- </select>
214
- )
215
- }
216
- bellow={
217
- <Trans>
218
- Your full username will be:{' '}
219
- {segment.length ? (
220
- <strong className="text-gray-800 dark:text-gray-200">
221
- {preview}
222
- </strong>
223
- ) : (
224
- <span
225
- aria-hidden
226
- className="bg-gray-300 dark:bg-slate-600 rounded-md p-2 w-24"
227
- />
228
- )}
229
- </Trans>
230
- }
231
- />
232
-
233
- <Admonition role="status">
234
- <p className="text-md">
235
- <Trans>
236
- You can change this username to any domain name you control after
237
- your account is set up.
238
- </Trans>
239
- </p>
240
- </Admonition>
241
- </FormCardAsync>
242
- )
243
- }
244
-
245
- type ValidationMessageProps = JSX.IntrinsicElements['div'] & {
246
- valid: boolean
247
- hasValue: boolean
248
- }
249
-
250
- function ValidationMessage({
251
- valid,
252
- hasValue,
253
-
254
- // div
255
- children,
256
- className,
257
- ...props
258
- }: ValidationMessageProps) {
259
- const { t } = useLingui()
260
- return (
261
- <div
262
- {...props}
263
- className={clsx('flex flex-row items-center gap-2', className)}
264
- >
265
- {hasValue ? (
266
- <>
267
- {valid ? (
268
- <CheckMarkIcon
269
- className="inline-block w-4 h-4 text-success"
270
- title={t`Valid`}
271
- />
272
- ) : (
273
- <XMarkIcon
274
- className="inline-block w-4 h-4 text-error"
275
- title={t`Invalid`}
276
- />
277
- )}
278
- </>
279
- ) : (
280
- <div aria-hidden className="w-4 h-4 flex items-center justify-center">
281
- <div className="bg-gray-300 dark:bg-slate-600 rounded-full w-2 h-2" />
282
- </div>
283
- )}
284
- <div className="text-sm">{children}</div>
285
- </div>
286
- )
287
- }
@@ -1,108 +0,0 @@
1
- import type HCaptcha from '@hcaptcha/react-hcaptcha'
2
- import {
3
- ForwardedRef,
4
- ReactNode,
5
- lazy,
6
- useCallback,
7
- useRef,
8
- useState,
9
- } from 'react'
10
- import {
11
- FormCardAsync,
12
- FormCardAsyncProps,
13
- } from '../../../components/forms/form-card-async.tsx'
14
- import { useBrowserColorScheme } from '../../../hooks/use-browser-color-scheme.ts'
15
- import { mergeRefs } from '../../../lib/ref.ts'
16
- import { Override } from '../../../lib/util.ts'
17
-
18
- export type SignUpHcaptchaFormProps = Override<
19
- Omit<
20
- FormCardAsyncProps,
21
- 'append' | 'onSubmit' | 'submitLabel' | 'onCancel' | 'cancelLabel'
22
- >,
23
- {
24
- siteKey: string
25
-
26
- token?: string
27
- onToken: (token: string, ekey: string) => void
28
-
29
- prevLabel?: ReactNode
30
- onPrev?: () => void
31
-
32
- nextLabel?: ReactNode
33
- onNext: (signal: AbortSignal) => void | PromiseLike<void>
34
-
35
- ref?: ForwardedRef<HCaptcha>
36
- }
37
- >
38
-
39
- const HCaptchaLazy = lazy(() => import('@hcaptcha/react-hcaptcha'))
40
-
41
- export function SignUpHcaptchaForm({
42
- siteKey,
43
-
44
- token: tokenInit,
45
- onToken,
46
-
47
- prevLabel,
48
- onPrev,
49
-
50
- nextLabel,
51
- onNext,
52
-
53
- ref,
54
-
55
- // FormCardProps
56
- invalid,
57
- children,
58
- ...props
59
- }: SignUpHcaptchaFormProps) {
60
- const captchaRef = useRef<HCaptcha>(null)
61
- const theme = useBrowserColorScheme()
62
- const [token, setToken] = useState<string | undefined>(tokenInit)
63
-
64
- const onLoad = useCallback(() => {
65
- // this reaches out to the hCaptcha JS API and runs the
66
- // execute function on it. you can use other functions as
67
- // documented here:
68
- // https://docs.hcaptcha.com/configuration#jsapi
69
- captchaRef.current?.execute()
70
- }, [])
71
-
72
- const onVerify = useCallback(
73
- (token: string, ekey: string) => {
74
- setToken(token)
75
- onToken(token, ekey)
76
- },
77
- [onToken],
78
- )
79
-
80
- const doSubmit = useCallback(
81
- (signal: AbortSignal) => {
82
- if (token) return onNext(signal)
83
- else if (captchaRef.current) captchaRef.current.execute()
84
- else throw new Error('Unable to load hCaptcha')
85
- },
86
- [token, onNext],
87
- )
88
-
89
- return (
90
- <FormCardAsync
91
- {...props}
92
- cancelLabel={prevLabel}
93
- onCancel={onPrev}
94
- submitLabel={nextLabel}
95
- onSubmit={doSubmit}
96
- append={children}
97
- invalid={invalid || !token}
98
- >
99
- <HCaptchaLazy
100
- theme={theme}
101
- sitekey={siteKey}
102
- onLoad={onLoad}
103
- onVerify={onVerify}
104
- ref={mergeRefs([ref, captchaRef])}
105
- />
106
- </FormCardAsync>
107
- )
108
- }
@@ -1,158 +0,0 @@
1
- import { Trans, useLingui } from '@lingui/react/macro'
2
- import { useCallback, useState } from 'react'
3
- import { CustomizationData } from '../../../backend-types.ts'
4
- import { WizardCard } from '../../../components/forms/wizard-card.tsx'
5
- import {
6
- LayoutTitlePage,
7
- LayoutTitlePageProps,
8
- } from '../../../components/layouts/layout-title-page.tsx'
9
- import { HelpCard } from '../../../components/utils/help-card.tsx'
10
- import { Override } from '../../../lib/util.ts'
11
- import {
12
- SignUpAccountForm,
13
- SignUpAccountFormOutput,
14
- } from './sign-up-account-form.tsx'
15
- import { SignUpDisclaimer } from './sign-up-disclaimer.tsx'
16
- import { SignUpHandleForm } from './sign-up-handle-form.tsx'
17
- import { SignUpHcaptchaForm } from './sign-up-hcaptcha-form.tsx'
18
-
19
- export type SignUpViewProps = Override<
20
- LayoutTitlePageProps,
21
- {
22
- customizationData?: CustomizationData
23
-
24
- onBack?: () => void
25
- onValidateNewHandle: (
26
- data: { handle: string },
27
- signal?: AbortSignal,
28
- ) => void | PromiseLike<void>
29
- onDone: (
30
- data: SignUpAccountFormOutput & {
31
- handle: string
32
- hcaptchaToken?: string
33
- },
34
- signal?: AbortSignal,
35
- ) => void | PromiseLike<void>
36
- }
37
- >
38
-
39
- export function SignUpView({
40
- customizationData: {
41
- availableUserDomains = [],
42
- hcaptchaSiteKey = undefined,
43
- inviteCodeRequired = true,
44
- links,
45
- } = {},
46
-
47
- onValidateNewHandle,
48
- onDone,
49
- onBack,
50
-
51
- // LayoutTitlePage
52
- ...props
53
- }: SignUpViewProps) {
54
- const { t } = useLingui()
55
- const [credentials, setCredentials] = useState<
56
- undefined | SignUpAccountFormOutput
57
- >(undefined)
58
- const [handle, setHandle] = useState<undefined | string>(undefined)
59
- const [hcaptcha, setHcaptcha] = useState<undefined | string>(undefined)
60
-
61
- /**
62
- * "false" indicates that the hcaptcha token is invalid (required but not provided)
63
- */
64
- const hcaptchaToken = hcaptchaSiteKey == null ? undefined : hcaptcha || false
65
-
66
- const doDone = useCallback(
67
- (signal: AbortSignal) => {
68
- if (credentials && handle && hcaptchaToken !== false) {
69
- return onDone({ ...credentials, handle, hcaptchaToken }, signal)
70
- }
71
- },
72
- [credentials, handle, hcaptchaToken, onDone],
73
- )
74
-
75
- return (
76
- <LayoutTitlePage
77
- {...props}
78
- title={props.title ?? t`Create Account`}
79
- subtitle={
80
- props.subtitle ?? <Trans>We're so excited to have you join us!</Trans>
81
- }
82
- >
83
- <WizardCard
84
- doneLabel={<Trans>Sign up</Trans>}
85
- onBack={onBack}
86
- onDone={doDone}
87
- steps={[
88
- // We use the handle input first since the "onValidateNewHandle" check
89
- // will make it less likely that the actual signup call will fail, and
90
- // will result in a better user experience, especially if there is an
91
- // issue with the email address (e.g. already in use).
92
- {
93
- invalid: !handle,
94
- titleRender: () => <Trans>Choose a username</Trans>,
95
- contentRender: ({ prev, prevLabel, next, nextLabel, invalid }) => (
96
- <SignUpHandleForm
97
- className="flex-grow"
98
- invalid={invalid}
99
- domains={availableUserDomains}
100
- handle={handle}
101
- onHandle={setHandle}
102
- prevLabel={prevLabel}
103
- onPrev={prev}
104
- nextLabel={nextLabel}
105
- onNext={async (signal) => {
106
- if (handle) await onValidateNewHandle({ handle }, signal)
107
- if (!signal.aborted) return next(signal)
108
- }}
109
- >
110
- <SignUpDisclaimer links={links} />
111
- </SignUpHandleForm>
112
- ),
113
- },
114
- {
115
- invalid: !credentials,
116
- titleRender: () => <Trans>Your account</Trans>,
117
- contentRender: ({ prev, prevLabel, next, nextLabel, invalid }) => (
118
- <SignUpAccountForm
119
- className="flex-grow"
120
- invalid={invalid}
121
- prevLabel={prevLabel}
122
- onPrev={prev}
123
- nextLabel={nextLabel}
124
- onNext={next}
125
- inviteCodeRequired={inviteCodeRequired}
126
- credentials={credentials}
127
- onCredentials={setCredentials}
128
- >
129
- <SignUpDisclaimer links={links} />
130
- </SignUpAccountForm>
131
- ),
132
- },
133
- hcaptchaSiteKey != null && {
134
- invalid: hcaptchaToken === false,
135
- titleRender: () => <Trans>Verify you are human</Trans>,
136
- contentRender: ({ prev, prevLabel, next, nextLabel, invalid }) => (
137
- <SignUpHcaptchaForm
138
- className="flex-grow"
139
- invalid={invalid}
140
- siteKey={hcaptchaSiteKey}
141
- token={hcaptcha}
142
- onToken={setHcaptcha}
143
- prevLabel={prevLabel}
144
- onPrev={prev}
145
- nextLabel={nextLabel}
146
- onNext={next}
147
- >
148
- <SignUpDisclaimer links={links} />
149
- </SignUpHcaptchaForm>
150
- ),
151
- },
152
- ]}
153
- />
154
-
155
- <HelpCard className="mt-4" links={links} />
156
- </LayoutTitlePage>
157
- )
158
- }
@@ -1,56 +0,0 @@
1
- import { Trans, useLingui } from '@lingui/react/macro'
2
- import { Button } from '../../../components/forms/button.tsx'
3
- import {
4
- LayoutWelcome,
5
- LayoutWelcomeProps,
6
- } from '../../../components/layouts/layout-welcome.tsx'
7
- import { Override } from '../../../lib/util.ts'
8
-
9
- export type WelcomeViewParams = Override<
10
- LayoutWelcomeProps,
11
- {
12
- onSignIn?: () => void
13
- onSignUp?: () => void
14
- onCancel?: () => void
15
- }
16
- >
17
-
18
- export function WelcomeView({
19
- onSignUp,
20
- onSignIn,
21
- onCancel,
22
-
23
- // LayoutWelcome
24
- ...props
25
- }: WelcomeViewParams) {
26
- const { t } = useLingui()
27
- return (
28
- <LayoutWelcome {...props} title={props.title ?? t`Authenticate`}>
29
- {onSignUp && (
30
- <Button
31
- className={'m-1 w-60 max-w-full min-w-min'}
32
- color={onSignIn ? 'brand' : undefined}
33
- onClick={onSignUp}
34
- >
35
- <Trans>Create a new account</Trans>
36
- </Button>
37
- )}
38
-
39
- {onSignIn && (
40
- <Button
41
- className={'m-1 w-60 max-w-full min-w-min'}
42
- color={onSignUp ? undefined : 'brand'}
43
- onClick={onSignIn}
44
- >
45
- <Trans>Sign in</Trans>
46
- </Button>
47
- )}
48
-
49
- {onCancel && (
50
- <Button className="m-1 w-60 max-w-full min-w-min" onClick={onCancel}>
51
- <Trans>Cancel</Trans>
52
- </Button>
53
- )}
54
- </LayoutWelcome>
55
- )
56
- }
@@ -1,31 +0,0 @@
1
- import { useLingui } from '@lingui/react/macro'
2
- import { memo } from 'react'
3
- import {
4
- LayoutWelcome,
5
- LayoutWelcomeProps,
6
- } from '../../components/layouts/layout-welcome.tsx'
7
- import { ErrorCard } from '../../components/utils/error-card.tsx'
8
- import { Override } from '../../lib/util.ts'
9
-
10
- export type ErrorViewProps = Override<
11
- LayoutWelcomeProps,
12
- {
13
- error: unknown
14
- }
15
- >
16
-
17
- export const ErrorView = memo(function ErrorView({
18
- error,
19
-
20
- // LayoutWelcome
21
- title,
22
- ...props
23
- }: ErrorViewProps) {
24
- const { t } = useLingui()
25
-
26
- return (
27
- <LayoutWelcome {...props} title={title ?? t`Error`}>
28
- <ErrorCard error={error} />
29
- </LayoutWelcome>
30
- )
31
- })
@@ -1,9 +0,0 @@
1
- import type { Readable } from 'node:stream'
2
-
3
- export type Asset = {
4
- url: string
5
- type?: string
6
- isEntry: boolean
7
- sha256: string
8
- createStream: () => Readable
9
- }