@atproto/oauth-provider 0.5.1 → 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.
- package/CHANGELOG.md +39 -0
- package/dist/account/account-manager.d.ts +7 -5
- package/dist/account/account-manager.d.ts.map +1 -1
- package/dist/account/account-manager.js +34 -25
- package/dist/account/account-manager.js.map +1 -1
- package/dist/account/account-store.d.ts +13 -5
- package/dist/account/account-store.d.ts.map +1 -1
- package/dist/account/account-store.js +24 -8
- package/dist/account/account-store.js.map +1 -1
- package/dist/account/account.d.ts +1 -11
- package/dist/account/account.d.ts.map +1 -1
- package/dist/account/{sign-up-data.d.ts → sign-up-input.d.ts} +5 -5
- package/dist/account/sign-up-input.d.ts.map +1 -0
- package/dist/account/{sign-up-data.js → sign-up-input.js} +3 -3
- package/dist/account/sign-up-input.js.map +1 -0
- package/dist/assets/assets-middleware.d.ts +2 -0
- package/dist/assets/assets-middleware.d.ts.map +1 -1
- package/dist/assets/assets-middleware.js +12 -14
- package/dist/assets/assets-middleware.js.map +1 -1
- package/dist/errors/invalid-invite-code-error.d.ts +5 -0
- package/dist/errors/invalid-invite-code-error.d.ts.map +1 -0
- package/dist/errors/invalid-invite-code-error.js +11 -0
- package/dist/errors/invalid-invite-code-error.js.map +1 -0
- package/dist/errors/oauth-error.d.ts +2 -2
- package/dist/errors/oauth-error.js.map +1 -1
- package/dist/lib/csp/index.d.ts +5 -6
- package/dist/lib/csp/index.d.ts.map +1 -1
- package/dist/lib/csp/index.js +14 -11
- package/dist/lib/csp/index.js.map +1 -1
- package/dist/lib/hcaptcha.d.ts +5 -3
- package/dist/lib/hcaptcha.d.ts.map +1 -1
- package/dist/lib/hcaptcha.js +7 -4
- package/dist/lib/hcaptcha.js.map +1 -1
- package/dist/lib/html/build-document.d.ts +2 -2
- package/dist/lib/html/build-document.d.ts.map +1 -1
- package/dist/lib/html/build-document.js +11 -7
- package/dist/lib/html/build-document.js.map +1 -1
- package/dist/lib/html/html.d.ts.map +1 -1
- package/dist/lib/html/html.js +10 -13
- package/dist/lib/html/html.js.map +1 -1
- package/dist/lib/html/util.d.ts +0 -1
- package/dist/lib/html/util.d.ts.map +1 -1
- package/dist/lib/html/util.js +0 -4
- package/dist/lib/html/util.js.map +1 -1
- package/dist/lib/http/response.d.ts +3 -1
- package/dist/lib/http/response.d.ts.map +1 -1
- package/dist/lib/http/response.js +3 -0
- package/dist/lib/http/response.js.map +1 -1
- package/dist/lib/http/security-headers.d.ts +48 -0
- package/dist/lib/http/security-headers.d.ts.map +1 -0
- package/dist/lib/http/security-headers.js +62 -0
- package/dist/lib/http/security-headers.js.map +1 -0
- package/dist/lib/util/type.d.ts +8 -0
- package/dist/lib/util/type.d.ts.map +1 -1
- package/dist/lib/util/type.js.map +1 -1
- package/dist/oauth-errors.d.ts +1 -0
- package/dist/oauth-errors.d.ts.map +1 -1
- package/dist/oauth-errors.js +3 -1
- package/dist/oauth-errors.js.map +1 -1
- package/dist/oauth-hooks.d.ts +4 -25
- package/dist/oauth-hooks.d.ts.map +1 -1
- package/dist/oauth-provider.d.ts.map +1 -1
- package/dist/oauth-provider.js +26 -25
- package/dist/oauth-provider.js.map +1 -1
- package/dist/output/backend-data.d.ts +4 -0
- package/dist/output/backend-data.d.ts.map +1 -0
- package/dist/output/backend-data.js +19 -0
- package/dist/output/backend-data.js.map +1 -0
- package/dist/output/build-authorize-data.d.ts +3 -19
- package/dist/output/build-authorize-data.d.ts.map +1 -1
- package/dist/output/build-authorize-data.js.map +1 -1
- package/dist/output/build-customization-data.d.ts +11 -18
- package/dist/output/build-customization-data.d.ts.map +1 -1
- package/dist/output/build-customization-data.js +1 -1
- package/dist/output/build-customization-data.js.map +1 -1
- package/dist/output/build-error-data.d.ts +3 -0
- package/dist/output/build-error-data.d.ts.map +1 -0
- package/dist/output/build-error-data.js +10 -0
- package/dist/output/build-error-data.js.map +1 -0
- package/dist/output/build-error-payload.d.ts +2 -1
- package/dist/output/build-error-payload.d.ts.map +1 -1
- package/dist/output/build-error-payload.js.map +1 -1
- package/dist/output/output-manager.d.ts +10 -4
- package/dist/output/output-manager.d.ts.map +1 -1
- package/dist/output/output-manager.js +68 -39
- package/dist/output/output-manager.js.map +1 -1
- package/dist/output/send-web-page.d.ts +6 -10
- package/dist/output/send-web-page.d.ts.map +1 -1
- package/dist/output/send-web-page.js +27 -47
- package/dist/output/send-web-page.js.map +1 -1
- package/dist/signer/signed-token-payload.d.ts +3 -3
- package/dist/signer/signer.d.ts +2 -2
- package/package.json +7 -39
- package/src/account/account-manager.ts +55 -34
- package/src/account/account-store.ts +29 -6
- package/src/account/account.ts +1 -14
- package/src/account/{sign-up-data.ts → sign-up-input.ts} +2 -2
- package/src/assets/assets-middleware.ts +11 -17
- package/src/errors/invalid-invite-code-error.ts +10 -0
- package/src/errors/oauth-error.ts +1 -1
- package/src/lib/csp/index.ts +16 -13
- package/src/lib/hcaptcha.ts +10 -7
- package/src/lib/html/build-document.ts +15 -8
- package/src/lib/html/html.ts +11 -18
- package/src/lib/html/util.ts +0 -4
- package/src/lib/http/response.ts +9 -1
- package/src/lib/http/security-headers.ts +91 -0
- package/src/lib/util/type.ts +18 -0
- package/src/oauth-errors.ts +1 -0
- package/src/oauth-hooks.ts +4 -25
- package/src/oauth-provider.ts +40 -34
- package/src/output/backend-data.ts +18 -0
- package/src/output/build-authorize-data.ts +3 -26
- package/src/output/build-customization-data.ts +2 -13
- package/src/output/build-error-data.ts +8 -0
- package/src/output/build-error-payload.ts +4 -2
- package/src/output/output-manager.ts +86 -47
- package/src/output/send-web-page.ts +29 -58
- package/tsconfig.backend.json +1 -2
- package/tsconfig.backend.tsbuildinfo +1 -1
- package/tsconfig.json +1 -5
- package/.linguirc +0 -57
- package/dist/account/sign-up-data.d.ts.map +0 -1
- package/dist/account/sign-up-data.js.map +0 -1
- package/dist/assets/app/bundle-manifest.json +0 -614
- package/dist/assets/app/index-ItwwtJ8r.js +0 -36
- package/dist/assets/app/index-ItwwtJ8r.js.map +0 -1
- package/dist/assets/app/main-B_dNxQo_.js +0 -4
- package/dist/assets/app/main-B_dNxQo_.js.map +0 -1
- package/dist/assets/app/main-CSatvmRR.css +0 -3
- package/dist/assets/app/main-CSatvmRR.js +0 -306
- package/dist/assets/app/main-CSatvmRR.js.map +0 -1
- package/dist/assets/app/messages-BQeltXSF.js +0 -4
- package/dist/assets/app/messages-BQeltXSF.js.map +0 -1
- package/dist/assets/app/messages-BQkEhfjg.js +0 -4
- package/dist/assets/app/messages-BQkEhfjg.js.map +0 -1
- package/dist/assets/app/messages-BUjKj_UJ.js +0 -4
- package/dist/assets/app/messages-BUjKj_UJ.js.map +0 -1
- package/dist/assets/app/messages-BWIQa8fO.js +0 -4
- package/dist/assets/app/messages-BWIQa8fO.js.map +0 -1
- package/dist/assets/app/messages-BaNVb0bp.js +0 -4
- package/dist/assets/app/messages-BaNVb0bp.js.map +0 -1
- package/dist/assets/app/messages-BaizVXcF.js +0 -4
- package/dist/assets/app/messages-BaizVXcF.js.map +0 -1
- package/dist/assets/app/messages-BfoClA1Y.js +0 -4
- package/dist/assets/app/messages-BfoClA1Y.js.map +0 -1
- package/dist/assets/app/messages-BsKGDZnC.js +0 -4
- package/dist/assets/app/messages-BsKGDZnC.js.map +0 -1
- package/dist/assets/app/messages-Bu-TJhml.js +0 -4
- package/dist/assets/app/messages-Bu-TJhml.js.map +0 -1
- package/dist/assets/app/messages-BvOKnBQk.js +0 -4
- package/dist/assets/app/messages-BvOKnBQk.js.map +0 -1
- package/dist/assets/app/messages-BxDzCiWz.js +0 -4
- package/dist/assets/app/messages-BxDzCiWz.js.map +0 -1
- package/dist/assets/app/messages-CDgFOy4S.js +0 -4
- package/dist/assets/app/messages-CDgFOy4S.js.map +0 -1
- package/dist/assets/app/messages-CLbTz0o9.js +0 -4
- package/dist/assets/app/messages-CLbTz0o9.js.map +0 -1
- package/dist/assets/app/messages-CNwSh0t7.js +0 -4
- package/dist/assets/app/messages-CNwSh0t7.js.map +0 -1
- package/dist/assets/app/messages-CSMNJ6P8.js +0 -4
- package/dist/assets/app/messages-CSMNJ6P8.js.map +0 -1
- package/dist/assets/app/messages-CZQUw3mp.js +0 -4
- package/dist/assets/app/messages-CZQUw3mp.js.map +0 -1
- package/dist/assets/app/messages-CZT41oVp.js +0 -4
- package/dist/assets/app/messages-CZT41oVp.js.map +0 -1
- package/dist/assets/app/messages-C_b-d3t8.js +0 -4
- package/dist/assets/app/messages-C_b-d3t8.js.map +0 -1
- package/dist/assets/app/messages-C_u3MTc2.js +0 -4
- package/dist/assets/app/messages-C_u3MTc2.js.map +0 -1
- package/dist/assets/app/messages-Cn8nHZic.js +0 -4
- package/dist/assets/app/messages-Cn8nHZic.js.map +0 -1
- package/dist/assets/app/messages-CtDywJUm.js +0 -4
- package/dist/assets/app/messages-CtDywJUm.js.map +0 -1
- package/dist/assets/app/messages-CurtIjBF.js +0 -4
- package/dist/assets/app/messages-CurtIjBF.js.map +0 -1
- package/dist/assets/app/messages-Cv6zIbaP.js +0 -4
- package/dist/assets/app/messages-Cv6zIbaP.js.map +0 -1
- package/dist/assets/app/messages-D1eLQuPE.js +0 -4
- package/dist/assets/app/messages-D1eLQuPE.js.map +0 -1
- package/dist/assets/app/messages-D8vHEaYW.js +0 -4
- package/dist/assets/app/messages-D8vHEaYW.js.map +0 -1
- package/dist/assets/app/messages-DJ1Q4GeC.js +0 -4
- package/dist/assets/app/messages-DJ1Q4GeC.js.map +0 -1
- package/dist/assets/app/messages-DRL3exqd.js +0 -4
- package/dist/assets/app/messages-DRL3exqd.js.map +0 -1
- package/dist/assets/app/messages-DWLPQRTp.js +0 -4
- package/dist/assets/app/messages-DWLPQRTp.js.map +0 -1
- package/dist/assets/app/messages-DjVaE9YE.js +0 -4
- package/dist/assets/app/messages-DjVaE9YE.js.map +0 -1
- package/dist/assets/app/messages-DqpMfFJR.js +0 -4
- package/dist/assets/app/messages-DqpMfFJR.js.map +0 -1
- package/dist/assets/app/messages-ETjhJBEN.js +0 -4
- package/dist/assets/app/messages-ETjhJBEN.js.map +0 -1
- package/dist/assets/app/messages-EUKrgrGn.js +0 -4
- package/dist/assets/app/messages-EUKrgrGn.js.map +0 -1
- package/dist/assets/app/messages-QQrOUcPW.js +0 -4
- package/dist/assets/app/messages-QQrOUcPW.js.map +0 -1
- package/dist/assets/app/messages-e2QGqFL6.js +0 -4
- package/dist/assets/app/messages-e2QGqFL6.js.map +0 -1
- package/dist/assets/app/messages-p61py7gD.js +0 -4
- package/dist/assets/app/messages-p61py7gD.js.map +0 -1
- package/dist/assets/asset.d.ts +0 -9
- package/dist/assets/asset.d.ts.map +0 -1
- package/dist/assets/asset.js +0 -3
- package/dist/assets/asset.js.map +0 -1
- package/dist/assets/index.d.ts +0 -5
- package/dist/assets/index.d.ts.map +0 -1
- package/dist/assets/index.js +0 -78
- package/dist/assets/index.js.map +0 -1
- package/rollup.config.js +0 -98
- package/src/assets/app/app.tsx +0 -43
- package/src/assets/app/backend-data.ts +0 -27
- package/src/assets/app/backend-types.ts +0 -66
- package/src/assets/app/components/forms/button-toggle-visibility.tsx +0 -43
- package/src/assets/app/components/forms/button.tsx +0 -60
- package/src/assets/app/components/forms/fieldset.tsx +0 -55
- package/src/assets/app/components/forms/form-card-async.tsx +0 -103
- package/src/assets/app/components/forms/form-card.tsx +0 -49
- package/src/assets/app/components/forms/input-checkbox.tsx +0 -73
- package/src/assets/app/components/forms/input-container.tsx +0 -107
- package/src/assets/app/components/forms/input-email-address.tsx +0 -66
- package/src/assets/app/components/forms/input-new-password.tsx +0 -62
- package/src/assets/app/components/forms/input-password.tsx +0 -88
- package/src/assets/app/components/forms/input-text.tsx +0 -76
- package/src/assets/app/components/forms/input-token.tsx +0 -94
- package/src/assets/app/components/forms/wizard-card.tsx +0 -116
- package/src/assets/app/components/layouts/layout-title-page.tsx +0 -77
- package/src/assets/app/components/layouts/layout-welcome.tsx +0 -73
- package/src/assets/app/components/utils/account-identifier.tsx +0 -23
- package/src/assets/app/components/utils/account-image.tsx +0 -33
- package/src/assets/app/components/utils/admonition.tsx +0 -52
- package/src/assets/app/components/utils/client-name.tsx +0 -45
- package/src/assets/app/components/utils/error-card.tsx +0 -93
- package/src/assets/app/components/utils/error-message.tsx +0 -62
- package/src/assets/app/components/utils/help-card.tsx +0 -46
- package/src/assets/app/components/utils/icons.tsx +0 -88
- package/src/assets/app/components/utils/link-anchor.tsx +0 -28
- package/src/assets/app/components/utils/link-title.tsx +0 -26
- package/src/assets/app/components/utils/multi-lang-string.tsx +0 -56
- package/src/assets/app/components/utils/password-strength-label.tsx +0 -37
- package/src/assets/app/components/utils/password-strength-meter.tsx +0 -58
- package/src/assets/app/components/utils/url-viewer.tsx +0 -73
- package/src/assets/app/cookies.ts +0 -11
- package/src/assets/app/hooks/use-api.ts +0 -178
- package/src/assets/app/hooks/use-async-action.ts +0 -120
- package/src/assets/app/hooks/use-bound-dispatch.ts +0 -5
- package/src/assets/app/hooks/use-browser-color-scheme.ts +0 -31
- package/src/assets/app/hooks/use-csrf-token.ts +0 -5
- package/src/assets/app/hooks/use-random-string.ts +0 -37
- package/src/assets/app/hooks/use-stepper.ts +0 -87
- package/src/assets/app/index.html +0 -182
- package/src/assets/app/lib/api.ts +0 -267
- package/src/assets/app/lib/clsx.ts +0 -6
- package/src/assets/app/lib/json-client.ts +0 -94
- package/src/assets/app/lib/password.ts +0 -98
- package/src/assets/app/lib/ref.ts +0 -17
- package/src/assets/app/lib/util.ts +0 -13
- package/src/assets/app/locales/an/messages.po +0 -492
- package/src/assets/app/locales/ast/messages.po +0 -492
- package/src/assets/app/locales/ca/messages.po +0 -492
- package/src/assets/app/locales/da/messages.po +0 -492
- package/src/assets/app/locales/de/messages.po +0 -492
- package/src/assets/app/locales/el/messages.po +0 -492
- package/src/assets/app/locales/en/messages.po +0 -492
- package/src/assets/app/locales/en-GB/messages.po +0 -492
- package/src/assets/app/locales/es/messages.po +0 -492
- package/src/assets/app/locales/eu/messages.po +0 -492
- package/src/assets/app/locales/fi/messages.po +0 -492
- package/src/assets/app/locales/fr/messages.po +0 -492
- package/src/assets/app/locales/ga/messages.po +0 -492
- package/src/assets/app/locales/gl/messages.po +0 -492
- package/src/assets/app/locales/hi/messages.po +0 -492
- package/src/assets/app/locales/hu/messages.po +0 -492
- package/src/assets/app/locales/ia/messages.po +0 -492
- package/src/assets/app/locales/id/messages.po +0 -492
- package/src/assets/app/locales/it/messages.po +0 -492
- package/src/assets/app/locales/ja/messages.po +0 -492
- package/src/assets/app/locales/km/messages.po +0 -492
- package/src/assets/app/locales/ko/messages.po +0 -492
- package/src/assets/app/locales/load.ts +0 -8
- package/src/assets/app/locales/locale-context.ts +0 -19
- package/src/assets/app/locales/locale-provider.tsx +0 -112
- package/src/assets/app/locales/locale-selector.tsx +0 -58
- package/src/assets/app/locales/locales.ts +0 -168
- package/src/assets/app/locales/ne/messages.po +0 -492
- package/src/assets/app/locales/nl/messages.po +0 -492
- package/src/assets/app/locales/pl/messages.po +0 -492
- package/src/assets/app/locales/pt-BR/messages.po +0 -492
- package/src/assets/app/locales/ro/messages.po +0 -492
- package/src/assets/app/locales/ru/messages.po +0 -492
- package/src/assets/app/locales/sv/messages.po +0 -492
- package/src/assets/app/locales/th/messages.po +0 -492
- package/src/assets/app/locales/tr/messages.po +0 -492
- package/src/assets/app/locales/uk/messages.po +0 -492
- package/src/assets/app/locales/vi/messages.po +0 -492
- package/src/assets/app/locales/zh-CN/messages.po +0 -492
- package/src/assets/app/locales/zh-HK/messages.po +0 -492
- package/src/assets/app/locales/zh-TW/messages.po +0 -492
- package/src/assets/app/main.css +0 -33
- package/src/assets/app/main.tsx +0 -44
- package/src/assets/app/views/authorize/accept/accept-form.tsx +0 -150
- package/src/assets/app/views/authorize/accept/accept-view.tsx +0 -70
- package/src/assets/app/views/authorize/authorize-view.tsx +0 -180
- package/src/assets/app/views/authorize/reset-password/reset-password-confirm-form.tsx +0 -88
- package/src/assets/app/views/authorize/reset-password/reset-password-request-form.tsx +0 -80
- package/src/assets/app/views/authorize/reset-password/reset-password-view.tsx +0 -127
- package/src/assets/app/views/authorize/sign-in/sign-in-form.tsx +0 -244
- package/src/assets/app/views/authorize/sign-in/sign-in-picker.tsx +0 -116
- package/src/assets/app/views/authorize/sign-in/sign-in-view.tsx +0 -145
- package/src/assets/app/views/authorize/sign-up/sign-up-account-form.tsx +0 -140
- package/src/assets/app/views/authorize/sign-up/sign-up-disclaimer.tsx +0 -51
- package/src/assets/app/views/authorize/sign-up/sign-up-handle-form.tsx +0 -289
- package/src/assets/app/views/authorize/sign-up/sign-up-hcaptcha-form.tsx +0 -108
- package/src/assets/app/views/authorize/sign-up/sign-up-view.tsx +0 -158
- package/src/assets/app/views/authorize/welcome/welcome-view.tsx +0 -56
- package/src/assets/app/views/error/error-view.tsx +0 -31
- package/src/assets/asset.ts +0 -9
- package/src/assets/index.ts +0 -86
- package/tailwind.config.js +0 -31
- package/tsconfig.frontend.json +0 -11
- package/tsconfig.frontend.tsbuildinfo +0 -1
- package/tsconfig.tools.json +0 -8
- package/tsconfig.tools.tsbuildinfo +0 -1
- package/vite.config.mjs +0 -16
@@ -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,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,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
|
-
}
|