@atproto/oauth-provider-ui 0.1.0 → 0.1.2
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/dist/authorization-page-Dhx8lvtZ.js +3 -0
- package/dist/authorization-page-Dhx8lvtZ.js.map +1 -0
- package/dist/bundle-manifest.json +630 -0
- package/dist/error-page-DC6Vc-cv.js +2 -0
- package/dist/error-page-DC6Vc-cv.js.map +1 -0
- package/dist/error-view-CRGNTAn2.css +1 -0
- package/dist/error-view-MVy7C9l0.js +59 -0
- package/dist/error-view-MVy7C9l0.js.map +1 -0
- package/dist/index-CHPoD7Rp.js +20 -0
- package/dist/index-CHPoD7Rp.js.map +1 -0
- package/dist/messages-B0mgsxS-.js +2 -0
- package/dist/messages-B0mgsxS-.js.map +1 -0
- package/dist/messages-B5g8Fkio.js +2 -0
- package/dist/messages-B5g8Fkio.js.map +1 -0
- package/dist/messages-BCMss-Kt.js +2 -0
- package/dist/messages-BCMss-Kt.js.map +1 -0
- package/dist/messages-BGUrKgyK.js +2 -0
- package/dist/messages-BGUrKgyK.js.map +1 -0
- package/dist/messages-BjxAnLDp.js +2 -0
- package/dist/messages-BjxAnLDp.js.map +1 -0
- package/dist/messages-Bjysz3rI.js +2 -0
- package/dist/messages-Bjysz3rI.js.map +1 -0
- package/dist/messages-BvvEr3UX.js +2 -0
- package/dist/messages-BvvEr3UX.js.map +1 -0
- package/dist/messages-Bz6JOhJf.js +2 -0
- package/dist/messages-Bz6JOhJf.js.map +1 -0
- package/dist/messages-BzL3D1EU.js +2 -0
- package/dist/messages-BzL3D1EU.js.map +1 -0
- package/dist/messages-CAvN5UoW.js +2 -0
- package/dist/messages-CAvN5UoW.js.map +1 -0
- package/dist/messages-CEmswT1Q.js +2 -0
- package/dist/messages-CEmswT1Q.js.map +1 -0
- package/dist/messages-CHYqz0q6.js +2 -0
- package/dist/messages-CHYqz0q6.js.map +1 -0
- package/dist/messages-CRmpdijj.js +2 -0
- package/dist/messages-CRmpdijj.js.map +1 -0
- package/dist/messages-Cdb79R6S.js +2 -0
- package/dist/messages-Cdb79R6S.js.map +1 -0
- package/dist/messages-ChkJ_0WT.js +2 -0
- package/dist/messages-ChkJ_0WT.js.map +1 -0
- package/dist/messages-CqiEX6JJ.js +2 -0
- package/dist/messages-CqiEX6JJ.js.map +1 -0
- package/dist/messages-CxkHjJSR.js +2 -0
- package/dist/messages-CxkHjJSR.js.map +1 -0
- package/dist/messages-D0-cWoJ9.js +2 -0
- package/dist/messages-D0-cWoJ9.js.map +1 -0
- package/dist/messages-D2MnAxYY.js +2 -0
- package/dist/messages-D2MnAxYY.js.map +1 -0
- package/dist/messages-D5TZVsui.js +2 -0
- package/dist/messages-D5TZVsui.js.map +1 -0
- package/dist/messages-DBdV4-iw.js +2 -0
- package/dist/messages-DBdV4-iw.js.map +1 -0
- package/dist/messages-DEK3zybC.js +2 -0
- package/dist/messages-DEK3zybC.js.map +1 -0
- package/dist/messages-DGSM5jkd.js +2 -0
- package/dist/messages-DGSM5jkd.js.map +1 -0
- package/dist/messages-DJgAnSTQ.js +2 -0
- package/dist/messages-DJgAnSTQ.js.map +1 -0
- package/dist/messages-DK7O7sb_.js +2 -0
- package/dist/messages-DK7O7sb_.js.map +1 -0
- package/dist/messages-DRp7qc3j.js +2 -0
- package/dist/messages-DRp7qc3j.js.map +1 -0
- package/dist/messages-DT6xRw0m.js +2 -0
- package/dist/messages-DT6xRw0m.js.map +1 -0
- package/dist/messages-LnzLtU0L.js +2 -0
- package/dist/messages-LnzLtU0L.js.map +1 -0
- package/dist/messages-_Nk2qNGw.js +2 -0
- package/dist/messages-_Nk2qNGw.js.map +1 -0
- package/dist/messages-eHH6nZyF.js +2 -0
- package/dist/messages-eHH6nZyF.js.map +1 -0
- package/dist/messages-iNw8zY2C.js +2 -0
- package/dist/messages-iNw8zY2C.js.map +1 -0
- package/dist/messages-ipc0L8yF.js +2 -0
- package/dist/messages-ipc0L8yF.js.map +1 -0
- package/dist/messages-j7LsWm2F.js +2 -0
- package/dist/messages-j7LsWm2F.js.map +1 -0
- package/dist/messages-mgE_5UEw.js +2 -0
- package/dist/messages-mgE_5UEw.js.map +1 -0
- package/dist/messages-oRd-J5--.js +2 -0
- package/dist/messages-oRd-J5--.js.map +1 -0
- package/package.json +10 -8
- package/.linguirc +0 -57
- package/CHANGELOG.md +0 -17
- package/CONTRIBUTING.md +0 -6
- package/authorization-page.html +0 -186
- package/error-page.html +0 -118
- package/index.html +0 -13
- package/src/authorization-page.tsx +0 -49
- package/src/components/forms/button-toggle-visibility.tsx +0 -43
- package/src/components/forms/button.tsx +0 -60
- package/src/components/forms/fieldset.tsx +0 -55
- package/src/components/forms/form-card-async.tsx +0 -103
- package/src/components/forms/form-card.tsx +0 -49
- package/src/components/forms/input-checkbox.tsx +0 -78
- package/src/components/forms/input-container.tsx +0 -107
- package/src/components/forms/input-email-address.tsx +0 -65
- package/src/components/forms/input-new-password.tsx +0 -62
- package/src/components/forms/input-password.tsx +0 -87
- package/src/components/forms/input-text.tsx +0 -82
- package/src/components/forms/input-token.tsx +0 -94
- package/src/components/forms/wizard-card.tsx +0 -116
- package/src/components/layouts/layout-title-page.tsx +0 -78
- package/src/components/layouts/layout-welcome.tsx +0 -78
- package/src/components/utils/account-identifier.tsx +0 -23
- package/src/components/utils/account-image.tsx +0 -33
- package/src/components/utils/admonition.tsx +0 -52
- package/src/components/utils/client-name.tsx +0 -71
- package/src/components/utils/error-card.tsx +0 -93
- package/src/components/utils/error-message.tsx +0 -88
- package/src/components/utils/help-card.tsx +0 -46
- package/src/components/utils/icons.tsx +0 -88
- package/src/components/utils/link-anchor.tsx +0 -28
- package/src/components/utils/link-title.tsx +0 -26
- package/src/components/utils/multi-lang-string.tsx +0 -62
- package/src/components/utils/password-strength-label.tsx +0 -37
- package/src/components/utils/password-strength-meter.tsx +0 -58
- package/src/components/utils/url-viewer.tsx +0 -73
- package/src/error-page.tsx +0 -23
- package/src/hooks/use-api.ts +0 -202
- package/src/hooks/use-async-action.ts +0 -120
- package/src/hooks/use-bound-dispatch.ts +0 -5
- package/src/hooks/use-browser-color-scheme.ts +0 -31
- package/src/hooks/use-random-string.ts +0 -37
- package/src/hooks/use-stepper.ts +0 -87
- package/src/lib/api.ts +0 -225
- package/src/lib/cookies.ts +0 -17
- package/src/lib/json-client.ts +0 -141
- package/src/lib/password.ts +0 -98
- package/src/lib/ref.ts +0 -17
- package/src/lib/util.ts +0 -14
- package/src/locales/an/messages.po +0 -494
- package/src/locales/ast/messages.po +0 -494
- package/src/locales/ca/messages.po +0 -494
- package/src/locales/da/messages.po +0 -494
- package/src/locales/de/messages.po +0 -494
- package/src/locales/el/messages.po +0 -494
- package/src/locales/en/messages.po +0 -494
- package/src/locales/en-GB/messages.po +0 -494
- package/src/locales/es/messages.po +0 -494
- package/src/locales/eu/messages.po +0 -494
- package/src/locales/fi/messages.po +0 -494
- package/src/locales/fr/messages.po +0 -494
- package/src/locales/ga/messages.po +0 -494
- package/src/locales/gl/messages.po +0 -494
- package/src/locales/hi/messages.po +0 -494
- package/src/locales/hu/messages.po +0 -494
- package/src/locales/ia/messages.po +0 -494
- package/src/locales/id/messages.po +0 -494
- package/src/locales/it/messages.po +0 -494
- package/src/locales/ja/messages.po +0 -494
- package/src/locales/km/messages.po +0 -494
- package/src/locales/ko/messages.po +0 -494
- package/src/locales/load.ts +0 -8
- package/src/locales/locale-provider.tsx +0 -108
- package/src/locales/locale-selector.tsx +0 -57
- package/src/locales/locales.ts +0 -183
- package/src/locales/ne/messages.po +0 -494
- package/src/locales/nl/messages.po +0 -494
- package/src/locales/pl/messages.po +0 -494
- package/src/locales/pt-BR/messages.po +0 -494
- package/src/locales/ro/messages.po +0 -494
- package/src/locales/ru/messages.po +0 -494
- package/src/locales/sv/messages.po +0 -494
- package/src/locales/th/messages.po +0 -494
- package/src/locales/tr/messages.po +0 -494
- package/src/locales/uk/messages.po +0 -494
- package/src/locales/vi/messages.po +0 -494
- package/src/locales/zh-CN/messages.po +0 -494
- package/src/locales/zh-HK/messages.po +0 -494
- package/src/locales/zh-TW/messages.po +0 -494
- package/src/style.css +0 -219
- package/src/views/authorize/accept/accept-form.tsx +0 -155
- package/src/views/authorize/accept/accept-view.tsx +0 -70
- package/src/views/authorize/authorize-view.tsx +0 -186
- package/src/views/authorize/reset-password/reset-password-confirm-form.tsx +0 -88
- package/src/views/authorize/reset-password/reset-password-request-form.tsx +0 -80
- package/src/views/authorize/reset-password/reset-password-view.tsx +0 -127
- package/src/views/authorize/sign-in/sign-in-form.tsx +0 -240
- package/src/views/authorize/sign-in/sign-in-picker.tsx +0 -116
- package/src/views/authorize/sign-in/sign-in-view.tsx +0 -145
- package/src/views/authorize/sign-up/sign-up-account-form.tsx +0 -142
- package/src/views/authorize/sign-up/sign-up-disclaimer.tsx +0 -51
- package/src/views/authorize/sign-up/sign-up-handle-form.tsx +0 -287
- package/src/views/authorize/sign-up/sign-up-hcaptcha-form.tsx +0 -108
- package/src/views/authorize/sign-up/sign-up-view.tsx +0 -158
- package/src/views/authorize/welcome/welcome-view.tsx +0 -56
- package/src/views/error/error-view.tsx +0 -31
- package/tsconfig.json +0 -7
- package/tsconfig.src.json +0 -13
- package/tsconfig.src.tsbuildinfo +0 -1
- package/tsconfig.tools.json +0 -8
- package/tsconfig.tools.tsbuildinfo +0 -1
- package/vite.config.mjs +0 -47
- /package/{src/hydration-data.d.ts → hydration-data.d.ts} +0 -0
package/src/hooks/use-stepper.ts
DELETED
|
@@ -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
|
-
}
|
package/src/lib/api.ts
DELETED
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
API_ENDPOINT_PREFIX,
|
|
3
|
-
ApiEndpoints,
|
|
4
|
-
CSRF_COOKIE_NAME,
|
|
5
|
-
CSRF_HEADER_NAME,
|
|
6
|
-
} from '@atproto/oauth-provider-api'
|
|
7
|
-
import { readCookie } from './cookies.ts'
|
|
8
|
-
import {
|
|
9
|
-
JsonClient,
|
|
10
|
-
JsonErrorPayload,
|
|
11
|
-
JsonErrorResponse,
|
|
12
|
-
} from './json-client.ts'
|
|
13
|
-
|
|
14
|
-
export type { Options } from './json-client.ts'
|
|
15
|
-
|
|
16
|
-
export class Api extends JsonClient<ApiEndpoints> {
|
|
17
|
-
constructor() {
|
|
18
|
-
const baseUrl = new URL(API_ENDPOINT_PREFIX, window.origin).toString()
|
|
19
|
-
super(baseUrl, () => ({
|
|
20
|
-
[CSRF_HEADER_NAME]: readCookie(CSRF_COOKIE_NAME),
|
|
21
|
-
}))
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Override the parent's parseError method to handle expected error responses
|
|
25
|
-
// and transform them into instances of the corresponding error classes.
|
|
26
|
-
public static override parseError(
|
|
27
|
-
json: unknown,
|
|
28
|
-
): undefined | JsonErrorResponse {
|
|
29
|
-
// @NOTE Most specific errors first !
|
|
30
|
-
if (SecondAuthenticationFactorRequiredError.is(json)) {
|
|
31
|
-
return new SecondAuthenticationFactorRequiredError(json)
|
|
32
|
-
}
|
|
33
|
-
if (InvalidCredentialsError.is(json)) {
|
|
34
|
-
return new InvalidCredentialsError(json)
|
|
35
|
-
}
|
|
36
|
-
if (InvalidInviteCodeError.is(json)) {
|
|
37
|
-
return new InvalidInviteCodeError(json)
|
|
38
|
-
}
|
|
39
|
-
if (HandleUnavailableError.is(json)) {
|
|
40
|
-
return new HandleUnavailableError(json)
|
|
41
|
-
}
|
|
42
|
-
if (EmailTakenError.is(json)) {
|
|
43
|
-
return new EmailTakenError(json)
|
|
44
|
-
}
|
|
45
|
-
if (RequestExpiredError.is(json)) {
|
|
46
|
-
return new RequestExpiredError(json)
|
|
47
|
-
}
|
|
48
|
-
if (UnknownRequestUriError.is(json)) {
|
|
49
|
-
return new UnknownRequestUriError(json)
|
|
50
|
-
}
|
|
51
|
-
if (InvalidRequestError.is(json)) {
|
|
52
|
-
return new InvalidRequestError(json)
|
|
53
|
-
}
|
|
54
|
-
if (AccessDeniedError.is(json)) {
|
|
55
|
-
return new AccessDeniedError(json)
|
|
56
|
-
}
|
|
57
|
-
return super.parseError(json)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export type AccessDeniedPayload = JsonErrorPayload<'access_denied'>
|
|
62
|
-
export class AccessDeniedError<
|
|
63
|
-
P extends AccessDeniedPayload = AccessDeniedPayload,
|
|
64
|
-
> extends JsonErrorResponse<P> {
|
|
65
|
-
constructor(
|
|
66
|
-
payload: P,
|
|
67
|
-
message = payload.error_description || 'Access denied',
|
|
68
|
-
) {
|
|
69
|
-
super(payload, message)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
static is(json: unknown): json is AccessDeniedPayload {
|
|
73
|
-
return super.is(json) && json.error === 'access_denied'
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export type InvalidRequestPayload = JsonErrorPayload<'invalid_request'>
|
|
78
|
-
export class InvalidRequestError<
|
|
79
|
-
P extends InvalidRequestPayload = InvalidRequestPayload,
|
|
80
|
-
> extends JsonErrorResponse<P> {
|
|
81
|
-
constructor(
|
|
82
|
-
payload: P,
|
|
83
|
-
message = payload.error_description || 'Invalid request',
|
|
84
|
-
) {
|
|
85
|
-
super(payload, message)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
static is(json: unknown): json is InvalidRequestPayload {
|
|
89
|
-
return super.is(json) && json.error === 'invalid_request'
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export type InvalidInviteCodePayload = InvalidRequestPayload & {
|
|
94
|
-
error_description: `This invite code is invalid.${string}`
|
|
95
|
-
}
|
|
96
|
-
export class InvalidInviteCodeError<
|
|
97
|
-
P extends InvalidInviteCodePayload = InvalidInviteCodePayload,
|
|
98
|
-
> extends InvalidRequestError<P> {
|
|
99
|
-
constructor(payload: P) {
|
|
100
|
-
super(payload)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
static is(json: unknown): json is InvalidInviteCodePayload {
|
|
104
|
-
return (
|
|
105
|
-
super.is(json) &&
|
|
106
|
-
json.error_description != null &&
|
|
107
|
-
json.error_description.startsWith('This invite code is invalid.')
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export type RequestExpiredPayload = AccessDeniedPayload & {
|
|
113
|
-
error_description: 'This request has expired'
|
|
114
|
-
}
|
|
115
|
-
export class RequestExpiredError<
|
|
116
|
-
P extends RequestExpiredPayload = RequestExpiredPayload,
|
|
117
|
-
> extends AccessDeniedError<P> {
|
|
118
|
-
static is(json: unknown): json is RequestExpiredPayload {
|
|
119
|
-
return (
|
|
120
|
-
super.is(json) && json.error_description === 'This request has expired'
|
|
121
|
-
)
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export type InvalidCredentialsPayload = InvalidRequestPayload & {
|
|
126
|
-
error_description: 'Invalid identifier or password'
|
|
127
|
-
}
|
|
128
|
-
export class InvalidCredentialsError<
|
|
129
|
-
P extends InvalidCredentialsPayload = InvalidCredentialsPayload,
|
|
130
|
-
> extends InvalidRequestError<P> {
|
|
131
|
-
static is(json: unknown): json is InvalidCredentialsPayload {
|
|
132
|
-
return (
|
|
133
|
-
super.is(json) &&
|
|
134
|
-
json.error_description === 'Invalid identifier or password'
|
|
135
|
-
)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export type UnknownRequestPayload = InvalidRequestPayload & {
|
|
140
|
-
error_description: 'Unknown request_uri'
|
|
141
|
-
}
|
|
142
|
-
export class UnknownRequestUriError<
|
|
143
|
-
P extends UnknownRequestPayload = UnknownRequestPayload,
|
|
144
|
-
> extends InvalidRequestError<P> {
|
|
145
|
-
static is(json: unknown): json is UnknownRequestPayload {
|
|
146
|
-
return super.is(json) && json.error_description === 'Unknown request_uri'
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
export type EmailTakenPayload = InvalidRequestPayload & {
|
|
150
|
-
error_description: 'Email already taken'
|
|
151
|
-
}
|
|
152
|
-
export class EmailTakenError<
|
|
153
|
-
P extends EmailTakenPayload = EmailTakenPayload,
|
|
154
|
-
> extends InvalidRequestError<P> {
|
|
155
|
-
static is(json: unknown): json is EmailTakenPayload {
|
|
156
|
-
return super.is(json) && json.error_description === 'Email already taken'
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export type HandleUnavailablePayload =
|
|
161
|
-
JsonErrorPayload<'handle_unavailable'> & {
|
|
162
|
-
reason: 'syntax' | 'domain' | 'slur' | 'taken'
|
|
163
|
-
}
|
|
164
|
-
export class HandleUnavailableError<
|
|
165
|
-
P extends HandleUnavailablePayload = HandleUnavailablePayload,
|
|
166
|
-
> extends JsonErrorResponse<P> {
|
|
167
|
-
constructor(
|
|
168
|
-
payload: P,
|
|
169
|
-
message = payload.error_description || 'That handle cannot be used',
|
|
170
|
-
) {
|
|
171
|
-
super(payload, message)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
get reason() {
|
|
175
|
-
return this.payload.reason
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
static is(json: unknown): json is HandleUnavailablePayload {
|
|
179
|
-
return (
|
|
180
|
-
super.is(json) &&
|
|
181
|
-
json.error === 'handle_unavailable' &&
|
|
182
|
-
'reason' in json &&
|
|
183
|
-
(json.reason === 'syntax' ||
|
|
184
|
-
json.reason === 'domain' ||
|
|
185
|
-
json.reason === 'slur' ||
|
|
186
|
-
json.reason === 'taken')
|
|
187
|
-
)
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export type SecondAuthenticationFactorRequiredPayload =
|
|
192
|
-
JsonErrorPayload<'second_authentication_factor_required'> & {
|
|
193
|
-
type: 'emailOtp'
|
|
194
|
-
hint: string
|
|
195
|
-
}
|
|
196
|
-
export class SecondAuthenticationFactorRequiredError<
|
|
197
|
-
P extends
|
|
198
|
-
SecondAuthenticationFactorRequiredPayload = SecondAuthenticationFactorRequiredPayload,
|
|
199
|
-
> extends JsonErrorResponse<P> {
|
|
200
|
-
constructor(
|
|
201
|
-
payload: P,
|
|
202
|
-
message = payload.error_description ||
|
|
203
|
-
`${payload.type} authentication factor required (hint: ${payload.hint})`,
|
|
204
|
-
) {
|
|
205
|
-
super(payload, message)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
get type() {
|
|
209
|
-
return this.payload.type
|
|
210
|
-
}
|
|
211
|
-
get hint() {
|
|
212
|
-
return this.payload.hint
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
static is(json: unknown): json is SecondAuthenticationFactorRequiredPayload {
|
|
216
|
-
return (
|
|
217
|
-
super.is(json) &&
|
|
218
|
-
json.error === 'second_authentication_factor_required' &&
|
|
219
|
-
'type' in json &&
|
|
220
|
-
json.type === 'emailOtp' &&
|
|
221
|
-
'hint' in json &&
|
|
222
|
-
typeof json.hint === 'string'
|
|
223
|
-
)
|
|
224
|
-
}
|
|
225
|
-
}
|
package/src/lib/cookies.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export const parseCookieString = (
|
|
2
|
-
cookie: string = document.cookie,
|
|
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 function readCookie(
|
|
12
|
-
name: string,
|
|
13
|
-
cookie: string = document.cookie,
|
|
14
|
-
): string | undefined {
|
|
15
|
-
const cookies = parseCookieString(cookie)
|
|
16
|
-
return cookies[name]
|
|
17
|
-
}
|
package/src/lib/json-client.ts
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
// Using a type import to avoid bundling this lib
|
|
2
|
-
import type { Json } from '@atproto-labs/fetch'
|
|
3
|
-
|
|
4
|
-
export { type Json }
|
|
5
|
-
type Awaitable<T> = T | PromiseLike<T>
|
|
6
|
-
|
|
7
|
-
export type Options = {
|
|
8
|
-
signal?: AbortSignal
|
|
9
|
-
bearer?: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type EndpointPath = `/${string}`
|
|
13
|
-
export type EndpointDefinition =
|
|
14
|
-
| {
|
|
15
|
-
method: 'POST'
|
|
16
|
-
input: Json
|
|
17
|
-
output: Json | void
|
|
18
|
-
}
|
|
19
|
-
| {
|
|
20
|
-
method: 'GET'
|
|
21
|
-
params?: Record<string, string | undefined>
|
|
22
|
-
output: Json | void
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export class JsonClient<
|
|
26
|
-
Endpoints extends { [Path: EndpointPath]: EndpointDefinition },
|
|
27
|
-
> {
|
|
28
|
-
constructor(
|
|
29
|
-
protected readonly baseUrl: string,
|
|
30
|
-
protected readonly getHeaders: () => Awaitable<
|
|
31
|
-
Record<string, string | undefined>
|
|
32
|
-
>,
|
|
33
|
-
) {}
|
|
34
|
-
|
|
35
|
-
public async fetch<Path extends EndpointPath & keyof Endpoints>(
|
|
36
|
-
method: Endpoints[Path]['method'],
|
|
37
|
-
path: Path,
|
|
38
|
-
input: Endpoints[Path] extends { method: 'GET' }
|
|
39
|
-
? Endpoints[Path]['params']
|
|
40
|
-
: Endpoints[Path] extends { method: 'POST' }
|
|
41
|
-
? Endpoints[Path]['input']
|
|
42
|
-
: undefined,
|
|
43
|
-
options?: Options,
|
|
44
|
-
): Promise<Endpoints[Path]['output']> {
|
|
45
|
-
const url = new URL(`${this.baseUrl}${path}`)
|
|
46
|
-
if (method === 'GET') {
|
|
47
|
-
if (input) {
|
|
48
|
-
for (const [key, value] of Object.entries(input)) {
|
|
49
|
-
url.searchParams.set(key, value)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const body = method === 'POST' ? JSON.stringify(input) : undefined
|
|
55
|
-
|
|
56
|
-
const headers = Object.entries(await this.getHeaders.call(null))
|
|
57
|
-
.filter((entry): entry is [string, string] => entry[1] != null)
|
|
58
|
-
.map(([k, v]) => [k.toLowerCase(), v] as [string, string])
|
|
59
|
-
|
|
60
|
-
if (options?.bearer) {
|
|
61
|
-
headers.push(['authorization', `Bearer ${options.bearer}`])
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const response = await fetch(url, {
|
|
65
|
-
method,
|
|
66
|
-
headers:
|
|
67
|
-
body && !headers.some(([k]) => k === 'content-type')
|
|
68
|
-
? headers.concat([['content-type', 'application/json']])
|
|
69
|
-
: headers,
|
|
70
|
-
mode: 'same-origin',
|
|
71
|
-
body,
|
|
72
|
-
signal: options?.signal,
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
if (response.status === 204) {
|
|
76
|
-
return undefined
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const responseType = response.headers.get('content-type')
|
|
80
|
-
if (responseType !== 'application/json') {
|
|
81
|
-
await response.body?.cancel()
|
|
82
|
-
throw new Error(`Invalid content type "${responseType}"`, {
|
|
83
|
-
cause: response,
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const json = await response.json()
|
|
88
|
-
|
|
89
|
-
if (response.ok) return json as Endpoints[Path]['output']
|
|
90
|
-
else throw this.parseError(response, json)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
protected parseError(response: Response, json: Json): Error {
|
|
94
|
-
const Class = this.constructor as typeof JsonClient
|
|
95
|
-
const error = Class.parseError(json)
|
|
96
|
-
if (error) return error
|
|
97
|
-
|
|
98
|
-
return new Error('Invalid JSON response', { cause: response })
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
public static parseError(json: unknown): undefined | JsonErrorResponse {
|
|
102
|
-
if (JsonErrorResponse.is(json)) {
|
|
103
|
-
return new JsonErrorResponse(json)
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export type JsonErrorPayload<E extends string = string> = {
|
|
109
|
-
error: E
|
|
110
|
-
error_description?: string
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export class JsonErrorResponse<
|
|
114
|
-
P extends JsonErrorPayload = JsonErrorPayload,
|
|
115
|
-
> extends Error {
|
|
116
|
-
constructor(
|
|
117
|
-
public readonly payload: P,
|
|
118
|
-
message = payload.error_description,
|
|
119
|
-
options?: ErrorOptions,
|
|
120
|
-
) {
|
|
121
|
-
super(message || `Error "${payload.error}"`, options)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
get error(): string {
|
|
125
|
-
return this.payload.error
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
get description(): string | undefined {
|
|
129
|
-
return this.payload.error_description
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
static is(json: unknown): json is JsonErrorPayload {
|
|
133
|
-
return (
|
|
134
|
-
json != null &&
|
|
135
|
-
typeof json === 'object' &&
|
|
136
|
-
typeof json['error'] === 'string' &&
|
|
137
|
-
(json['error_description'] === undefined ||
|
|
138
|
-
typeof json['error_description'] === 'string')
|
|
139
|
-
)
|
|
140
|
-
}
|
|
141
|
-
}
|
package/src/lib/password.ts
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
export const MIN_PASSWORD_LENGTH = 8
|
|
2
|
-
|
|
3
|
-
const EMOJI =
|
|
4
|
-
/(\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/
|
|
5
|
-
const UPPER = /[A-Z]/
|
|
6
|
-
const LOWER = /[a-z]/
|
|
7
|
-
const DEC = /[0-9]/
|
|
8
|
-
const SPECIAL = /[^a-zA-Z0-9]/
|
|
9
|
-
|
|
10
|
-
export enum PasswordStrength {
|
|
11
|
-
weak = 1,
|
|
12
|
-
moderate = 2,
|
|
13
|
-
strong = 3,
|
|
14
|
-
extra = 4,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function getPasswordStrength(pwd: string): PasswordStrength {
|
|
18
|
-
if (pwd.length < MIN_PASSWORD_LENGTH) {
|
|
19
|
-
return PasswordStrength.weak
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Very long passwords
|
|
23
|
-
if (pwd.length >= MIN_PASSWORD_LENGTH + 12) {
|
|
24
|
-
return PasswordStrength.extra
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Long passwords
|
|
28
|
-
if (pwd.length >= MIN_PASSWORD_LENGTH + 8) {
|
|
29
|
-
if (matches(pwd, [SPECIAL])) {
|
|
30
|
-
return PasswordStrength.extra
|
|
31
|
-
}
|
|
32
|
-
if (matches(pwd, [UPPER, LOWER, DEC], 2)) {
|
|
33
|
-
return PasswordStrength.extra
|
|
34
|
-
}
|
|
35
|
-
return PasswordStrength.strong
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Emojis make passwords strong
|
|
39
|
-
if (pwd.length >= MIN_PASSWORD_LENGTH) {
|
|
40
|
-
if (matches(pwd, [EMOJI])) {
|
|
41
|
-
return PasswordStrength.strong
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Pretty long passwords
|
|
46
|
-
if (pwd.length >= MIN_PASSWORD_LENGTH + 6) {
|
|
47
|
-
if (matches(pwd, [SPECIAL])) {
|
|
48
|
-
return PasswordStrength.strong
|
|
49
|
-
}
|
|
50
|
-
if (matches(pwd, [UPPER, LOWER, DEC], 2)) {
|
|
51
|
-
return PasswordStrength.strong
|
|
52
|
-
}
|
|
53
|
-
// Only 1 type of alpha-num characters
|
|
54
|
-
return PasswordStrength.moderate
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Longish password
|
|
58
|
-
if (pwd.length >= MIN_PASSWORD_LENGTH + 4) {
|
|
59
|
-
if (matches(pwd, [SPECIAL])) {
|
|
60
|
-
return PasswordStrength.moderate
|
|
61
|
-
}
|
|
62
|
-
if (matches(pwd, [UPPER, LOWER, DEC], 2)) {
|
|
63
|
-
return PasswordStrength.moderate
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Only 1 type of alpha-num characters
|
|
67
|
-
return PasswordStrength.weak
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Short password (8-11 characters)
|
|
71
|
-
if (pwd.length >= MIN_PASSWORD_LENGTH) {
|
|
72
|
-
if (matches(pwd, [SPECIAL])) {
|
|
73
|
-
return PasswordStrength.moderate
|
|
74
|
-
}
|
|
75
|
-
if (matches(pwd, [UPPER, LOWER, DEC])) {
|
|
76
|
-
return PasswordStrength.moderate
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return PasswordStrength.weak
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function matches(
|
|
84
|
-
pwd: string,
|
|
85
|
-
regexps: RegExp[],
|
|
86
|
-
regexpsCountToMatch: number = regexps.length,
|
|
87
|
-
): boolean {
|
|
88
|
-
if (regexpsCountToMatch < 1 || regexpsCountToMatch > regexps.length) {
|
|
89
|
-
throw new TypeError('Invalid regexpsCountToMatch')
|
|
90
|
-
}
|
|
91
|
-
for (const regexp of regexps) {
|
|
92
|
-
if (regexp.test(pwd)) {
|
|
93
|
-
regexpsCountToMatch--
|
|
94
|
-
if (regexpsCountToMatch === 0) return true
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return false
|
|
98
|
-
}
|
package/src/lib/ref.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ForwardedRef } from 'react'
|
|
2
|
-
|
|
3
|
-
export function updateRef<T>(ref: ForwardedRef<T>, value: T | null) {
|
|
4
|
-
if (typeof ref === 'function') {
|
|
5
|
-
ref(value)
|
|
6
|
-
} else if (ref) {
|
|
7
|
-
ref.current = value
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function mergeRefs<T>(refs: readonly (ForwardedRef<T> | undefined)[]) {
|
|
12
|
-
return (value: T | null) => {
|
|
13
|
-
for (const ref of refs) {
|
|
14
|
-
if (ref) updateRef(ref, value)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
package/src/lib/util.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function upsert<T>(
|
|
2
|
-
arr: undefined | readonly T[],
|
|
3
|
-
item: T,
|
|
4
|
-
predicate: (value: T, index: number, obj: readonly T[]) => boolean,
|
|
5
|
-
): T[] {
|
|
6
|
-
if (!arr) return [item]
|
|
7
|
-
const idx = arr.findIndex(predicate)
|
|
8
|
-
return idx === -1
|
|
9
|
-
? [...arr, item]
|
|
10
|
-
: [...arr.slice(0, idx), item, ...arr.slice(idx + 1)]
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export type Simplify<T> = { [K in keyof T]: T[K] } & NonNullable<unknown>
|
|
14
|
-
export type Override<T, U> = Simplify<Omit<T, keyof U> & U>
|