@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,182 +0,0 @@
|
|
1
|
-
<!doctype html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta charset="UTF-8" />
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
6
|
-
<link rel="stylesheet" href="./main.css" />
|
7
|
-
<title>OAuth Provider</title>
|
8
|
-
</head>
|
9
|
-
<body>
|
10
|
-
<div id="root"></div>
|
11
|
-
<script>
|
12
|
-
/*
|
13
|
-
* This file's purpose is to provide a way to develop the UI without
|
14
|
-
* running a full featured OAuth server. It mocks the server responses and
|
15
|
-
* provides configuration data to the UI.
|
16
|
-
*
|
17
|
-
* This file is not part of the production build.
|
18
|
-
*
|
19
|
-
* Start the development server with the following command from the
|
20
|
-
* oauth-provider root:
|
21
|
-
*
|
22
|
-
* ```sh
|
23
|
-
* pnpm run start:ui
|
24
|
-
* ```
|
25
|
-
*
|
26
|
-
* Then open the browser at http://localhost:5173/
|
27
|
-
*/
|
28
|
-
</script>
|
29
|
-
<style>
|
30
|
-
/*
|
31
|
-
* PDS branding configuration (colors), in R G B format.
|
32
|
-
*
|
33
|
-
* The variables here are meant to override the default values defined in
|
34
|
-
* main.css. These values are typically generated by the backend and
|
35
|
-
* injected into the HTML. The colors suffixed with "-c" denote the
|
36
|
-
* "contrast" color of the corresponding color name. These are also
|
37
|
-
* automatically generated by the backend from the branding colors.
|
38
|
-
*
|
39
|
-
* The default colors can be seen by commenting out a color name (and
|
40
|
-
* corresponding "-c" contrast color) below:
|
41
|
-
*/
|
42
|
-
:root {
|
43
|
-
--color-brand: 10 122 255;
|
44
|
-
--color-brand-c: 255 255 255;
|
45
|
-
--color-error: 244 11 66;
|
46
|
-
--color-error-c: 255 255 255;
|
47
|
-
--color-warning: 251 86 7;
|
48
|
-
--color-warning-c: 255 255 255;
|
49
|
-
--color-success: 2 195 154;
|
50
|
-
--color-success-c: 0 0 0;
|
51
|
-
}
|
52
|
-
</style>
|
53
|
-
<script type="module">
|
54
|
-
/*
|
55
|
-
* PDS branding configuration
|
56
|
-
*/
|
57
|
-
|
58
|
-
const name = 'Bluesky'
|
59
|
-
const links = [
|
60
|
-
{
|
61
|
-
title: { en: 'Home' },
|
62
|
-
href: 'https://bsky.social/',
|
63
|
-
rel: 'canonical', // prevents the login page from being indexed by search engines
|
64
|
-
},
|
65
|
-
{
|
66
|
-
title: { en: 'Terms of Service' },
|
67
|
-
href: 'https://bsky.social/about/support/tos',
|
68
|
-
rel: 'terms-of-service',
|
69
|
-
},
|
70
|
-
{
|
71
|
-
title: { en: 'Privacy Policy' },
|
72
|
-
href: 'https://bsky.social/about/support/privacy-policy',
|
73
|
-
rel: 'privacy-policy',
|
74
|
-
},
|
75
|
-
{
|
76
|
-
title: { en: 'Support' },
|
77
|
-
href: 'https://blueskyweb.zendesk.com/hc/en-us',
|
78
|
-
rel: 'help',
|
79
|
-
},
|
80
|
-
]
|
81
|
-
const logo = `data:image/svg+xml,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 320 286"><path fill="rgb(10,122,255)" d="M69.364 19.146c36.687 27.806 76.147 84.186 90.636 114.439 14.489-30.253 53.948-86.633 90.636-114.439C277.107-.917 320-16.44 320 32.957c0 9.865-5.603 82.875-8.889 94.729-11.423 41.208-53.045 51.719-90.071 45.357 64.719 11.12 81.182 47.953 45.627 84.785-80 82.874-106.667-44.333-106.667-44.333s-26.667 127.207-106.667 44.333c-35.555-36.832-19.092-73.665 45.627-84.785-37.026 6.362-78.648-4.149-90.071-45.357C5.603 115.832 0 42.822 0 32.957 0-16.44 42.893-.917 69.364 19.147Z" /></svg>')}`
|
82
|
-
|
83
|
-
// Provide a value here to test the "sing-in only" flow
|
84
|
-
const loginHint = undefined // 'alice.test'
|
85
|
-
|
86
|
-
// Use empty array to disable the "sing-up" flow, use a single value to
|
87
|
-
// disable the domain selector.
|
88
|
-
const availableUserDomains = ['.bsky.social', '.bsky.team']
|
89
|
-
|
90
|
-
// Use non empty string to enable hCaptcha during "sing-up" flow
|
91
|
-
const hcaptchaSiteKey = undefined
|
92
|
-
|
93
|
-
/*
|
94
|
-
* Client branding configuration
|
95
|
-
*/
|
96
|
-
|
97
|
-
// Use an "http://" URL to test the "an app on your device" flow
|
98
|
-
const clientId = 'https://example.com/client.json'
|
99
|
-
const clientName = 'My App'
|
100
|
-
const clientPolicyUri = 'https://bsky.app'
|
101
|
-
const clientTosUri = 'https://bsky.app'
|
102
|
-
const clientLogoUri = 'https://bsky.app'
|
103
|
-
|
104
|
-
// Mock data
|
105
|
-
|
106
|
-
const requestUri = 'foo-bar'
|
107
|
-
|
108
|
-
document.cookie = `csrf-${requestUri}=xyz; path=/`
|
109
|
-
|
110
|
-
window.__customizationData = {
|
111
|
-
availableUserDomains,
|
112
|
-
inviteCodeRequired: false,
|
113
|
-
hcaptchaSiteKey,
|
114
|
-
name,
|
115
|
-
links,
|
116
|
-
logo,
|
117
|
-
}
|
118
|
-
|
119
|
-
window.__authorizeData = {
|
120
|
-
clientId: clientId,
|
121
|
-
clientMetadata: {
|
122
|
-
client_id: clientId,
|
123
|
-
client_name: clientName,
|
124
|
-
policy_uri: clientPolicyUri,
|
125
|
-
tos_uri: clientTosUri,
|
126
|
-
logo_uri: clientLogoUri,
|
127
|
-
},
|
128
|
-
clientTrusted: false,
|
129
|
-
requestUri,
|
130
|
-
loginHint,
|
131
|
-
newSessionsRequireConsent: true,
|
132
|
-
sessions: [],
|
133
|
-
scopeDetails: [
|
134
|
-
{ scope: 'atproto' },
|
135
|
-
{ scope: 'transition:generic' },
|
136
|
-
{ scope: 'transition:chat.bsky' },
|
137
|
-
],
|
138
|
-
}
|
139
|
-
|
140
|
-
const origFetch = window.fetch
|
141
|
-
|
142
|
-
async function mockFetch(...args) {
|
143
|
-
const [input, init] = args
|
144
|
-
|
145
|
-
if (typeof input === 'string' && init.method === 'POST') {
|
146
|
-
const url = new URL(input, window.location)
|
147
|
-
switch (url.pathname) {
|
148
|
-
case '/oauth/authorize/sign-up':
|
149
|
-
case '/oauth/authorize/sign-in':
|
150
|
-
return new Response(
|
151
|
-
JSON.stringify({
|
152
|
-
consentRequired: false,
|
153
|
-
account: {
|
154
|
-
sub: 'did:plc:123',
|
155
|
-
name: 'Alice',
|
156
|
-
email: 'alice@test.com',
|
157
|
-
email_verified: false,
|
158
|
-
preferred_username: 'alice.test',
|
159
|
-
picture: 'https://cat.com/cat.jpg',
|
160
|
-
},
|
161
|
-
}),
|
162
|
-
{ status: 200 },
|
163
|
-
)
|
164
|
-
case '/oauth/authorize/verify-handle-availability':
|
165
|
-
case '/oauth/authorize/reset-password-request':
|
166
|
-
case '/oauth/authorize/reset-password-confirm':
|
167
|
-
return new Response(null, { status: 204 })
|
168
|
-
}
|
169
|
-
}
|
170
|
-
|
171
|
-
return origFetch.call(this, ...args)
|
172
|
-
}
|
173
|
-
|
174
|
-
Object.defineProperty(window, 'fetch', {
|
175
|
-
value: mockFetch,
|
176
|
-
writable: true,
|
177
|
-
configurable: true,
|
178
|
-
})
|
179
|
-
</script>
|
180
|
-
<script src="./main.tsx" type="module"></script>
|
181
|
-
</body>
|
182
|
-
</html>
|
@@ -1,267 +0,0 @@
|
|
1
|
-
import { Account } from '../backend-types.ts'
|
2
|
-
import {
|
3
|
-
JsonClient,
|
4
|
-
JsonErrorPayload,
|
5
|
-
JsonErrorResponse,
|
6
|
-
} from './json-client.ts'
|
7
|
-
|
8
|
-
export type { Options } from './json-client.ts'
|
9
|
-
|
10
|
-
export type AcceptData = {
|
11
|
-
sub: string
|
12
|
-
}
|
13
|
-
|
14
|
-
export type SignInData = {
|
15
|
-
locale: string
|
16
|
-
username: string
|
17
|
-
password: string
|
18
|
-
emailOtp?: string
|
19
|
-
remember?: boolean
|
20
|
-
}
|
21
|
-
|
22
|
-
export type SignUpData = {
|
23
|
-
locale: string
|
24
|
-
handle: string
|
25
|
-
email: string
|
26
|
-
password: string
|
27
|
-
inviteCode?: string
|
28
|
-
hcaptchaToken?: string
|
29
|
-
}
|
30
|
-
|
31
|
-
export type InitiatePasswordResetData = {
|
32
|
-
locale: string
|
33
|
-
email: string
|
34
|
-
}
|
35
|
-
|
36
|
-
export type ConfirmResetPasswordData = {
|
37
|
-
token: string
|
38
|
-
password: string
|
39
|
-
}
|
40
|
-
|
41
|
-
export type VerifyHandleAvailabilityData = {
|
42
|
-
handle: string
|
43
|
-
}
|
44
|
-
|
45
|
-
export type SessionResponse = {
|
46
|
-
account: Account
|
47
|
-
consentRequired: boolean
|
48
|
-
}
|
49
|
-
|
50
|
-
export class Api extends JsonClient<{
|
51
|
-
'/verify-handle-availability': {
|
52
|
-
input: VerifyHandleAvailabilityData
|
53
|
-
output: void
|
54
|
-
}
|
55
|
-
'/sign-up': {
|
56
|
-
input: SignUpData
|
57
|
-
output: SessionResponse
|
58
|
-
}
|
59
|
-
'/sign-in': {
|
60
|
-
input: SignInData
|
61
|
-
output: SessionResponse
|
62
|
-
}
|
63
|
-
'/reset-password-request': {
|
64
|
-
input: InitiatePasswordResetData
|
65
|
-
output: void
|
66
|
-
}
|
67
|
-
'/reset-password-confirm': {
|
68
|
-
input: ConfirmResetPasswordData
|
69
|
-
output: void
|
70
|
-
}
|
71
|
-
}> {
|
72
|
-
constructor(csrfToken: string) {
|
73
|
-
const baseUrl = new URL('/oauth/authorize', window.origin).toString()
|
74
|
-
super(baseUrl, csrfToken)
|
75
|
-
}
|
76
|
-
|
77
|
-
public buildAcceptUrl(data: AcceptData): URL {
|
78
|
-
const url = new URL(`${this.baseUrl}/accept`)
|
79
|
-
url.searchParams.set('account_sub', data.sub)
|
80
|
-
url.searchParams.set('csrf_token', this.csrfToken)
|
81
|
-
return url
|
82
|
-
}
|
83
|
-
|
84
|
-
public buildRejectUrl(): URL {
|
85
|
-
const url = new URL(`${this.baseUrl}/reject`)
|
86
|
-
url.searchParams.set('csrf_token', this.csrfToken)
|
87
|
-
return url
|
88
|
-
}
|
89
|
-
|
90
|
-
public static override parseError(
|
91
|
-
json: unknown,
|
92
|
-
): undefined | JsonErrorResponse {
|
93
|
-
// @NOTE Most specific errors first !
|
94
|
-
if (SecondAuthenticationFactorRequiredError.is(json)) {
|
95
|
-
return new SecondAuthenticationFactorRequiredError(json)
|
96
|
-
}
|
97
|
-
if (InvalidCredentialsError.is(json)) {
|
98
|
-
return new InvalidCredentialsError(json)
|
99
|
-
}
|
100
|
-
if (HandleUnavailableError.is(json)) {
|
101
|
-
return new HandleUnavailableError(json)
|
102
|
-
}
|
103
|
-
if (EmailTakenError.is(json)) {
|
104
|
-
return new EmailTakenError(json)
|
105
|
-
}
|
106
|
-
if (RequestExpiredError.is(json)) {
|
107
|
-
return new RequestExpiredError(json)
|
108
|
-
}
|
109
|
-
if (UnknownRequestUriError.is(json)) {
|
110
|
-
return new UnknownRequestUriError(json)
|
111
|
-
}
|
112
|
-
if (InvalidRequestError.is(json)) {
|
113
|
-
return new InvalidRequestError(json)
|
114
|
-
}
|
115
|
-
if (AccessDeniedError.is(json)) {
|
116
|
-
return new AccessDeniedError(json)
|
117
|
-
}
|
118
|
-
return super.parseError(json)
|
119
|
-
}
|
120
|
-
}
|
121
|
-
|
122
|
-
export type AccessDeniedPayload = JsonErrorPayload<'access_denied'>
|
123
|
-
export class AccessDeniedError<
|
124
|
-
P extends AccessDeniedPayload = AccessDeniedPayload,
|
125
|
-
> extends JsonErrorResponse<P> {
|
126
|
-
constructor(
|
127
|
-
payload: P,
|
128
|
-
message = payload.error_description || 'Access denied',
|
129
|
-
) {
|
130
|
-
super(payload, message)
|
131
|
-
}
|
132
|
-
|
133
|
-
static is(json: unknown): json is AccessDeniedPayload {
|
134
|
-
return super.is(json) && json.error === 'access_denied'
|
135
|
-
}
|
136
|
-
}
|
137
|
-
|
138
|
-
export type InvalidRequestPayload = JsonErrorPayload<'invalid_request'>
|
139
|
-
export class InvalidRequestError<
|
140
|
-
P extends InvalidRequestPayload = InvalidRequestPayload,
|
141
|
-
> extends JsonErrorResponse<P> {
|
142
|
-
constructor(
|
143
|
-
payload: P,
|
144
|
-
message = payload.error_description || 'Invalid request',
|
145
|
-
) {
|
146
|
-
super(payload, message)
|
147
|
-
}
|
148
|
-
|
149
|
-
static is(json: unknown): json is InvalidRequestPayload {
|
150
|
-
return super.is(json) && json.error === 'invalid_request'
|
151
|
-
}
|
152
|
-
}
|
153
|
-
|
154
|
-
export type RequestExpiredPayload = AccessDeniedPayload & {
|
155
|
-
error_description: 'This request has expired'
|
156
|
-
}
|
157
|
-
export class RequestExpiredError<
|
158
|
-
P extends RequestExpiredPayload = RequestExpiredPayload,
|
159
|
-
> extends AccessDeniedError<P> {
|
160
|
-
static is(json: unknown): json is RequestExpiredPayload {
|
161
|
-
return (
|
162
|
-
super.is(json) && json.error_description === 'This request has expired'
|
163
|
-
)
|
164
|
-
}
|
165
|
-
}
|
166
|
-
|
167
|
-
export type InvalidCredentialsPayload = InvalidRequestPayload & {
|
168
|
-
error_description: 'Invalid identifier or password'
|
169
|
-
}
|
170
|
-
export class InvalidCredentialsError<
|
171
|
-
P extends InvalidCredentialsPayload = InvalidCredentialsPayload,
|
172
|
-
> extends InvalidRequestError<P> {
|
173
|
-
static is(json: unknown): json is InvalidCredentialsPayload {
|
174
|
-
return (
|
175
|
-
super.is(json) &&
|
176
|
-
json.error_description === 'Invalid identifier or password'
|
177
|
-
)
|
178
|
-
}
|
179
|
-
}
|
180
|
-
|
181
|
-
export type UnknownRequestPayload = InvalidRequestPayload & {
|
182
|
-
error_description: 'Unknown request_uri'
|
183
|
-
}
|
184
|
-
export class UnknownRequestUriError<
|
185
|
-
P extends UnknownRequestPayload = UnknownRequestPayload,
|
186
|
-
> extends InvalidRequestError<P> {
|
187
|
-
static is(json: unknown): json is UnknownRequestPayload {
|
188
|
-
return super.is(json) && json.error_description === 'Unknown request_uri'
|
189
|
-
}
|
190
|
-
}
|
191
|
-
export type EmailTakenPayload = InvalidRequestPayload & {
|
192
|
-
error_description: 'Email already taken'
|
193
|
-
}
|
194
|
-
export class EmailTakenError<
|
195
|
-
P extends EmailTakenPayload = EmailTakenPayload,
|
196
|
-
> extends InvalidRequestError<P> {
|
197
|
-
static is(json: unknown): json is EmailTakenPayload {
|
198
|
-
return super.is(json) && json.error_description === 'Email already taken'
|
199
|
-
}
|
200
|
-
}
|
201
|
-
|
202
|
-
export type HandleUnavailablePayload =
|
203
|
-
JsonErrorPayload<'handle_unavailable'> & {
|
204
|
-
reason: 'syntax' | 'domain' | 'slur' | 'taken'
|
205
|
-
}
|
206
|
-
export class HandleUnavailableError<
|
207
|
-
P extends HandleUnavailablePayload = HandleUnavailablePayload,
|
208
|
-
> extends JsonErrorResponse<P> {
|
209
|
-
constructor(
|
210
|
-
payload: P,
|
211
|
-
message = payload.error_description || 'That handle cannot be used',
|
212
|
-
) {
|
213
|
-
super(payload, message)
|
214
|
-
}
|
215
|
-
|
216
|
-
get reason() {
|
217
|
-
return this.payload.reason
|
218
|
-
}
|
219
|
-
|
220
|
-
static is(json: unknown): json is HandleUnavailablePayload {
|
221
|
-
return (
|
222
|
-
super.is(json) &&
|
223
|
-
json.error === 'handle_unavailable' &&
|
224
|
-
'reason' in json &&
|
225
|
-
(json.reason === 'syntax' ||
|
226
|
-
json.reason === 'domain' ||
|
227
|
-
json.reason === 'slur' ||
|
228
|
-
json.reason === 'taken')
|
229
|
-
)
|
230
|
-
}
|
231
|
-
}
|
232
|
-
|
233
|
-
export type SecondAuthenticationFactorRequiredPayload =
|
234
|
-
JsonErrorPayload<'second_authentication_factor_required'> & {
|
235
|
-
type: 'emailOtp'
|
236
|
-
hint: string
|
237
|
-
}
|
238
|
-
export class SecondAuthenticationFactorRequiredError<
|
239
|
-
P extends
|
240
|
-
SecondAuthenticationFactorRequiredPayload = SecondAuthenticationFactorRequiredPayload,
|
241
|
-
> extends JsonErrorResponse<P> {
|
242
|
-
constructor(
|
243
|
-
payload: P,
|
244
|
-
message = payload.error_description ||
|
245
|
-
`${payload.type} authentication factor required (hint: ${payload.hint})`,
|
246
|
-
) {
|
247
|
-
super(payload, message)
|
248
|
-
}
|
249
|
-
|
250
|
-
get type() {
|
251
|
-
return this.payload.type
|
252
|
-
}
|
253
|
-
get hint() {
|
254
|
-
return this.payload.hint
|
255
|
-
}
|
256
|
-
|
257
|
-
static is(json: unknown): json is SecondAuthenticationFactorRequiredPayload {
|
258
|
-
return (
|
259
|
-
super.is(json) &&
|
260
|
-
json.error === 'second_authentication_factor_required' &&
|
261
|
-
'type' in json &&
|
262
|
-
json.type === 'emailOtp' &&
|
263
|
-
'hint' in json &&
|
264
|
-
typeof json.hint === 'string'
|
265
|
-
)
|
266
|
-
}
|
267
|
-
}
|
@@ -1,94 +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
|
-
|
6
|
-
export type Options = {
|
7
|
-
signal?: AbortSignal
|
8
|
-
}
|
9
|
-
|
10
|
-
export type EndpointDefinition = {
|
11
|
-
input: Json
|
12
|
-
output: Json | void
|
13
|
-
}
|
14
|
-
|
15
|
-
export class JsonClient<E extends { [Path: string]: EndpointDefinition }> {
|
16
|
-
constructor(
|
17
|
-
protected readonly baseUrl: string,
|
18
|
-
protected readonly csrfToken: string,
|
19
|
-
) {}
|
20
|
-
|
21
|
-
public async fetch<P extends string & keyof E>(
|
22
|
-
path: P,
|
23
|
-
payload: E[P]['input'],
|
24
|
-
options?: Options,
|
25
|
-
): Promise<E[P]['output']> {
|
26
|
-
const response = await fetch(`${this.baseUrl}${path}`, {
|
27
|
-
method: 'POST',
|
28
|
-
headers: {
|
29
|
-
'Content-Type': 'application/json',
|
30
|
-
'X-CSRF-Token': this.csrfToken,
|
31
|
-
},
|
32
|
-
mode: 'same-origin',
|
33
|
-
body: JSON.stringify(payload),
|
34
|
-
signal: options?.signal,
|
35
|
-
})
|
36
|
-
|
37
|
-
if (response.status === 204) {
|
38
|
-
return undefined
|
39
|
-
}
|
40
|
-
|
41
|
-
return response.json().then((json: Json) => {
|
42
|
-
if (response.ok) return json as E[P]['output']
|
43
|
-
else throw this.parseError(response, json)
|
44
|
-
})
|
45
|
-
}
|
46
|
-
|
47
|
-
protected parseError(response: Response, json: Json): Error {
|
48
|
-
const Class = this.constructor as typeof JsonClient
|
49
|
-
const error = Class.parseError(json)
|
50
|
-
if (error) return error
|
51
|
-
|
52
|
-
return new Error('Invalid JSON response', { cause: response })
|
53
|
-
}
|
54
|
-
|
55
|
-
public static parseError(json: unknown): undefined | JsonErrorResponse {
|
56
|
-
if (JsonErrorResponse.is(json)) {
|
57
|
-
return new JsonErrorResponse(json)
|
58
|
-
}
|
59
|
-
}
|
60
|
-
}
|
61
|
-
|
62
|
-
export type JsonErrorPayload<E extends string = string> = {
|
63
|
-
error: E
|
64
|
-
error_description?: string
|
65
|
-
}
|
66
|
-
|
67
|
-
export class JsonErrorResponse<
|
68
|
-
P extends JsonErrorPayload = JsonErrorPayload,
|
69
|
-
> extends Error {
|
70
|
-
constructor(
|
71
|
-
public readonly payload: P,
|
72
|
-
message = payload.error_description,
|
73
|
-
) {
|
74
|
-
super(message || `Error "${payload.error}"`)
|
75
|
-
}
|
76
|
-
|
77
|
-
get error(): string {
|
78
|
-
return this.payload.error
|
79
|
-
}
|
80
|
-
|
81
|
-
get description(): string | undefined {
|
82
|
-
return this.payload.error_description
|
83
|
-
}
|
84
|
-
|
85
|
-
static is(json: unknown): json is JsonErrorPayload {
|
86
|
-
return (
|
87
|
-
json != null &&
|
88
|
-
typeof json === 'object' &&
|
89
|
-
typeof json['error'] === 'string' &&
|
90
|
-
(json['error_description'] === undefined ||
|
91
|
-
typeof json['error_description'] === 'string')
|
92
|
-
)
|
93
|
-
}
|
94
|
-
}
|
@@ -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
|
-
}
|
@@ -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
|
-
}
|
@@ -1,13 +0,0 @@
|
|
1
|
-
export function upsert<T>(
|
2
|
-
arr: readonly T[],
|
3
|
-
item: T,
|
4
|
-
predicate: (value: T, index: number, obj: readonly T[]) => boolean,
|
5
|
-
): T[] {
|
6
|
-
const idx = arr.findIndex(predicate)
|
7
|
-
return idx === -1
|
8
|
-
? [...arr, item]
|
9
|
-
: [...arr.slice(0, idx), item, ...arr.slice(idx + 1)]
|
10
|
-
}
|
11
|
-
|
12
|
-
export type Simplify<T> = { [K in keyof T]: T[K] } & NonNullable<unknown>
|
13
|
-
export type Override<T, U> = Simplify<Omit<T, keyof U> & U>
|