From c2294c8d5669efd87805df6aad606cb93d4610c8 Mon Sep 17 00:00:00 2001 From: Bogdan Carpusor Date: Wed, 29 Jul 2026 21:54:50 +0300 Subject: [PATCH 01/67] refactor: migrate to blume --- .github/PULL_REQUEST_TEMPLATE.md | 7 +- .github/workflows/deploy.yml | 59 +- .github/workflows/lint.yml | 9 +- .gitignore | 4 +- AGENTS.md | 10 +- CONTRIBUTING.md | 53 +- blume.config.ts | 82 + components.ts | 21 + components/ConditionalContent.astro | 15 + components/ContextCondition.astro | 19 + components/NextjsRouterTypeSelect.astro | 10 + components/PasswordlessRecipeForm.astro | 34 + components/TenantTypeSwitch.astro | 10 + components/UITypeSwitch.astro | 10 + components/VariantContent.astro | 45 + components/VariantSwitch.astro | 62 + docs/_blocks/oauth-tokens-callout.mdx | 6 - docs/_blocks/react-router-callout.mdx | 37 - docs/_templates/api-reference.md | 4 +- docs/_templates/how-to-guide.md | 4 +- docs/_templates/tutorial.md | 4 +- docs/additional-verification/_category_.json | 9 - .../_blocks/anomaly-detection-request.mdx | 352 - .../attack-protection-suite/_category_.json | 4 - .../attack-protection-suite/initial-setup.mdx | 525 +- .../attack-protection-suite/introduction.mdx | 21 +- .../attack-protection-suite/meta.ts | 7 + docs/additional-verification/captcha.mdx | 54 +- .../email-verification/_category_.json | 4 - .../email-verification/changing-style.mdx | 138 +- .../email-verification/embed-in-page.mdx | 122 +- .../hooks-and-overrides.mdx | 49 +- .../email-verification/initial-setup.mdx | 324 +- .../email-verification/introduction.mdx | 70 +- .../email-verification/manual-actions.mdx | 116 +- .../email-verification/meta.ts | 7 + .../email-verification/protecting-routes.mdx | 490 +- docs/additional-verification/meta.ts | 8 + .../mfa/_blocks/paid-feature-callout.mdx | 8 - .../mfa/_category_.json | 4 - .../mfa/backup-codes.mdx | 63 +- .../mfa/email-sms-otp/_category_.json | 4 - .../mfa/email-sms-otp/meta.ts | 7 + .../mfa/email-sms-otp/otp-for-all-users.mdx | 345 +- .../email-sms-otp/otp-for-opt-in-users.mdx | 178 +- .../mfa/embed-the-prebuilt-ui.mdx | 128 +- .../mfa/hooks-and-overrides.mdx | 38 +- .../mfa/important-concepts.mdx | 51 +- .../mfa/initial-setup.mdx | 814 +- .../mfa/introduction.mdx | 139 +- .../mfa/legacy-mfa/_category_.json | 4 - .../legacy-mfa/backend-setup/_category_.json | 4 - .../legacy-mfa/backend-setup/first-factor.mdx | 256 +- .../mfa/legacy-mfa/backend-setup/meta.ts | 6 + .../backend-setup/protecting-api.mdx | 79 +- .../backend-setup/second-factor.mdx | 401 +- .../mfa/legacy-mfa/frontend-custom.mdx | 155 +- .../mfa/legacy-mfa/how-it-works.mdx | 17 +- .../mfa/legacy-mfa/legacy-vs-new.mdx | 14 +- .../mfa/legacy-mfa/meta.ts | 7 + .../legacy-mfa/prebuilt-ui/_category_.json | 4 - .../mfa/legacy-mfa/prebuilt-ui/init.mdx | 29 +- .../mfa/legacy-mfa/prebuilt-ui/meta.ts | 7 + .../prebuilt-ui/protecting-routes.mdx | 22 +- .../prebuilt-ui/showing-login-ui.mdx | 26 +- docs/additional-verification/mfa/meta.ts | 7 + .../mfa/migration/_category_.json | 4 - .../mfa/migration/legacy-to-new.mdx | 18 +- .../mfa/migration/meta.ts | 7 + .../mfa/migration/old-sdk-to-new.mdx | 45 +- .../mfa/protect-routes.mdx | 317 +- .../mfa/step-up-auth.mdx | 250 +- .../mfa/totp/_category_.json | 4 - docs/additional-verification/mfa/totp/meta.ts | 7 + .../mfa/totp/totp-for-all-users.mdx | 390 +- .../mfa/totp/totp-for-opt-in-users.mdx | 420 +- ...ry-factor-setup.mdx => webauthn-setup.mdx} | 325 +- .../_blocks/session-object.mdx | 458 - .../session-verification/_category_.json | 4 - .../session-verification/claim-validation.mdx | 53 +- .../session-verification/meta.ts | 7 + .../protect-api-routes.mdx | 1853 +- .../protect-frontend-routes.mdx | 205 +- .../session-verification/ssr.mdx | 85 +- .../session-verification/with-websocket.mdx | 75 +- .../_blocks/assign-role-to-session.mdx | 82 - .../_blocks/assign-role-to-user.mdx | 119 - .../user-roles/_blocks/create-role.mdx | 108 - .../user-roles/_category_.json | 4 - .../user-roles/initial-setup.mdx | 399 +- .../user-roles/introduction.mdx | 57 +- .../user-roles/meta.ts | 7 + .../user-roles/protecting-routes.mdx | 435 +- .../user-roles/role-management-actions.mdx | 740 +- docs/authentication/_category_.json | 9 - docs/authentication/ai-authentication.mdx | 33 +- .../email-password/_category_.json | 15 - .../customize-the-sign-in-form.mdx | 100 +- .../customize-the-sign-up-form.mdx | 462 +- .../email-password/disable-signup.mdx | 95 +- .../email-password/hooks-and-overrides.mdx | 230 +- .../implement-username-login.mdx | 233 +- .../email-password/introduction.mdx | 106 +- docs/authentication/email-password/meta.ts | 7 + .../email-password/password-hashing.mdx | 120 +- .../email-password/password-managers.mdx | 55 +- .../email-password/password-reset.mdx | 230 +- .../enterprise/_blocks/create-tenant.mdx | 176 - .../enterprise/_blocks/get-tenant.mdx | 160 - .../_blocks/paid-feature-banner.mdx | 9 - .../_blocks/update-tenant-config.mdx | 192 - .../authentication/enterprise/_category_.json | 4 - .../enterprise/common-domain-login.mdx | 313 +- .../enterprise/important-concepts.mdx | 17 +- .../enterprise/initial-setup.mdx | 652 +- .../enterprise/introduction.mdx | 106 +- .../authentication/enterprise/legacy-saml.mdx | 169 +- .../authentication/enterprise/manage-apps.mdx | 70 +- .../enterprise/manage-tenants.mdx | 756 +- docs/authentication/enterprise/meta.ts | 7 + docs/authentication/enterprise/saml.mdx | 41 +- .../enterprise/subdomain-login.mdx | 237 +- .../enterprise/tenant-discovery.mdx | 27 +- .../enterprise/tenant-management-plugin.mdx | 22 +- docs/authentication/m2m/_category_.json | 4 - .../authentication/m2m/client-credentials.mdx | 371 +- docs/authentication/m2m/introduction.mdx | 60 +- docs/authentication/m2m/legacy-flow.mdx | 186 +- docs/authentication/m2m/meta.ts | 7 + docs/authentication/meta.ts | 8 + docs/authentication/overview.mdx | 150 +- docs/authentication/passkeys/_category_.json | 4 - .../authentication/passkeys/customization.mdx | 76 +- .../passkeys/important-concepts.mdx | 93 +- .../authentication/passkeys/initial-setup.mdx | 352 +- docs/authentication/passkeys/introduction.mdx | 78 +- docs/authentication/passkeys/meta.ts | 7 + .../passwordless/_blocks/backend-sdk-init.mdx | 146 - .../frontend-custom-ui-magic-link-ui.mdx | 493 - .../_blocks/frontend-custom-ui-otp-ui.mdx | 444 - .../passwordless/_category_.json | 4 - .../passwordless/allow-list-flow.mdx | 74 +- .../configure-email-and-sms-behavior.mdx | 107 +- .../passwordless/customize-the-magic-link.mdx | 151 +- .../passwordless/customize-the-otp.mdx | 111 +- .../passwordless/hooks-and-overrides.mdx | 105 +- .../passwordless/initial-setup.mdx | 1551 +- .../passwordless/introduction.mdx | 106 +- .../passwordless/invite-link-flow.mdx | 161 +- docs/authentication/passwordless/meta.ts | 7 + .../social/_blocks/backend-providers-init.mdx | 310 - .../social/_blocks/backend-sdk-init.mdx | 132 - ...end-custom-ui-mobile-access-token-flow.mdx | 44 - ...stom-ui-mobile-authorization-code-flow.mdx | 666 - ...-custom-ui-web-authorization-code-flow.mdx | 261 - ...enant-provider-config-active-directory.mdx | 99 - .../multi-tenant-provider-config-apple.mdx | 185 - ...multi-tenant-provider-config-bitbucket.mdx | 111 - .../multi-tenant-provider-config-discord.mdx | 161 - .../multi-tenant-provider-config-facebook.mdx | 163 - .../multi-tenant-provider-config-github.mdx | 165 - .../multi-tenant-provider-config-gitlab.mdx | 168 - ...nant-provider-config-google-workspaces.mdx | 174 - .../multi-tenant-provider-config-google.mdx | 155 - .../multi-tenant-provider-config-linkedin.mdx | 162 - .../multi-tenant-provider-config-okta.mdx | 169 - .../multi-tenant-provider-config-saml.mdx | 180 - .../multi-tenant-provider-config-twitter.mdx | 164 - ...enant-provider-config-active-directory.mdx | 118 - .../single-tenant-provider-config-apple.mdx | 127 - ...ingle-tenant-provider-config-bitbucket.mdx | 111 - .../single-tenant-provider-config-discord.mdx | 115 - ...single-tenant-provider-config-facebook.mdx | 115 - .../single-tenant-provider-config-github.mdx | 115 - .../single-tenant-provider-config-gitlab.mdx | 118 - ...nant-provider-config-google-workspaces.mdx | 120 - .../single-tenant-provider-config-google.mdx | 111 - ...single-tenant-provider-config-linkedin.mdx | 115 - .../single-tenant-provider-config-okta.mdx | 119 - .../single-tenant-provider-config-saml.mdx | 126 - .../single-tenant-provider-config-twitter.mdx | 115 - docs/authentication/social/_category_.json | 4 - ...multiple-clients-for-the-same-provider.mdx | 105 +- .../social/built-in-providers-config.mdx | 3399 ++ .../social/built-in-providers.mdx | 191 - .../social/custom-invite-flow.mdx | 68 +- .../social/custom-providers.mdx | 205 +- .../social/hooks-and-overrides.mdx | 101 +- docs/authentication/social/initial-setup.mdx | 2150 +- docs/authentication/social/introduction.mdx | 93 +- docs/authentication/social/meta.ts | 7 + .../create-oauth2-client-request-details.mdx | 102 - .../create-oauth2-client-request-m2m.mdx | 121 - .../create-oauth2-client-request-no-auth.mdx | 129 - .../_blocks/create-oauth2-client-request.mdx | 125 - .../unified-login/_blocks/custom-ui-guide.mdx | 271 - .../_blocks/paid-feature-callout.mdx | 6 - .../unified-login/_category_.json | 4 - .../add-custom-claims-in-tokens.mdx | 54 +- .../unified-login/introduction.mdx | 107 +- docs/authentication/unified-login/meta.ts | 7 + .../unified-login/oauth2-basics.mdx | 27 +- .../quickstart-guides/_category_.json | 4 - .../unified-login/quickstart-guides/meta.ts | 7 + ...ltiple-frontends-with-a-single-backend.mdx | 744 +- ...tiple-frontends-with-separate-backends.mdx | 649 +- .../quickstart-guides/reuse-website-login.mdx | 321 +- .../unified-login/verify-tokens.mdx | 95 +- .../unified-login/work-with-scopes.mdx | 33 +- docs/deployment/_category_.json | 9 - docs/deployment/meta.ts | 8 + docs/deployment/migrate-from-mysql.mdx | 60 +- docs/deployment/rate-limits.mdx | 17 +- docs/deployment/scalability.mdx | 20 +- docs/deployment/self-host-supertokens.mdx | 141 +- docs/deployment/telemetry.mdx | 66 +- docs/index.mdx | 190 +- .../legacy/core/v10/self-host-supertokens.mdx | 219 +- .../add-users-for-bulk-import-request.mdx | 195 - .../_blocks/bulk-import-user-request.mdx | 172 - .../_blocks/count-staged-users-request.mdx | 53 - .../_blocks/get-staged-users-request.mdx | 61 - docs/migration/_category_.json | 9 - docs/migration/account-migration.mdx | 707 +- docs/migration/legacy/_category_.json | 7 - docs/migration/legacy/about.mdx | 25 +- .../legacy/account-creation/_category_.json | 4 - .../account-creation/email-verification.mdx | 17 +- .../ep-migration-without-password-hash.mdx | 110 +- .../migration/legacy/account-creation/meta.ts | 7 + .../legacy/account-creation/user-creation.mdx | 76 +- .../account-creation/user-id-mapping.mdx | 15 +- docs/migration/legacy/data-migration.mdx | 35 +- docs/migration/legacy/meta.ts | 8 + docs/migration/legacy/mfa-migration.mdx | 11 +- docs/migration/legacy/session-migration.mdx | 30 +- docs/migration/meta.ts | 8 + docs/migration/overview.mdx | 32 +- docs/migration/rownd/_category_.json | 7 - docs/migration/rownd/meta.ts | 7 + docs/migration/rownd/migration-steps.mdx | 24 +- .../migration/rownd/sdk-integration-guide.mdx | 172 +- docs/migration/session-migration.mdx | 39 +- docs/platform-configuration/_category_.json | 9 - .../platform-configuration/email-delivery.mdx | 175 +- docs/platform-configuration/meta.ts | 8 + docs/platform-configuration/sms-delivery.mdx | 187 +- .../supertokens-core/_category_.json | 4 - .../supertokens-core/add-ssl-via-nginx.mdx | 23 +- .../supertokens-core/api-keys.mdx | 57 +- .../supertokens-core/base-path.mdx | 63 +- .../supertokens-core/cli.mdx | 16 +- .../supertokens-core/ip-allow-deny.mdx | 45 +- .../supertokens-core/meta.ts | 7 + docs/post-authentication/_category_.json | 9 - .../_blocks/paid-feature-callout.mdx | 10 - .../account-linking/_category_.json | 4 - .../add-passwords-to-an-existing-account.mdx | 86 +- .../automatic-account-linking.mdx | 188 +- .../account-linking/important-concepts.mdx | 30 +- .../account-linking/introduction.mdx | 78 +- .../account-linking/link-social-accounts.mdx | 86 +- .../manual-account-linking.mdx | 167 +- .../account-linking/meta.ts | 7 + .../dashboard/_category_.json | 4 - .../dashboard/initial-setup.mdx | 136 +- .../dashboard/introduction.mdx | 53 +- docs/post-authentication/dashboard/meta.ts | 7 + .../dashboard/tenant-management.mdx | 70 +- .../dashboard/user-management.mdx | 47 +- docs/post-authentication/meta.ts | 8 + .../post-login-redirect.mdx | 98 +- .../session-management/_category_.json | 4 - .../access-session-data.mdx | 454 +- .../advanced-workflows/_category_.json | 4 - .../access-token-blacklisting.mdx | 256 +- .../advanced-workflows/anonymous-session.mdx | 81 +- .../customize-error-handling.mdx | 160 +- .../disable-frontend-interceptors.mdx | 93 +- .../advanced-workflows/in-iframe.mdx | 100 +- .../advanced-workflows/meta.ts | 7 + .../multiple-api-endpoints.mdx | 170 +- .../advanced-workflows/user-impersonation.mdx | 100 +- .../session-management/introduction.mdx | 127 +- .../session-management/meta.ts | 7 + .../session-management/security.mdx | 193 +- .../session-invalidation.mdx | 334 +- .../share-session-across-sub-domains.mdx | 108 +- ...ween-cookies-and-header-authentication.mdx | 141 +- .../user-management/_category_.json | 4 - .../user-management/account-deduplication.mdx | 42 +- .../allow-users-to-update-their-data.mdx | 279 +- .../user-management/common-actions.mdx | 376 +- .../user-management/introduction.mdx | 61 +- .../user-management/meta.ts | 7 + .../user-management/progressive-profiling.mdx | 60 +- .../user-management/user-banning.mdx | 56 +- .../user-management/user-metadata.mdx | 527 +- .../user-management/user-profile.mdx | 76 +- .../_blocks/angular-app-component.mdx | 13 - .../_blocks/angular-auth-component.mdx | 59 - docs/quickstart/_blocks/angular-routing.mdx | 26 - docs/quickstart/_blocks/curl-sign-in.mdx | 14 - .../_blocks/flutter-custom-client-session.mdx | 17 - .../_blocks/flutter-dio-request-example.mdx | 15 - .../_blocks/flutter-dio-session.mdx | 10 - .../_blocks/flutter-http-session.mdx | 11 - docs/quickstart/_blocks/go-sdk-init.mdx | 37 - .../kotlin-http-urlconnection-session.mdx | 30 - .../_blocks/kotlin-okhttp-session.mdx | 31 - docs/quickstart/_blocks/kotlin-sdk-init.mdx | 17 - .../_blocks/node-express-sdk-init.mdx | 30 - .../_blocks/node-fastify-sdk-init.mdx | 30 - .../quickstart/_blocks/node-hapi-sdk-init.mdx | 30 - docs/quickstart/_blocks/node-koa-sdk-init.mdx | 30 - .../_blocks/node-loopback-sdk-init.mdx | 30 - .../_blocks/python-django-sdk-init.mdx | 28 - .../_blocks/python-fastapi-sdk-init.mdx | 28 - .../_blocks/python-flask-sdk-init.mdx | 27 - docs/quickstart/_blocks/react-no-router.mdx | 23 - docs/quickstart/_blocks/react-router-v5.mdx | 34 - docs/quickstart/_blocks/react-router-v6.mdx | 33 - docs/quickstart/_blocks/react-sdk-init.mdx | 35 - docs/quickstart/_blocks/swift-almorife.mdx | 18 - docs/quickstart/_blocks/swift-sdk-init.mdx | 24 - .../_blocks/swift-url-session-instance.mdx | 15 - .../_blocks/swift-urlsession-shared.mdx | 11 - .../_blocks/vanilla-js-npm-check-email.mdx | 23 - .../_blocks/vanilla-js-npm-sdk-init.mdx | 18 - .../_blocks/vanilla-js-npm-sign-in.mdx | 45 - .../_blocks/vanilla-js-npm-sign-up.mdx | 49 - .../_blocks/vanilla-js-script-check-email.mdx | 22 - .../_blocks/vanilla-js-script-sdk-init.mdx | 17 - .../_blocks/vanilla-js-script-sign-in.mdx | 45 - .../_blocks/vanilla-js-script-sign-up.mdx | 48 - docs/quickstart/_blocks/vue-auth-view.mdx | 50 - docs/quickstart/_blocks/vue-main-file.mdx | 26 - docs/quickstart/_blocks/vue-routing.mdx | 29 - docs/quickstart/_category_.json | 9 - docs/quickstart/backend-setup.mdx | 757 +- docs/quickstart/build-with-ai-tools.mdx | 63 +- docs/quickstart/example-applications.mdx | 66 +- docs/quickstart/frontend-setup.mdx | 1237 +- docs/quickstart/integrations/_category_.json | 4 - .../integrations/aws-lambda/_category_.json | 6 - .../aws-lambda/appsync-integration.mdx | 21 +- .../integrations/aws-lambda/meta.ts | 7 + .../aws-lambda/quickstart-guide.mdx | 200 +- .../aws-lambda/session-verification.mdx | 171 +- docs/quickstart/integrations/graphql.mdx | 38 +- docs/quickstart/integrations/hasura.mdx | 143 +- docs/quickstart/integrations/meta.ts | 7 + docs/quickstart/integrations/nestjs.mdx | 49 +- docs/quickstart/integrations/netlify.mdx | 49 +- .../integrations/nextjs/_category_.json | 4 - .../nextjs/app-directory/_category_.json | 4 - .../nextjs/app-directory/about.mdx | 30 +- .../nextjs/app-directory/init.mdx | 79 +- .../integrations/nextjs/app-directory/meta.ts | 6 + .../nextjs/app-directory/next-steps.mdx | 39 +- .../protecting-backend/_category_.json | 4 - .../app-directory/protecting-backend/meta.ts | 7 + .../session-verification-middleware.mdx | 28 +- .../session-verification-session-guard.mdx | 22 +- .../nextjs/app-directory/protecting-route.mdx | 59 +- .../server-components-requests.mdx | 46 +- .../app-directory/setting-up-backend.mdx | 20 +- .../app-directory/setting-up-frontend.mdx | 22 +- docs/quickstart/integrations/nextjs/meta.ts | 6 + .../nextjs/pages-directory/_category_.json | 4 - .../nextjs/pages-directory/about.mdx | 29 +- .../nextjs/pages-directory/init.mdx | 77 +- .../nextjs/pages-directory/meta.ts | 6 + .../nextjs/pages-directory/next-steps.mdx | 39 +- .../protecting-backend/_category_.json | 4 - .../protecting-backend/in-api.mdx | 28 +- .../protecting-backend/in-ssr.mdx | 37 +- .../protecting-backend/meta.ts | 7 + .../pages-directory/protecting-route.mdx | 32 +- .../pages-directory/setting-up-backend.mdx | 21 +- .../pages-directory/setting-up-frontend.mdx | 22 +- docs/quickstart/integrations/overview.mdx | 121 +- docs/quickstart/integrations/supabase.mdx | 44 +- docs/quickstart/integrations/vercel.mdx | 27 +- docs/quickstart/introduction.mdx | 42 +- docs/quickstart/meta.ts | 8 + docs/quickstart/next-steps.mdx | 192 +- docs/references/_category_.json | 7 - docs/references/backend-sdks/_category_.json | 7 - .../references/backend-sdks/api-overrides.mdx | 183 +- .../backend-sdk-core-interceptor.mdx | 44 +- .../backend-sdks/function-overrides.mdx | 194 +- docs/references/backend-sdks/meta.ts | 7 + .../backend-sdks/other-frameworks.mdx | 19 +- docs/references/backend-sdks/reference.mdx | 140 +- .../supertokens-nodejs/_category_.json | 1 - .../backend-sdks/supertokens-nodejs/meta.ts | 7 + .../supertokens-nodejs/package.mdx | 49 +- .../recipe-accountlinking-types.mdx | 23 +- .../recipe-accountlinking.mdx | 79 +- .../recipe-dashboard-types.mdx | 23 +- .../supertokens-nodejs/recipe-dashboard.mdx | 23 +- .../recipe-emailpassword-types.mdx | 71 +- .../recipe-emailpassword.mdx | 67 +- .../recipe-emailverification-types.mdx | 57 +- .../recipe-emailverification.mdx | 57 +- .../supertokens-nodejs/recipe-jwt-types.mdx | 21 +- .../supertokens-nodejs/recipe-jwt.mdx | 29 +- .../recipe-multifactorauth-types.mdx | 27 +- .../recipe-multifactorauth.mdx | 29 +- .../recipe-multitenancy-types.mdx | 17 +- .../recipe-multitenancy.mdx | 43 +- .../recipe-oauth2provider-types.mdx | 151 +- .../recipe-oauth2provider.mdx | 59 +- .../recipe-openid-types.mdx | 21 +- .../supertokens-nodejs/recipe-openid.mdx | 17 +- .../recipe-passwordless-types.mdx | 25 +- .../recipe-passwordless.mdx | 79 +- .../recipe-thirdparty-types.mdx | 37 +- .../supertokens-nodejs/recipe-thirdparty.mdx | 45 +- .../supertokens-nodejs/recipe-totp-types.mdx | 21 +- .../supertokens-nodejs/recipe-totp.mdx | 23 +- .../recipe-usermetadata-types.mdx | 13 +- .../recipe-usermetadata.mdx | 29 +- .../recipe-userroles-types.mdx | 11 +- .../supertokens-nodejs/recipe-userroles.mdx | 19 +- .../recipe-webauthn-types.mdx | 137 +- .../supertokens-nodejs/recipe-webauthn.mdx | 123 +- .../backend-sdks/supertokens-nodejs/types.mdx | 43 +- docs/references/backend-sdks/user-context.mdx | 79 +- docs/references/backend-sdks/user-object.mdx | 20 +- docs/references/cdi/_category_.json | 5 - .../cdi/account-linking/_category_.json | 4 - .../get-accountlinking-user-link-check.mdx | 13 - .../get-accountlinking-user-primary-check.mdx | 13 - docs/references/cdi/account-linking/meta.ts | 7 + .../post-accountlinking-user-link.mdx | 13 - .../post-accountlinking-user-primary.mdx | 13 - .../post-accountlinking-user-unlink.mdx | 13 - docs/references/cdi/core/_category_.json | 4 - .../references/cdi/core/delete-ee-license.mdx | 11 - docs/references/cdi/core/delete-hello.mdx | 11 - docs/references/cdi/core/get-apiversion.mdx | 11 - docs/references/cdi/core/get-config.mdx | 11 - .../cdi/core/get-ee-featureflag.mdx | 11 - docs/references/cdi/core/get-ee-license.mdx | 11 - docs/references/cdi/core/get-hello.mdx | 11 - .../cdi/core/get-requests-stats.mdx | 11 - docs/references/cdi/core/get-root.mdx | 11 - docs/references/cdi/core/get-telemetry.mdx | 11 - docs/references/cdi/core/get-user-id.mdx | 11 - .../cdi/core/get-user-search-tags.mdx | 11 - docs/references/cdi/core/get-userid-map.mdx | 11 - .../cdi/core/get-users-by-accountinfo.mdx | 13 - .../cdi/core/get-users-count-active.mdx | 11 - docs/references/cdi/core/get-users-count.mdx | 11 - docs/references/cdi/core/get-users.mdx | 11 - docs/references/cdi/core/meta.ts | 7 + docs/references/cdi/core/post-hello.mdx | 11 - docs/references/cdi/core/post-user-remove.mdx | 11 - .../cdi/core/post-userid-map-remove.mdx | 11 - docs/references/cdi/core/post-userid-map.mdx | 11 - docs/references/cdi/core/put-ee-license.mdx | 11 - docs/references/cdi/core/put-hello.mdx | 11 - .../core/put-userid-external-user-id-info.mdx | 13 - docs/references/cdi/dashboard/_category_.json | 4 - .../dashboard/delete-dashboard-session.mdx | 11 - .../cdi/dashboard/delete-dashboard-user.mdx | 11 - .../get-dashboard-tenant-core-config.mdx | 13 - .../dashboard/get-dashboard-user-sessions.mdx | 13 - .../cdi/dashboard/get-dashboard-users.mdx | 11 - docs/references/cdi/dashboard/meta.ts | 7 + .../post-dashboard-session-verify.mdx | 13 - .../cdi/dashboard/post-dashboard-signin.mdx | 11 - .../cdi/dashboard/post-dashboard-user.mdx | 11 - .../cdi/dashboard/put-dashboard-user.mdx | 11 - .../cdi/email-password/_category_.json | 4 - .../cdi/email-password/get-user.mdx | 11 - docs/references/cdi/email-password/meta.ts | 7 + .../cdi/email-password/post-signin.mdx | 11 - .../cdi/email-password/post-signup.mdx | 11 - ...post-user-password-reset-token-consume.mdx | 13 - .../post-user-password-reset-token.mdx | 13 - .../post-user-password-reset.mdx | 13 - .../post-user-passwordhash-import.mdx | 13 - .../cdi/email-password/put-user.mdx | 11 - .../cdi/email-verification/_category_.json | 4 - .../get-user-email-verify.mdx | 11 - .../references/cdi/email-verification/meta.ts | 7 + .../post-user-email-verify-remove.mdx | 13 - .../post-user-email-verify-token-remove.mdx | 13 - .../post-user-email-verify-token.mdx | 13 - .../post-user-email-verify.mdx | 13 - docs/references/cdi/import/_category_.json | 4 - .../cdi/import/delete-bulk-import-users.mdx | 11 - .../import/get-bulk-import-users-count.mdx | 11 - .../cdi/import/get-bulk-import-users.mdx | 11 - docs/references/cdi/import/meta.ts | 7 + .../cdi/import/post-bulk-import-import.mdx | 11 - .../cdi/import/post-bulk-import-users.mdx | 11 - docs/references/cdi/introduction.mdx | 26 +- docs/references/cdi/meta.ts | 7 + docs/references/cdi/mfa/_category_.json | 4 - .../cdi/mfa/get-totp-device-list.mdx | 11 - docs/references/cdi/mfa/meta.ts | 7 + .../cdi/mfa/post-totp-device-import.mdx | 11 - .../cdi/mfa/post-totp-device-remove.mdx | 11 - .../cdi/mfa/post-totp-device-verify.mdx | 13 - docs/references/cdi/mfa/post-totp-device.mdx | 11 - docs/references/cdi/mfa/post-totp-verify.mdx | 13 - docs/references/cdi/mfa/put-totp-device.mdx | 11 - .../cdi/multitenancy/_category_.json | 4 - .../get-multitenancy-app-list-v2.mdx | 11 - .../get-multitenancy-app-list.mdx | 11 - ...ltitenancy-connectionuridomain-list-v2.mdx | 13 - ...-multitenancy-connectionuridomain-list.mdx | 13 - .../get-multitenancy-tenant-list-v2.mdx | 13 - .../get-multitenancy-tenant-list.mdx | 13 - .../get-multitenancy-tenant-v2.mdx | 13 - .../multitenancy/get-multitenancy-tenant.mdx | 13 - docs/references/cdi/multitenancy/meta.ts | 7 + .../post-multitenancy-app-remove.mdx | 11 - ...-multitenancy-config-thirdparty-remove.mdx | 13 - ...ultitenancy-connectionuridomain-remove.mdx | 13 - .../post-multitenancy-tenant-remove.mdx | 13 - .../post-multitenancy-tenant-user-remove.mdx | 13 - .../post-multitenancy-tenant-user.mdx | 13 - .../multitenancy/put-multitenancy-app-v2.mdx | 11 - .../cdi/multitenancy/put-multitenancy-app.mdx | 11 - .../put-multitenancy-config-thirdparty.mdx | 13 - ...ut-multitenancy-connectionuridomain-v2.mdx | 13 - .../put-multitenancy-connectionuridomain.mdx | 11 - .../put-multitenancy-tenant-v2.mdx | 13 - .../multitenancy/put-multitenancy-tenant.mdx | 11 - docs/references/cdi/oauth/_category_.json | 4 - docs/references/cdi/oauth/get-jwks.mdx | 11 - docs/references/cdi/oauth/get-oauth2-auth.mdx | 11 - .../cdi/oauth/get-oauth2-client.mdx | 11 - .../cdi/oauth/get-oauth2-clients.mdx | 11 - .../cdi/oauth/get-oauth2-consent-request.mdx | 13 - .../cdi/oauth/get-oauth2-login-request.mdx | 13 - .../cdi/oauth/get-oauth2-sessions-logout.mdx | 13 - .../references/cdi/oauth/get-oauth2-token.mdx | 11 - .../cdi/oauth/get-well-known-jwks.mdx | 11 - docs/references/cdi/oauth/meta.ts | 7 + .../cdi/oauth/post-oauth2-client-remove.mdx | 13 - .../cdi/oauth/post-oauth2-client.mdx | 11 - .../post-oauth2-consent-request-accept.mdx | 13 - .../post-oauth2-consent-request-reject.mdx | 13 - .../post-oauth2-login-request-accept.mdx | 13 - .../post-oauth2-login-request-reject.mdx | 13 - .../post-oauth2-logout-request-accept.mdx | 13 - .../post-oauth2-logout-request-reject.mdx | 13 - .../cdi/oauth/post-oauth2-session-revoke.mdx | 13 - .../oauth/post-oauth2-token-introspect.mdx | 11 - .../cdi/oauth/post-oauth2-token-revoke.mdx | 11 - .../cdi/oauth/post-oauth2-tokens-revoke.mdx | 11 - .../cdi/oauth/put-oauth2-client.mdx | 11 - .../cdi/passwordless/_category_.json | 4 - .../cdi/passwordless/get-signinup-codes.mdx | 13 - docs/references/cdi/passwordless/get-user.mdx | 11 - docs/references/cdi/passwordless/meta.ts | 7 + .../passwordless/post-signinup-code-check.mdx | 13 - .../post-signinup-code-consume.mdx | 13 - .../post-signinup-code-remove.mdx | 13 - .../cdi/passwordless/post-signinup-code.mdx | 13 - .../post-signinup-codes-remove.mdx | 13 - docs/references/cdi/passwordless/put-user.mdx | 11 - docs/references/cdi/session/_category_.json | 4 - docs/references/cdi/session/get-jwt-data.mdx | 11 - .../cdi/session/get-session-data.mdx | 11 - .../cdi/session/get-session-user.mdx | 13 - docs/references/cdi/session/get-session.mdx | 11 - docs/references/cdi/session/meta.ts | 7 + docs/references/cdi/session/post-jwt.mdx | 11 - .../cdi/session/post-session-refresh.mdx | 11 - .../cdi/session/post-session-regenerate.mdx | 11 - .../cdi/session/post-session-remove.mdx | 13 - .../cdi/session/post-session-verify.mdx | 11 - docs/references/cdi/session/post-session.mdx | 11 - docs/references/cdi/session/put-jwt-data.mdx | 11 - .../cdi/session/put-session-data.mdx | 11 - .../references/cdi/thirdparty/_category_.json | 4 - docs/references/cdi/thirdparty/get-user.mdx | 11 - .../cdi/thirdparty/get-users-by-email.mdx | 13 - docs/references/cdi/thirdparty/meta.ts | 7 + .../cdi/thirdparty/post-signinup.mdx | 11 - .../cdi/user-metadata/_category_.json | 4 - .../cdi/user-metadata/get-user-metadata.mdx | 11 - docs/references/cdi/user-metadata/meta.ts | 7 + .../post-user-metadata-remove.mdx | 13 - .../cdi/user-metadata/put-user-metadata.mdx | 11 - .../references/cdi/user-roles/_category_.json | 4 - .../cdi/user-roles/get-permission-roles.mdx | 11 - .../cdi/user-roles/get-role-permissions.mdx | 11 - .../cdi/user-roles/get-role-users.mdx | 13 - docs/references/cdi/user-roles/get-roles.mdx | 11 - .../cdi/user-roles/get-user-roles.mdx | 13 - docs/references/cdi/user-roles/meta.ts | 7 + .../post-role-permissions-remove.mdx | 13 - .../cdi/user-roles/post-role-remove.mdx | 11 - .../cdi/user-roles/post-user-role-remove.mdx | 13 - docs/references/cdi/user-roles/put-role.mdx | 11 - .../cdi/user-roles/put-user-role.mdx | 11 - docs/references/cdi/webauthn/_category_.json | 4 - .../webauthn/delete-webauthn-credential.mdx | 13 - .../cdi/webauthn/delete-webauthn-options.mdx | 13 - .../cdi/webauthn/get-webauthn-credential.mdx | 13 - .../cdi/webauthn/get-webauthn-credentials.mdx | 13 - .../cdi/webauthn/get-webauthn-options.mdx | 13 - docs/references/cdi/webauthn/meta.ts | 7 + .../cdi/webauthn/post-webauthn-recover.mdx | 13 - .../cdi/webauthn/post-webauthn-register.mdx | 13 - .../post-webauthn-registration-options.mdx | 13 - .../webauthn/post-webauthn-signin-options.mdx | 13 - .../cdi/webauthn/post-webauthn-signin.mdx | 13 - .../cdi/webauthn/post-webauthn-signup.mdx | 13 - .../webauthn/post-webauthn-token-consume.mdx | 13 - .../webauthn/post-webauthn-token-recovery.mdx | 13 - .../cdi/webauthn/put-webauthn-email.mdx | 13 - docs/references/compatibility-table.mdx | 15 +- docs/references/fdi/_category_.json | 5 - .../fdi/email-password/_category_.json | 4 - .../get-emailpassword-email-exists.mdx | 13 - .../get-signup-email-exists.mdx | 13 - docs/references/fdi/email-password/meta.ts | 7 + .../fdi/email-password/post-signin.mdx | 11 - .../fdi/email-password/post-signup.mdx | 11 - .../post-user-password-reset-token.mdx | 13 - .../post-user-password-reset.mdx | 13 - .../fdi/email-verification/_category_.json | 4 - .../get-user-email-verify.mdx | 11 - .../references/fdi/email-verification/meta.ts | 7 + .../post-user-email-verify-token.mdx | 13 - .../post-user-email-verify.mdx | 13 - docs/references/fdi/get-example.mdx | 11 - docs/references/fdi/get-jwt-jwks-json.mdx | 11 - docs/references/fdi/get-loginmethods.mdx | 11 - .../get-well-known-openid-configuration.mdx | 13 - docs/references/fdi/introduction.mdx | 27 +- docs/references/fdi/meta.ts | 7 + docs/references/fdi/mfa/_category_.json | 4 - .../fdi/mfa/get-totp-device-list.mdx | 11 - docs/references/fdi/mfa/meta.ts | 7 + .../fdi/mfa/post-totp-device-remove.mdx | 11 - .../fdi/mfa/post-totp-device-verify.mdx | 11 - docs/references/fdi/mfa/post-totp-device.mdx | 11 - docs/references/fdi/mfa/post-totp-verify.mdx | 11 - docs/references/fdi/mfa/put-mfa-info.mdx | 11 - docs/references/fdi/oauth/_category_.json | 4 - docs/references/fdi/oauth/get-oauth-auth.mdx | 11 - .../fdi/oauth/get-oauth-end_session.mdx | 11 - docs/references/fdi/oauth/get-oauth-login.mdx | 11 - .../fdi/oauth/get-oauth-logininfo.mdx | 11 - .../fdi/oauth/get-oauth-userinfo.mdx | 11 - docs/references/fdi/oauth/meta.ts | 7 + .../fdi/oauth/post-oauth-end_session.mdx | 11 - .../fdi/oauth/post-oauth-introspect.mdx | 11 - .../fdi/oauth/post-oauth-logout.mdx | 11 - .../fdi/oauth/post-oauth-revoke.mdx | 11 - .../references/fdi/oauth/post-oauth-token.mdx | 11 - .../fdi/passwordless/_category_.json | 4 - .../get-passwordless-email-exists.mdx | 13 - .../get-passwordless-phoneNumber-exists.mdx | 13 - .../passwordless/get-signup-email-exists.mdx | 13 - .../get-signup-phoneNumber-exists.mdx | 13 - docs/references/fdi/passwordless/meta.ts | 7 + .../post-signinup-code-consume.mdx | 13 - .../post-signinup-code-resend.mdx | 13 - .../fdi/passwordless/post-signinup-code.mdx | 11 - docs/references/fdi/session/_category_.json | 4 - docs/references/fdi/session/meta.ts | 7 + .../fdi/session/post-session-refresh.mdx | 11 - docs/references/fdi/session/post-signout.mdx | 11 - .../references/fdi/thirdparty/_category_.json | 4 - .../fdi/thirdparty/get-authorisationurl.mdx | 11 - docs/references/fdi/thirdparty/meta.ts | 7 + .../fdi/thirdparty/post-callback-apple.mdx | 11 - .../fdi/thirdparty/post-signinup.mdx | 11 - docs/references/fdi/webauthn/_category_.json | 4 - .../webauthn/get-webauthn-email-exists.mdx | 13 - docs/references/fdi/webauthn/meta.ts | 7 + .../fdi/webauthn/post-webauthn-credential.mdx | 13 - .../post-webauthn-recover-account-token.mdx | 13 - .../post-webauthn-recover-account.mdx | 13 - .../post-webauthn-register-options.mdx | 13 - .../webauthn/post-webauthn-signin-options.mdx | 13 - .../fdi/webauthn/post-webauthn-signin.mdx | 11 - .../fdi/webauthn/post-webauthn-signup.mdx | 11 - docs/references/frontend-sdks/_category_.json | 7 - .../frontend-sdks/function-overrides.mdx | 45 +- docs/references/frontend-sdks/hooks.mdx | 142 +- docs/references/frontend-sdks/meta.ts | 7 + .../frontend-sdks/prebuilt-ui/_category_.json | 8 - .../prebuilt-ui/changing-colours.mdx | 38 +- .../prebuilt-ui/changing-style.mdx | 121 +- .../prebuilt-ui/embed-sign-in-up-form.mdx | 180 +- .../frontend-sdks/prebuilt-ui/meta.ts | 8 + .../prebuilt-ui/override-react-components.mdx | 33 +- .../frontend-sdks/prebuilt-ui/shadow-dom.mdx | 35 +- .../prebuilt-ui/toc-privacypolicy.mdx | 31 +- .../prebuilt-ui/translations.mdx | 118 +- .../frontend-sdks/prebuilt-ui/ui-showcase.mdx | 231 +- docs/references/frontend-sdks/reference.mdx | 193 +- .../supertokens-auth-react/_category_.json | 1 - .../supertokens-auth-react/meta.ts | 7 + .../supertokens-auth-react/package.mdx | 35 +- .../recipe-emailpassword-types.mdx | 53 +- .../recipe-emailpassword.mdx | 81 +- .../recipe-emailverification-types.mdx | 37 +- .../recipe-emailverification.mdx | 57 +- .../recipe-multifactorauth-types.mdx | 33 +- .../recipe-multifactorauth.mdx | 67 +- .../recipe-multitenancy-types.mdx | 17 +- .../recipe-multitenancy.mdx | 25 +- .../recipe-oauth2provider-types.mdx | 19 +- .../recipe-oauth2provider.mdx | 31 +- .../recipe-passwordless-types.mdx | 69 +- .../recipe-passwordless.mdx | 105 +- .../recipe-session-types.mdx | 25 +- .../supertokens-auth-react/recipe-session.mdx | 103 +- .../recipe-thirdparty-types.mdx | 33 +- .../recipe-thirdparty.mdx | 91 +- .../recipe-totp-types.mdx | 41 +- .../supertokens-auth-react/recipe-totp.mdx | 65 +- .../recipe-userroles.mdx | 15 +- .../recipe-webauthn-types.mdx | 61 +- .../recipe-webauthn.mdx | 31 +- .../supertokens-auth-react/types.mdx | 69 +- .../supertokens-web-js/_category_.json | 1 - .../frontend-sdks/supertokens-web-js/meta.ts | 7 + .../supertokens-web-js/package.mdx | 23 +- .../recipe-emailpassword-types.mdx | 15 +- .../recipe-emailpassword.mdx | 35 +- .../recipe-emailverification-types.mdx | 11 +- .../recipe-emailverification.mdx | 71 +- .../recipe-multifactorauth-types.mdx | 11 +- .../recipe-multifactorauth.mdx | 59 +- .../recipe-multitenancy-types.mdx | 11 +- .../recipe-multitenancy.mdx | 37 +- .../recipe-oauth2provider-types.mdx | 11 +- .../recipe-oauth2provider.mdx | 61 +- .../recipe-passwordless-types.mdx | 13 +- .../recipe-passwordless.mdx | 71 +- .../recipe-session-types.mdx | 13 +- .../supertokens-web-js/recipe-session.mdx | 23 +- .../recipe-thirdparty-types.mdx | 13 +- .../supertokens-web-js/recipe-thirdparty.mdx | 57 +- .../supertokens-web-js/recipe-totp-types.mdx | 11 +- .../supertokens-web-js/recipe-totp.mdx | 73 +- .../supertokens-web-js/recipe-userroles.mdx | 15 +- .../recipe-webauthn-types.mdx | 37 +- .../supertokens-web-js/recipe-webauthn.mdx | 229 +- .../supertokens-web-js/types.mdx | 31 +- docs/references/how-supertokens-works.mdx | 110 +- docs/references/index.mdx | 136 +- docs/references/meta.ts | 7 + docs/references/plugins/_category_.json | 7 - docs/references/plugins/captcha-nodejs.mdx | 4 +- docs/references/plugins/captcha-react.mdx | 4 +- docs/references/plugins/introduction.mdx | 142 +- docs/references/plugins/meta.ts | 7 + .../plugins/opentelemetry-nodejs.mdx | 14 +- .../references/plugins/profile-base-react.mdx | 4 +- .../plugins/profile-details-nodejs.mdx | 4 +- .../plugins/profile-details-react.mdx | 8 +- .../plugins/profile-details-shared.mdx | 4 +- .../plugins/progressive-profiling-nodejs.mdx | 10 +- .../plugins/progressive-profiling-react.mdx | 8 +- .../plugins/progressive-profiling-shared.mdx | 4 +- .../plugins/tenant-discovery-nodejs.mdx | 4 +- .../plugins/tenant-discovery-react.mdx | 4 +- docs/references/plugins/tenants-nodejs.mdx | 12 +- docs/references/plugins/tenants-react.mdx | 6 +- .../plugins/user-banning-nodejs.mdx | 4 +- .../references/plugins/user-banning-react.mdx | 4 +- .../testing-and-debugging/_category_.json | 5 - .../testing-and-debugging/api-testing.mdx | 44 +- .../testing-and-debugging/common-issues.mdx | 27 +- .../how-to-troubleshoot.mdx | 162 +- docs/references/testing-and-debugging/meta.ts | 7 + docs/references/updating-supertokens.mdx | 33 +- docusaurus.config.ts | 196 - islands/ExampleAppForm.tsx | 53 + islands/SDKCompatibilityTable.tsx | 77 + microfrontends.jsonc | 21 + {static => openapi}/cdi.yml | 0 {static => openapi}/fdi.yml | 0 package-lock.json | 33985 ++++++---------- package.json | 105 +- {static => public}/.nojekyll | 0 {static => public}/cdi-file-paths.json | 0 {static => public}/cdi-mapping.json | 0 {static => public}/cdi.json | 0 public/cdi.yml | 10747 +++++ {static/img => public}/favicon.ico | Bin {static => public}/fdi-file-paths.json | 0 {static => public}/fdi-mapping.json | 0 {static => public}/fdi.json | 0 public/fdi.yml | 3812 ++ .../fonts/IBMPlexMono-Regular.ttf | Bin {static => public}/fonts/IBMPlexMono-Thin.ttf | Bin .../img/account-linking/err_001.png | Bin .../img/account-linking/err_002.png | Bin .../img/account-linking/err_003.png | Bin .../img/account-linking/err_004.png | Bin .../img/account-linking/err_005.png | Bin .../img/account-linking/err_006.png | Bin .../img/account-linking/err_007.png | Bin .../img/account-linking/err_008.png | Bin {static => public}/img/active-recipe-icon.png | Bin .../img/architecture/managed_service.png | Bin .../architecture/managed_service_generic.png | Bin .../managed_service_without_dashboard.png | Bin .../img/architecture/self_hosted.png | Bin .../img/architecture/self_hosted_generic.png | Bin .../self_hosted_without_dashboard.png | Bin {static => public}/img/arrow-down.svg | 0 .../sequence-diagram.png | Bin {static => public}/img/avg-latency.png | Bin {static => public}/img/change-user.png | Bin .../img/dashboard/assign-role.png | Bin .../img/dashboard/create-role.gif | Bin .../img/dashboard/create-role.png | Bin .../img/dashboard/csp-error.png | Bin .../img/dashboard/forgot-password.png | Bin {static => public}/img/dashboard/login.png | Bin .../img/dashboard/no-roles-created.png | Bin {static => public}/img/dashboard/no-users.png | Bin {static => public}/img/dashboard/one-user.png | Bin .../img/dashboard/preview-role.png | Bin .../img/dashboard/reset-password.png | Bin .../img/dashboard/roles-list.png | Bin .../img/dashboard/select-tenant.png | Bin {static => public}/img/dashboard/signup.png | Bin .../tenant-management/active-directory.png | Bin .../tenant-management/add-provider-prompt.png | Bin .../tenant-management/all-enabled.png | Bin .../tenant-management/core-config.png | Bin .../create-active-directory.gif | Bin .../create-provider/create-apple.gif | Bin .../create-provider/create-bitbucket.gif | Bin .../create-provider/create-discord.gif | Bin .../create-provider/create-facebook.gif | Bin .../create-provider/create-github.gif | Bin .../create-provider/create-gitlab.gif | Bin .../create-google-workspaces.gif | Bin .../create-provider/create-google.gif | Bin .../create-provider/create-linkedin.gif | Bin .../create-provider/create-okta.gif | Bin .../create-provider/create-public-google.gif | Bin .../create-provider/create-saml.gif | Bin .../create-provider/create-twitter.gif | Bin .../tenant-management/create-tenant.gif | Bin .../tenant-management/create-tenant.png | Bin .../custom-provider-basic-details.png | Bin .../custom-tenant-config.png | Bin .../dashboard/tenant-management/details.png | Bin .../tenant-management/edit-core-config.png | Bin .../tenant-management/enable-ep-tp.png | Bin .../enable-tp-ep-emailotp.png | Bin .../tenant-management/ep-create-tenant.gif | Bin .../tenant-management/ep-enabled.png | Bin .../dashboard/tenant-management/landing.png | Bin .../tenant-management/login-methods.png | Bin .../tenant-management/new-boxy-config.gif | Bin .../tenant-management/new-oauth-provider.png | Bin .../tenant-management/new-oidc-provider.png | Bin .../new-provider-details.png | Bin .../tenant-management/new-provider.png | Bin .../tenant-management/openid-config.png | Bin .../tenant-management/otp-email-enabled.png | Bin .../tenant-management/pl-create-tenant.gif | Bin .../tenant-management/saml-config-via-api.png | Bin .../tenant-management/saml-config.png | Bin .../tenant-management/saml-prompt.png | Bin .../tenant-management/secondary-factors.png | Bin .../tenant-management/tenant-users.png | Bin .../third-party-providers.png | Bin .../tenant-management/tp-create-tenant.gif | Bin .../tenant-management/tpep-create-tenant.gif | Bin .../tpep-create-thirdparty.gif | Bin .../tenant-management/tpl-create-tenant.gif | Bin .../img/dashboard/user-info-continued.png | Bin .../img/dashboard/user-info.png | Bin .../img/dashboard/view-assigned-roles.png | Bin {static => public}/img/discord-yellow.png | Bin {static => public}/img/discord.png | Bin .../img/docs-left-menu-chevron.png | Bin .../email-verification-clicked-no-session.png | Bin .../img/email-verification-link-expired.png | Bin .../email-verification-link-generic-error.png | Bin ...-verification-send-email-generic-error.png | Bin .../img/email-verification-send-email.png | Bin .../img/email-verification-success.png | Bin .../emailpassword-field-validation-error.png | Bin .../img/emailpassword-general-error.png | Bin .../img/emailpassword-sign-in.png | Bin .../img/emailpassword-sign-up.png | Bin .../img/emailpassword-wrong-cred.png | Bin .../img/emailpassword/buttonText.png | Bin .../img/emailpassword/change-user.png | Bin .../custom-field-name-signup-ep.png | Bin .../email-verification-successful.png | Bin .../img/emailpassword/email-verify-email.png | Bin .../img/emailpassword/error.png | Bin .../img/emailpassword/input-background.png | Bin .../img/emailpassword/inspect-button-2.png | Bin .../img/emailpassword/inspect-button.png | Bin .../img/emailpassword/modified-formfields.png | Bin .../emailpassword/override/find-component.png | Bin .../img/emailpassword/pass-reset-email.png | Bin .../img/emailpassword/password-manager.png | Bin .../img/emailpassword/primary.png | Bin .../emailpassword/react-override-octocat.png | Bin .../reset-password-enter-email.png | Bin .../reset-password-submit-new-password.png | Bin .../img/emailpassword/saas-connect-popup.png | Bin .../img/emailpassword/signin-dark.png | Bin .../signin-with-custom-error-msg.png | Bin .../signin-with-default-values.png | Bin .../signup-centered-blue-button.png | Bin .../img/emailpassword/signup-light.png | Bin .../signup-with-custom-components.png | Bin .../signup-with-custom-error-msg.png | Bin .../signup-with-custom-field-order.png | Bin .../signup-with-default-values.png | Bin .../signup-with-name-and-age-failure.png | Bin .../signup-with-name-and-age.png | Bin .../img/emailpassword/sp-test-signup.png | Bin .../emailpassword/st-ep-refresh-cookies.png | Bin .../img/emailpassword/st-ep-refresh.png | Bin .../img/emailpassword/st-ep-signout.png | Bin .../emailpassword/st-test-signin-cookies.png | Bin .../emailpassword/st-user-unauthorized.png | Bin .../img/emailpassword/success.png | Bin .../img/emailpassword/textInput.png | Bin .../img/emailpassword/textLabel.png | Bin .../img/emailpassword/textPrimary.png | Bin .../img/emailpassword/textTitle.png | Bin .../img/emailpassword/verify-email-screen.png | Bin .../emailverification/resend-with-border.png | Bin {static => public}/img/enter-otp-error.png | Bin {static => public}/img/enter-otp-invalid.png | Bin {static => public}/img/enter-otp-screen.png | Bin public/img/favicon.ico | Bin 0 -> 4432 bytes {static => public}/img/flutter-debug-logs.png | Bin {static => public}/img/form-question.png | Bin .../img/form-submitted-tick.png | Bin {static => public}/img/front-debug-logs.png | Bin {static => public}/img/guides/API-orange.svg | 0 {static => public}/img/guides/API.svg | 0 {static => public}/img/guides/MFA-orange.svg | 0 {static => public}/img/guides/MFA.svg | 0 {static => public}/img/guides/SDK-orange.svg | 0 {static => public}/img/guides/SDK.svg | 0 .../guides/attackprotectionsuite-orange.svg | 0 .../img/guides/attackprotectionsuite.svg | 0 .../img/guides/dashboard-orange.svg | 0 {static => public}/img/guides/dashboard.svg | 0 .../img/guides/emailPass-orange.svg | 0 {static => public}/img/guides/emailPass.svg | 0 .../img/guides/emailPassPlusSocial-orange.svg | 0 .../img/guides/emailPassPlusSocial.svg | 0 {static => public}/img/guides/emailPassSS.png | Bin .../img/guides/emailSocialSS.png | Bin .../img/guides/micro-orange.svg | 0 {static => public}/img/guides/micro.svg | 0 .../img/guides/multitenancy-orange.svg | 0 .../img/guides/multitenancy.svg | 0 .../img/guides/oauth-logo-orange.svg | 0 {static => public}/img/guides/oauth-logo.svg | 0 .../img/guides/passLessSocial-orange.svg | 0 .../img/guides/passLessSocial.svg | 0 .../img/guides/passwordless-orange.svg | 0 .../img/guides/passwordless.svg | 0 .../img/guides/passwordlessSS.png | Bin .../img/guides/passwordlessSocialSS.png | Bin .../img/guides/phoneNumberSS.png | Bin .../img/guides/phonePass-orange.svg | 0 {static => public}/img/guides/phonePass.svg | 0 .../img/guides/session-orange.svg | 0 {static => public}/img/guides/session.svg | 0 .../img/guides/social-orange.svg | 0 {static => public}/img/guides/social.svg | 0 {static => public}/img/guides/socialSS.png | Bin .../img/guides/unified-login-orange.svg | 0 .../img/guides/unified-login.svg | 0 .../img/guides/userRoles-orange.svg | 0 {static => public}/img/guides/userRoles.svg | 0 {static => public}/img/ic-binoculars.svg | 0 {static => public}/img/icon-plus.png | Bin {static => public}/img/icons/android.svg | 0 {static => public}/img/icons/check.svg | 0 {static => public}/img/icons/chevron-down.svg | 0 {static => public}/img/icons/code.svg | 0 {static => public}/img/icons/copy.svg | 0 {static => public}/img/icons/credit-card.svg | 0 .../img/icons/exclamation-triangle.svg | 0 .../img/icons/external-link.svg | 0 {static => public}/img/icons/eye.svg | 0 {static => public}/img/icons/file.svg | 0 {static => public}/img/icons/flutter.svg | 0 {static => public}/img/icons/github.svg | 0 {static => public}/img/icons/go.svg | 0 {static => public}/img/icons/hash.svg | 0 {static => public}/img/icons/info-circled.svg | 0 {static => public}/img/icons/info.svg | 0 {static => public}/img/icons/ios.svg | 0 {static => public}/img/icons/js.svg | 0 {static => public}/img/icons/key.svg | 0 {static => public}/img/icons/node.svg | 0 {static => public}/img/icons/pen.svg | 0 {static => public}/img/icons/python.svg | 0 {static => public}/img/icons/react.svg | 0 {static => public}/img/icons/search.svg | 0 {static => public}/img/icons/terminal.svg | 0 {static => public}/img/icons/thumbs-down.svg | 0 {static => public}/img/icons/thumbs-up.svg | 0 {static => public}/img/icons/typescript.svg | 0 {static => public}/img/icons/x.svg | 0 .../img/integration-lambda/add-a-layer.png | Bin .../add-auth-middleware-node.png | Bin .../integration-lambda/add-env-var-node.png | Bin .../add-layer-detail-node.png | Bin .../integration-lambda/click-enable-cors.png | Bin .../img/integration-lambda/configure-cors.png | Bin .../configure-lambda-integration.png | Bin .../integration-lambda/create-api-gateway.png | Bin .../create-function-node.png | Bin .../create-function-python.png | Bin .../img/integration-lambda/create-layer.png | Bin .../integration-lambda/create-proxy-route.png | Bin .../integration-lambda/link-node-layer.jpg | Bin .../integration-lambda/link-python-layer.png | Bin .../integration-lambda/node-lambda-layer.png | Bin .../python-lambda-layer.png | Bin .../route-creation-complete.png | Bin .../img/integration-lambda/sidebar.png | Bin {static => public}/img/logo.svg | 0 {static => public}/img/logos/android.svg | 0 {static => public}/img/logos/angular.svg | 0 {static => public}/img/logos/anthropic.svg | 0 {static => public}/img/logos/aws-lambda.svg | 0 {static => public}/img/logos/boxyhq.png | Bin {static => public}/img/logos/capacitor-js.svg | 0 .../img/logos/capacitorjs-icon.svg | 0 {static => public}/img/logos/cdi.svg | 0 {static => public}/img/logos/chatgpt.svg | 0 {static => public}/img/logos/discord.svg | 0 {static => public}/img/logos/django.svg | 0 {static => public}/img/logos/electron.svg | 0 {static => public}/img/logos/fastapi.svg | 0 {static => public}/img/logos/fauna-db.svg | 0 {static => public}/img/logos/fdi.svg | 0 {static => public}/img/logos/github.svg | 0 {static => public}/img/logos/go.svg | 0 {static => public}/img/logos/graphql-logo.png | Bin {static => public}/img/logos/graphql.svg | 0 {static => public}/img/logos/hasura-logo.png | Bin {static => public}/img/logos/hasura.svg | 0 {static => public}/img/logos/ios.svg | 0 {static => public}/img/logos/js.svg | 0 {static => public}/img/logos/mcp.svg | 0 {static => public}/img/logos/nestjs.svg | 0 {static => public}/img/logos/netlify.svg | 0 {static => public}/img/logos/next-logo.png | Bin {static => public}/img/logos/nextjs.svg | 0 {static => public}/img/logos/node.svg | 0 {static => public}/img/logos/nodejs-small.svg | 0 {static => public}/img/logos/python.svg | 0 {static => public}/img/logos/react.svg | 0 {static => public}/img/logos/redwood-logo.png | Bin {static => public}/img/logos/saml.svg | 0 .../img/logos/supabase-logo.jpg | Bin {static => public}/img/logos/supabase.svg | 0 .../img/logos/supertokens-dark.svg | 0 .../img/logos/supertokens-light.svg | 0 {static => public}/img/logos/t3-chat.svg | 0 {static => public}/img/logos/t4-app.png | Bin {static => public}/img/logos/vercel.jpeg | Bin {static => public}/img/logos/vercel.svg | 0 {static => public}/img/logos/vue.svg | 0 .../magic-link-clicked-different-device.png | Bin {static => public}/img/magic-link-clicked.png | Bin .../img/magic-link-sent-error.png | Bin {static => public}/img/magic-link-sent.png | Bin .../img/microservice_auth/architecture.png | Bin .../firebase_password_hashing_params.png | Bin .../migration/session-migration-diagram.png | Bin ...aged_service_edit_configuration_button.png | Bin ...ns_managed_service_firebase_signer_key.png | Bin .../img/multi-tenancy-architecture.png | Bin .../img/multi-tenant-multi-app-diagram.svg | 0 .../img/multi-tenant-multi-app.png | Bin .../img/multi-tenant-single-app-diagram.svg | 0 .../img/multi-tenant-single-app.png | Bin .../img/new-password-general-error.png | Bin .../img/oauth/authorization-code-flow.png | Bin .../img/oauth/client-credentials-flow.png | Bin .../img/oauth/machine-to-machine.png | Bin ...frontend-domains-with-a-single-backend.png | Bin ...rontend-domains-with-separate-backends.png | Bin .../img/oauth/reuse-web-ui-for-mobile.png | Bin .../img/other-framework-setup.png | Bin .../img/otp-magic-link-same-time.png | Bin {static => public}/img/passkey.png | Bin .../img/password-reset-general-error.png | Bin .../img/password-reset-success.png | Bin .../img/passwordless-email-phone.png | Bin {static => public}/img/passwordless-email.png | Bin .../img/passwordless-invalid-phone-email.png | Bin .../img/passwordless-magic-link-expired.png | Bin ...asswordless-passwordless-general-error.png | Bin {static => public}/img/passwordless-phone.png | Bin .../img/passwordless-too-many-otp-tries.png | Bin .../img/passwordless/buttonText.png | Bin .../img/passwordless/change-user.png | Bin .../passwordless/diagrams/magic_link_flow.png | Bin .../img/passwordless/diagrams/otp_flow.png | Bin .../diagrams/passwordless-migration-flow.png | Bin {static => public}/img/passwordless/error.png | Bin .../img/passwordless/input-background.png | Bin .../img/passwordless/inspect-button.png | Bin .../img/passwordless/modified-formfields.png | Bin .../passwordless/override/find-component.png | Bin .../img/passwordless/primary.png | Bin .../passwordless/react-override-octocat.png | Bin .../signinup-centered-blue-button.png | Bin .../img/passwordless/signinup-dark.png | Bin .../img/passwordless/signinup-light.png | Bin .../img/passwordless/sms-api-key.png | Bin .../img/passwordless/sp-test-signup-1.png | Bin .../img/passwordless/sp-test-signup-2.png | Bin .../passwordless/st-ep-refresh-cookies.png | Bin .../img/passwordless/st-ep-refresh.png | Bin .../img/passwordless/st-ep-signout.png | Bin .../passwordless/st-test-signin-cookies.png | Bin .../img/passwordless/st-user-unauthorized.png | Bin .../img/passwordless/success.png | Bin .../img/passwordless/textInput.png | Bin .../img/passwordless/textLabel.png | Bin .../img/passwordless/textPrimary.png | Bin .../img/passwordless/textTitle.png | Bin .../img/prebuilt-and-custom-ui-screenshot.png | Bin .../img/progressive-profiling.png | Bin .../img/quickstart-next-steps-0.png | Bin .../img/quickstart-next-steps-1.png | Bin .../img/quickstart-next-steps-copy-creds.png | Bin ...uickstart-next-steps-create-deployment.png | Bin .../img/react-native-debug-logs.png | Bin .../img/recipe-tabs/recipe-email-social.png | Bin .../img/recipe-tabs/recipe-email.png | Bin .../recipe-passwordless-social.png | Bin .../img/recipe-tabs/recipe-passwordless.png | Bin .../img/recipe-tabs/recipe-session.png | Bin .../img/recipe-tabs/recipe-social.png | Bin .../img/recipe_selector_close.png | Bin .../img/recipe_selector_open.png | Bin .../img/reset-password-email-sent.png | Bin .../img/reset-password-email.png | Bin ...et-password-new-password-invalid-token.png | Bin .../img/reset-password-new-password.png | Bin {static => public}/img/rpm.png | Bin {static => public}/img/saas-dev-connect.png | Bin .../img/saas/supertokens-core-deploy.png | Bin .../img/saas/supertokens-core-quicksetup.png | Bin .../img/saas/supertokens-core-success.png | Bin {static => public}/img/saml-oauth.png | Bin .../img/saml/supertokens-boxyhq.png | Bin {static => public}/img/select.svg | 0 {static => public}/img/session_flow.png | Bin .../img/sidebar-category-icons/lightning.png | Bin .../img/sidebar-category-icons/pencil.png | Bin {static => public}/img/signupDropdownIcon.png | Bin .../img/signupDropdownIconDisabled.png | Bin .../img/single-tenant-multi-app-diagram.png | 0 .../img/single-tenant-multi-app-diagram.svg | 0 .../img/single-tenant-multi-app.png | Bin .../img/single-tenant-single-app-diagram.svg | 0 .../img/single-tenant-single-app.png | Bin {static => public}/img/st-session-cookies.png | Bin .../img/st-session-new-session.png | Bin {static => public}/img/st-session-userid.png | Bin .../img/st-thirdparty-change-user.png | Bin .../img/styling/branding_element.png | Bin .../img/tenant-discovery-email-form.png | Bin .../img/thirdparty-general-error.png | Bin .../img/thirdparty-no-email.png | Bin .../thirdparty-sign-in-custom-provider.png | Bin .../img/thirdparty-thirdparty-callback.png | Bin .../img/thirdparty/dark-theme.png | Bin .../img/thirdparty/inspect-button-2.png | Bin .../img/thirdparty/inspect-button.png | Bin .../thirdparty/override/find-component.png | Bin .../img/thirdparty/react-override-octocat.png | Bin .../img/thirdparty/signup-light.png | Bin .../img/thirdparty/textTitle.png | Bin .../img/thirdparty/title-border.png | Bin ...tyemailpassword-field-validation-error.png | Bin .../thirdpartyemailpassword-general-error.png | Bin .../img/thirdpartyemailpassword-no-email.png | Bin ...yemailpassword-sign-in-custom-provider.png | Bin .../img/thirdpartyemailpassword-sign-in.png | Bin .../img/thirdpartyemailpassword-sign-up.png | Bin ...partyemailpassword-thirdparty-callback.png | Bin .../thirdpartyemailpassword-wrong-cred.png | Bin .../auth0-database.png | Bin .../thirdpartyemailpassword/change-user.png | Bin .../custom-field-name-signup-ep.png | Bin .../custom-field-name-signup.png | Bin .../default-directory-settings.png | Bin .../ep-account-migration.png | Bin .../modified-formfields.png | Bin .../override/find-component.png | Bin .../react-override-octocat.png | Bin .../session-migration.png | Bin .../thirdpartyemailpassword/signin-dark.png | Bin .../thirdpartyemailpassword/signin-light.png | Bin .../signin-with-custom-error-msg.png | Bin .../signin-with-default-values.png | Bin .../signup-centered-blue-button.png | Bin .../thirdpartyemailpassword/signup-dark.png | Bin .../signup-invalid-age-light.png | Bin .../thirdpartyemailpassword/signup-light.png | Bin .../signup-with-custom-components.png | Bin .../signup-with-custom-error-msg.png | Bin .../signup-with-custom-field-order.png | Bin .../signup-with-default-values.png | Bin .../signup-with-name-and-age.png | Bin .../supabase/create_policy.png | Bin .../supabase/policy_config_insert.png | Bin .../supabase/policy_config_select.png | Bin .../supabase_app_authenticated_screen.png | Bin .../supabase/supabase_dashboard_create.png | Bin .../supabase/supabase_table_create.png | Bin .../supabase/table_with_user.png | Bin .../tp-account-migration.png | Bin .../thirdpartypasswordless-email-phone.png | Bin .../img/thirdpartypasswordless-email.png | Bin .../thirdpartypasswordless-general-error.png | Bin ...dpartypasswordless-invalid-phone-email.png | Bin ...rdpartypasswordless-magic-link-expired.png | Bin .../img/thirdpartypasswordless-no-email.png | Bin ...asswordless-passwordless-general-error.png | Bin .../img/thirdpartypasswordless-phone.png | Bin ...typasswordless-sign-in-custom-provider.png | Bin ...dpartypasswordless-thirdparty-callback.png | Bin ...rdpartypasswordless-too-many-otp-tries.png | Bin .../thirdpartypasswordless/change-user.png | Bin .../override/find-component.png | Bin .../thirdpartypasswordless/signinup-light.png | Bin {static => public}/img/ui-switcher-check.svg | 0 {static => public}/img/user-banning.png | Bin {static => public}/img/user-profile.png | Bin .../img/userroles/user-roles-intro.png | Bin .../img/webauthn-recover-account.png | Bin {static => public}/img/webauthn-signin.png | Bin {static => public}/img/webauthn-signup.png | Bin {static => public}/img/work-in-progress.png | Bin scripts/ai.ts | 274 - scripts/blume/convert-categories.mjs | 100 + scripts/blume/convert-content.mjs | 483 + scripts/blume/create-route-manifest.mjs | 140 + scripts/blume/fix-legacy-components.mjs | 210 + scripts/blume/fix-stale-links.mjs | 116 + scripts/blume/openapi-redirects.ts | 823 + scripts/blume/prefix-content-assets.mjs | 46 + scripts/blume/remove-openapi-stubs.mjs | 22 + scripts/blume/restore-frontmatter.mjs | 73 + scripts/blume/route-manifest.json | 3605 ++ scripts/generate-api-reference-pages.ts | 181 - scripts/search.ts | 308 - scripts/search/api-reference-index.ts | 281 - scripts/search/index.ts | 38 - scripts/search/sdk-reference-index.ts | 292 - scripts/search/search-index.ts | 19 - sidebars.ts | 64 - src/components/APIRequest/APIRequest.scss | 282 - src/components/APIRequest/APIRequest.tsx | 753 - .../APIRequest/APIRequestClient.tsx | 86 - .../APIRequest/APIRequestCodeSnippet.tsx | 147 - .../APIRequestEditParametersModal.tsx | 248 - src/components/APIRequest/APIRequestPage.tsx | 91 - .../APIRequest/APIRequestParametersCard.tsx | 33 - .../APIRequest/APIRequestResponsePreview.tsx | 111 - .../APIRequest/APIRequestSchemaCard.tsx | 340 - .../APIRequest/ApiRequestApiTypeCallout.tsx | 49 - src/components/APIRequest/index.ts | 1 - src/components/Accordion.scss | 83 - src/components/Accordion.tsx | 117 - src/components/BetaBadge.tsx | 36 - src/components/Callouts/OAuthCallouts.tsx | 91 - .../Callouts/PaidFeatureCallouts.tsx | 89 - src/components/Callouts/TokensCallout.tsx | 85 - src/components/Callouts/index.ts | 3 - src/components/Cards/APIRequestCard.scss | 17 - src/components/Cards/AccountTypeCard.tsx | 56 - src/components/Cards/CodeSampleCard.tsx | 68 - src/components/Cards/GoFrameworksCard.tsx | 26 - src/components/Cards/HTTPRequestCard.scss | 16 - src/components/Cards/HTTPRequestCard.tsx | 305 - .../Cards/JavascriptHttpLibraryCard.tsx | 21 - .../Cards/ManagedOrSelfHostedCard.tsx | 0 src/components/Cards/MobileFrameworksCard.tsx | 21 - src/components/Cards/NodeFrameworksCard.tsx | 46 - .../Cards/NodePackageManagerCard.tsx | 20 - src/components/Cards/NpmOrScriptsCard.tsx | 21 - .../Cards/PasswordlessConfigCard.tsx | 27 - src/components/Cards/PythonFrameworksCard.tsx | 26 - .../Cards/PythonPackageManagerCard.tsx | 20 - src/components/Cards/PythonSyncAsyncCard.tsx | 20 - .../Cards/ReferenceCard/ReferenceCard.tsx | 157 - .../Cards/ReferenceCard/styles.scss | 49 - .../Cards/ThirdPartyBuiltinProvidersCard.tsx | 20 - src/components/Cards/index.ts | 15 - src/components/Cards/styles.scss | 16 - src/components/ColorModeToggle.scss | 89 - src/components/ColorModeToggle.tsx | 23 - src/components/ConditionalContent.tsx | 14 - src/components/CopyPageContentButton.scss | 43 - src/components/CopyPageContentButton.tsx | 85 - src/components/DescriptionText.tsx | 10 - src/components/DocItemContextCondition.tsx | 24 - src/components/DocItemContextValue.tsx | 8 - src/components/Forms/AppInfoForm.scss | 112 - src/components/Forms/AppInfoForm.tsx | 148 - src/components/Forms/ExampleAppForm.scss | 3 - src/components/Forms/ExampleAppForm.tsx | 179 - .../Forms/PasswordlessRecipeForm.tsx | 44 - src/components/Forms/index.ts | 3 - src/components/MenuItemIcon.tsx | 197 - src/components/Modal/SideModal.scss | 69 - src/components/Modal/SideModal.tsx | 29 - src/components/Modal/index.tsx | 1 - src/components/NewBadge.tsx | 46 - src/components/PageOptionsDropdownMenu.tsx | 78 - src/components/PaidFeatureCallout.tsx | 143 - src/components/Question.tsx | 101 - src/components/RadioCard.scss | 11 - src/components/RemoveForLLMs.tsx | 5 - src/components/SDKCompatibilityTable.tsx | 358 - src/components/SDKReference/SDKReference.scss | 17 - src/components/SDKReference/SDKReference.tsx | 151 - src/components/SDKReference/index.ts | 1 - src/components/ScrollOffsetFix.tsx | 12 - src/components/Search.scss | 160 - src/components/Search.tsx | 617 - src/components/Select/AccountTypeSelect.tsx | 20 - src/components/Select/AppTypeSelect.tsx | 18 - src/components/Select/GoFrameworksSelect.tsx | 39 - .../Select/JavascriptHttpLibrarySelect.tsx | 24 - .../Select/MobileFrameworksSelect.tsx | 39 - .../Select/NextjsRouterTypeSelect.tsx | 20 - .../Select/NodeFrameworksSelect.tsx | 43 - .../Select/NodePackageManagerSelect.tsx | 25 - src/components/Select/NpmOrScriptsSelect.tsx | 24 - .../PasswordlessContactMethodSelect.tsx | 37 - .../Select/PasswordlessFlowTypeSelect.tsx | 37 - .../Select/PythonFrameworksSelect.tsx | 38 - .../Select/PythonPackageManagerSelect.tsx | 24 - .../Select/PythonSyncAsyncSelect.tsx | 36 - .../Select/SelfHostedDeploymentTypeSelect.tsx | 22 - src/components/Select/TenantTypeSelect.tsx | 20 - .../ThirdpartyBuiltinProvidersSelect.tsx | 48 - src/components/Select/index.ts | 17 - src/components/Separator.tsx | 7 - src/components/Steps.tsx | 137 - src/components/StripParagraph.tsx | 13 - src/components/Tabs/BackendTabs.tsx | 41 - src/components/Tabs/DatabaseTabs.tsx | 34 - src/components/Tabs/FrontendCustomUITabs.tsx | 25 - .../Tabs/FrontendPrebuiltUITabs.tsx | 56 - src/components/Tabs/FrontendTabs.tsx | 53 - src/components/Tabs/OSTabs.tsx | 35 - .../Tabs/ReactRouterVersionsTabs.tsx | 26 - src/components/Tabs/RowndFrontendTabs.tsx | 29 - src/components/Tabs/SelfHostingTabs.tsx | 34 - src/components/Tabs/index.ts | 9 - src/components/TenantTypeSwitch.tsx | 57 - src/components/Typography.tsx | 75 - src/components/UITypeSwitch.tsx | 108 - src/components/index.ts | 26 - src/context/DocItemContext.tsx | 154 - src/context/TabsContex.tsx | 15 - src/context/index.ts | 2 - src/css/custom.scss | 178 - src/css/fonts.css | 17 - src/css/radix.css | 777 - src/hooks/index.ts | 7 - src/hooks/useDocItemStore.ts | 102 - src/hooks/useDocPageData.ts | 20 - src/hooks/useFilteredTocItems.ts | 64 - src/hooks/useIsVisible.ts | 27 - src/hooks/useLoadOpenApiSchema.ts | 26 - src/hooks/useSelection.ts | 5 - src/hooks/useSelectionStore.ts | 64 - src/hooks/useUIType.ts | 32 - src/lib/amplitude.ts | 75 - src/lib/analytics.ts | 311 - src/lib/api.ts | 324 - src/lib/categoryIcons.tsx | 136 - src/lib/constants.ts | 42 - src/lib/docPageStore.ts | 106 - src/lib/generateCodeSnippetFromAPIRequest.ts | 330 - .../generateExampleFromAPIRequestSchema.ts | 21 - src/lib/getExampleFromSchema.ts | 368 - src/lib/index.ts | 11 - src/lib/normalizeOpenAPIObject.ts | 24 - src/lib/normalizePath.ts | 29 - src/lib/replaceVariablesForScalar.ts | 56 - src/lib/replaceVariablesInApiPath.ts | 9 - src/lib/scrollOffset.ts | 62 - src/lib/search.ts | 302 - src/lib/themeStore.ts | 230 - src/lib/types.ts | 342 - src/plugins/addNofollowToExternalLinks.js | 84 - src/plugins/generateLllmsFullTxt.ts | 415 - src/plugins/generateLllmsTxt.ts | 167 - src/plugins/reactBundle.js | 47 - src/plugins/remarkAddBadgesInHeadings.ts | 53 - src/plugins/remarkAddPaidFeatureCallout.ts | 24 - src/plugins/remarkDocItemContextValues.ts | 27 - src/plugins/remarkDocItemDescription.ts | 78 - ...rkRemoveCodeTypeCheckingCommentsAndRows.ts | 28 - src/plugins/remarkRemoveWebJsScriptImports.ts | 37 - src/plugins/transformOpenSearchLink.js | 55 - src/plugins/utils/getAllMdxFiles.ts | 55 - src/theme/Admonition/Icon/Danger.tsx | 13 - src/theme/Admonition/Icon/Info.tsx | 13 - src/theme/Admonition/Icon/Note.tsx | 13 - src/theme/Admonition/Icon/Tip.tsx | 13 - src/theme/Admonition/Icon/Warning.tsx | 13 - src/theme/Admonition/Layout/index.tsx | 49 - src/theme/Admonition/Layout/styles.module.css | 35 - src/theme/Admonition/Type/Caution.tsx | 30 - src/theme/Admonition/Type/Danger.tsx | 25 - src/theme/Admonition/Type/Info.tsx | 25 - src/theme/Admonition/Type/Note.tsx | 25 - src/theme/Admonition/Type/Tip.tsx | 25 - src/theme/Admonition/Type/Warning.tsx | 28 - src/theme/Admonition/Types.tsx | 31 - src/theme/Admonition/admonition.scss | 25 - src/theme/Admonition/index.tsx | 73 - src/theme/CodeBlock/Container/index.tsx | 21 - .../CodeBlock/Container/styles.module.css | 11 - src/theme/CodeBlock/Content/Element.tsx | 17 - src/theme/CodeBlock/Content/String.tsx | 174 - src/theme/CodeBlock/Content/styles.module.css | 92 - src/theme/CodeBlock/CopyButton/index.tsx | 54 - .../CodeBlock/CopyButton/styles.module.css | 40 - src/theme/CodeBlock/Line/index.tsx | 38 - src/theme/CodeBlock/Line/styles.module.css | 49 - src/theme/CodeBlock/WordWrapButton/index.tsx | 27 - .../WordWrapButton/styles.module.css | 8 - src/theme/CodeBlock/index.tsx | 49 - src/theme/CodeInline/index.scss | 0 src/theme/CodeInline/index.tsx | 30 - src/theme/DocItem/Content/index.scss | 44 - src/theme/DocItem/Content/index.tsx | 45 - src/theme/DocItem/Footer/index.scss | 12 - src/theme/DocItem/Footer/index.tsx | 306 - src/theme/DocItem/Layout/index.tsx | 135 - src/theme/DocItem/Layout/styles.module.css | 10 - src/theme/DocItem/Metadata/index.tsx | 15 - src/theme/DocItem/Paginator/index.tsx | 12 - src/theme/DocItem/TOC/Desktop/index.tsx | 17 - src/theme/DocItem/TOC/Mobile/index.tsx | 20 - .../DocItem/TOC/Mobile/styles.module.css | 12 - src/theme/DocItem/index.tsx | 21 - src/theme/DocPaginator/index.tsx | 40 - src/theme/DocRoot/Layout/Main/index.tsx | 33 - .../DocRoot/Layout/Main/styles.module.css | 42 - .../Layout/Sidebar/ExpandButton/index.tsx | 30 - .../Sidebar/ExpandButton/styles.module.css | 27 - src/theme/DocRoot/Layout/Sidebar/index.tsx | 65 - .../DocRoot/Layout/Sidebar/styles.module.css | 32 - src/theme/DocRoot/Layout/index.tsx | 28 - src/theme/DocRoot/Layout/styles.module.css | 9 - src/theme/DocRoot/index.tsx | 24 - src/theme/DocSidebar/AdditionalLinks.scss | 101 - src/theme/DocSidebar/AdditionalLinks.tsx | 64 - .../Desktop/CollapseButton/index.tsx | 29 - .../Desktop/CollapseButton/styles.module.css | 45 - .../DocSidebar/Desktop/Content/index.tsx | 53 - .../Desktop/Content/styles.module.css | 35 - src/theme/DocSidebar/Desktop/index.tsx | 34 - .../DocSidebar/Desktop/styles.module.css | 37 - src/theme/DocSidebar/Mobile/index.scss | 26 - src/theme/DocSidebar/Mobile/index.tsx | 52 - src/theme/DocSidebar/index.tsx | 22 - src/theme/DocSidebarItem/Category/index.tsx | 274 - src/theme/DocSidebarItem/Category/styles.scss | 84 - src/theme/DocSidebarItem/Html/index.tsx | 23 - .../DocSidebarItem/Html/styles.module.css | 5 - src/theme/DocSidebarItem/Link/index.tsx | 84 - .../DocSidebarItem/Link/styles.module.scss | 38 - src/theme/DocSidebarItem/index.tsx | 17 - src/theme/EditMetaRow/index.tsx | 20 - src/theme/EditMetaRow/styles.module.css | 11 - src/theme/EditThisPage/index.tsx | 17 - src/theme/Heading/index.tsx | 50 - src/theme/Heading/styles.module.css | 28 - src/theme/Layout/Provider/index.tsx | 24 - src/theme/Layout/index.tsx | 73 - src/theme/Layout/styles.module.css | 21 - src/theme/Logo/index.tsx | 41 - src/theme/MDXComponents.tsx | 221 - src/theme/MDXComponents/Code.tsx | 22 - src/theme/MDXComponents/Heading.tsx | 7 - src/theme/MDXComponents/Img/index.tsx | 77 - src/theme/MDXComponents/Img/styles.module.css | 3 - src/theme/Navbar/ColorModeToggle/index.tsx | 26 - .../Navbar/ColorModeToggle/styles.module.css | 3 - src/theme/Navbar/Content/index.tsx | 137 - src/theme/Navbar/Content/styles.module.css | 49 - src/theme/Navbar/Layout/index.tsx | 67 - src/theme/Navbar/Layout/styles.module.scss | 41 - src/theme/Navbar/Logo/index.scss | 0 src/theme/Navbar/Logo/index.tsx | 18 - .../Navbar/MobileSidebar/Header/index.tsx | 34 - .../Navbar/MobileSidebar/Layout/index.scss | 24 - .../Navbar/MobileSidebar/Layout/index.tsx | 87 - .../MobileSidebar/PrimaryMenu/index.tsx | 26 - .../MobileSidebar/SecondaryMenu/index.tsx | 31 - .../Navbar/MobileSidebar/Toggle/index.tsx | 23 - src/theme/Navbar/MobileSidebar/index.tsx | 23 - src/theme/Navbar/Search/index.tsx | 9 - src/theme/Navbar/Search/styles.module.css | 20 - src/theme/Navbar/index.tsx | 11 - src/theme/NavbarItem/ComponentTypes.tsx | 25 - src/theme/NavbarItem/DefaultNavbarItem.tsx | 42 - src/theme/NavbarItem/DocNavbarItem.tsx | 30 - src/theme/NavbarItem/DocSidebarNavbarItem.tsx | 21 - .../DocsVersionDropdownNavbarItem.tsx | 95 - .../NavbarItem/DocsVersionNavbarItem.tsx | 19 - .../NavbarItem/DropdownNavbarItem/index.tsx | 148 - .../DropdownNavbarItem/styles.module.css | 3 - src/theme/NavbarItem/HtmlNavbarItem.tsx | 25 - .../LocaleDropdownNavbarItem/index.tsx | 76 - .../styles.module.css | 4 - src/theme/NavbarItem/NavbarNavLink.tsx | 77 - src/theme/NavbarItem/SearchNavbarItem.tsx | 16 - src/theme/NavbarItem/index.tsx | 21 - src/theme/PaginatorNavLink/index.tsx | 25 - src/theme/Root.tsx | 109 - src/theme/SearchBar/index.tsx | 242 - src/theme/SearchBar/styles.css | 15 - src/theme/TOC/index.tsx | 39 - src/theme/TOC/styles.module.css | 16 - .../TOCCollapsible/CollapseButton/index.tsx | 28 - .../CollapseButton/styles.module.css | 23 - src/theme/TOCCollapsible/index.tsx | 24 - src/theme/TOCCollapsible/styles.module.css | 24 - src/theme/TOCItems/Tree.tsx | 36 - src/theme/TOCItems/index.scss | 11 - src/theme/TOCItems/index.tsx | 47 - src/theme/TabItem/index.tsx | 22 - src/theme/TabItem/styles.scss | 24 - src/theme/Tabs/index.tsx | 56 - src/theme/Tabs/styles.module.css | 27 - static/img/docusaurus-social-card.jpg | Bin 55746 -> 0 bytes static/img/docusaurus.png | Bin 5142 -> 0 bytes static/img/undraw_docusaurus_mountain.svg | 171 - static/img/undraw_docusaurus_react.svg | 170 - static/img/undraw_docusaurus_tree.svg | 40 - task.md | 265 + theme.css | 35 + tsconfig.json | 18 +- vercel.json | 17 + vitest.config.ts | 10 - 1571 files changed, 59605 insertions(+), 73756 deletions(-) create mode 100644 blume.config.ts create mode 100644 components.ts create mode 100644 components/ConditionalContent.astro create mode 100644 components/ContextCondition.astro create mode 100644 components/NextjsRouterTypeSelect.astro create mode 100644 components/PasswordlessRecipeForm.astro create mode 100644 components/TenantTypeSwitch.astro create mode 100644 components/UITypeSwitch.astro create mode 100644 components/VariantContent.astro create mode 100644 components/VariantSwitch.astro delete mode 100644 docs/_blocks/oauth-tokens-callout.mdx delete mode 100644 docs/_blocks/react-router-callout.mdx delete mode 100644 docs/additional-verification/_category_.json delete mode 100644 docs/additional-verification/attack-protection-suite/_blocks/anomaly-detection-request.mdx delete mode 100644 docs/additional-verification/attack-protection-suite/_category_.json create mode 100644 docs/additional-verification/attack-protection-suite/meta.ts delete mode 100644 docs/additional-verification/email-verification/_category_.json create mode 100644 docs/additional-verification/email-verification/meta.ts create mode 100644 docs/additional-verification/meta.ts delete mode 100644 docs/additional-verification/mfa/_blocks/paid-feature-callout.mdx delete mode 100644 docs/additional-verification/mfa/_category_.json delete mode 100644 docs/additional-verification/mfa/email-sms-otp/_category_.json create mode 100644 docs/additional-verification/mfa/email-sms-otp/meta.ts delete mode 100644 docs/additional-verification/mfa/legacy-mfa/_category_.json delete mode 100644 docs/additional-verification/mfa/legacy-mfa/backend-setup/_category_.json create mode 100644 docs/additional-verification/mfa/legacy-mfa/backend-setup/meta.ts create mode 100644 docs/additional-verification/mfa/legacy-mfa/meta.ts delete mode 100644 docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/_category_.json create mode 100644 docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/meta.ts create mode 100644 docs/additional-verification/mfa/meta.ts delete mode 100644 docs/additional-verification/mfa/migration/_category_.json create mode 100644 docs/additional-verification/mfa/migration/meta.ts delete mode 100644 docs/additional-verification/mfa/totp/_category_.json create mode 100644 docs/additional-verification/mfa/totp/meta.ts rename docs/additional-verification/mfa/{webauthn-secondary-factor-setup.mdx => webauthn-setup.mdx} (73%) delete mode 100644 docs/additional-verification/session-verification/_blocks/session-object.mdx delete mode 100644 docs/additional-verification/session-verification/_category_.json create mode 100644 docs/additional-verification/session-verification/meta.ts delete mode 100644 docs/additional-verification/user-roles/_blocks/assign-role-to-session.mdx delete mode 100644 docs/additional-verification/user-roles/_blocks/assign-role-to-user.mdx delete mode 100644 docs/additional-verification/user-roles/_blocks/create-role.mdx delete mode 100644 docs/additional-verification/user-roles/_category_.json create mode 100644 docs/additional-verification/user-roles/meta.ts delete mode 100644 docs/authentication/_category_.json delete mode 100644 docs/authentication/email-password/_category_.json create mode 100644 docs/authentication/email-password/meta.ts delete mode 100644 docs/authentication/enterprise/_blocks/create-tenant.mdx delete mode 100644 docs/authentication/enterprise/_blocks/get-tenant.mdx delete mode 100644 docs/authentication/enterprise/_blocks/paid-feature-banner.mdx delete mode 100644 docs/authentication/enterprise/_blocks/update-tenant-config.mdx delete mode 100644 docs/authentication/enterprise/_category_.json create mode 100644 docs/authentication/enterprise/meta.ts delete mode 100644 docs/authentication/m2m/_category_.json create mode 100644 docs/authentication/m2m/meta.ts create mode 100644 docs/authentication/meta.ts delete mode 100644 docs/authentication/passkeys/_category_.json create mode 100644 docs/authentication/passkeys/meta.ts delete mode 100644 docs/authentication/passwordless/_blocks/backend-sdk-init.mdx delete mode 100644 docs/authentication/passwordless/_blocks/frontend-custom-ui-magic-link-ui.mdx delete mode 100644 docs/authentication/passwordless/_blocks/frontend-custom-ui-otp-ui.mdx delete mode 100644 docs/authentication/passwordless/_category_.json create mode 100644 docs/authentication/passwordless/meta.ts delete mode 100644 docs/authentication/social/_blocks/backend-providers-init.mdx delete mode 100644 docs/authentication/social/_blocks/backend-sdk-init.mdx delete mode 100644 docs/authentication/social/_blocks/frontend-custom-ui-mobile-access-token-flow.mdx delete mode 100644 docs/authentication/social/_blocks/frontend-custom-ui-mobile-authorization-code-flow.mdx delete mode 100644 docs/authentication/social/_blocks/frontend-custom-ui-web-authorization-code-flow.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-active-directory.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-apple.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-bitbucket.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-discord.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-facebook.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-github.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-gitlab.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-google-workspaces.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-google.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-linkedin.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-okta.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-saml.mdx delete mode 100644 docs/authentication/social/_blocks/multi-tenant-provider-config-twitter.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-active-directory.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-apple.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-bitbucket.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-discord.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-facebook.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-github.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-gitlab.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-google-workspaces.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-google.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-linkedin.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-okta.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-saml.mdx delete mode 100644 docs/authentication/social/_blocks/single-tenant-provider-config-twitter.mdx delete mode 100644 docs/authentication/social/_category_.json create mode 100644 docs/authentication/social/built-in-providers-config.mdx delete mode 100644 docs/authentication/social/built-in-providers.mdx create mode 100644 docs/authentication/social/meta.ts delete mode 100644 docs/authentication/unified-login/_blocks/create-oauth2-client-request-details.mdx delete mode 100644 docs/authentication/unified-login/_blocks/create-oauth2-client-request-m2m.mdx delete mode 100644 docs/authentication/unified-login/_blocks/create-oauth2-client-request-no-auth.mdx delete mode 100644 docs/authentication/unified-login/_blocks/create-oauth2-client-request.mdx delete mode 100644 docs/authentication/unified-login/_blocks/custom-ui-guide.mdx delete mode 100644 docs/authentication/unified-login/_blocks/paid-feature-callout.mdx delete mode 100644 docs/authentication/unified-login/_category_.json create mode 100644 docs/authentication/unified-login/meta.ts delete mode 100644 docs/authentication/unified-login/quickstart-guides/_category_.json create mode 100644 docs/authentication/unified-login/quickstart-guides/meta.ts delete mode 100644 docs/deployment/_category_.json create mode 100644 docs/deployment/meta.ts delete mode 100644 docs/migration/_blocks/add-users-for-bulk-import-request.mdx delete mode 100644 docs/migration/_blocks/bulk-import-user-request.mdx delete mode 100644 docs/migration/_blocks/count-staged-users-request.mdx delete mode 100644 docs/migration/_blocks/get-staged-users-request.mdx delete mode 100644 docs/migration/_category_.json delete mode 100644 docs/migration/legacy/_category_.json delete mode 100644 docs/migration/legacy/account-creation/_category_.json create mode 100644 docs/migration/legacy/account-creation/meta.ts create mode 100644 docs/migration/legacy/meta.ts create mode 100644 docs/migration/meta.ts delete mode 100644 docs/migration/rownd/_category_.json create mode 100644 docs/migration/rownd/meta.ts delete mode 100644 docs/platform-configuration/_category_.json create mode 100644 docs/platform-configuration/meta.ts delete mode 100644 docs/platform-configuration/supertokens-core/_category_.json create mode 100644 docs/platform-configuration/supertokens-core/meta.ts delete mode 100644 docs/post-authentication/_category_.json delete mode 100644 docs/post-authentication/account-linking/_blocks/paid-feature-callout.mdx delete mode 100644 docs/post-authentication/account-linking/_category_.json create mode 100644 docs/post-authentication/account-linking/meta.ts delete mode 100644 docs/post-authentication/dashboard/_category_.json create mode 100644 docs/post-authentication/dashboard/meta.ts create mode 100644 docs/post-authentication/meta.ts delete mode 100644 docs/post-authentication/session-management/_category_.json delete mode 100644 docs/post-authentication/session-management/advanced-workflows/_category_.json create mode 100644 docs/post-authentication/session-management/advanced-workflows/meta.ts create mode 100644 docs/post-authentication/session-management/meta.ts delete mode 100644 docs/post-authentication/user-management/_category_.json create mode 100644 docs/post-authentication/user-management/meta.ts delete mode 100644 docs/quickstart/_blocks/angular-app-component.mdx delete mode 100644 docs/quickstart/_blocks/angular-auth-component.mdx delete mode 100644 docs/quickstart/_blocks/angular-routing.mdx delete mode 100644 docs/quickstart/_blocks/curl-sign-in.mdx delete mode 100644 docs/quickstart/_blocks/flutter-custom-client-session.mdx delete mode 100644 docs/quickstart/_blocks/flutter-dio-request-example.mdx delete mode 100644 docs/quickstart/_blocks/flutter-dio-session.mdx delete mode 100644 docs/quickstart/_blocks/flutter-http-session.mdx delete mode 100644 docs/quickstart/_blocks/go-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/kotlin-http-urlconnection-session.mdx delete mode 100644 docs/quickstart/_blocks/kotlin-okhttp-session.mdx delete mode 100644 docs/quickstart/_blocks/kotlin-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/node-express-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/node-fastify-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/node-hapi-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/node-koa-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/node-loopback-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/python-django-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/python-fastapi-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/python-flask-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/react-no-router.mdx delete mode 100644 docs/quickstart/_blocks/react-router-v5.mdx delete mode 100644 docs/quickstart/_blocks/react-router-v6.mdx delete mode 100644 docs/quickstart/_blocks/react-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/swift-almorife.mdx delete mode 100644 docs/quickstart/_blocks/swift-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/swift-url-session-instance.mdx delete mode 100644 docs/quickstart/_blocks/swift-urlsession-shared.mdx delete mode 100644 docs/quickstart/_blocks/vanilla-js-npm-check-email.mdx delete mode 100644 docs/quickstart/_blocks/vanilla-js-npm-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/vanilla-js-npm-sign-in.mdx delete mode 100644 docs/quickstart/_blocks/vanilla-js-npm-sign-up.mdx delete mode 100644 docs/quickstart/_blocks/vanilla-js-script-check-email.mdx delete mode 100644 docs/quickstart/_blocks/vanilla-js-script-sdk-init.mdx delete mode 100644 docs/quickstart/_blocks/vanilla-js-script-sign-in.mdx delete mode 100644 docs/quickstart/_blocks/vanilla-js-script-sign-up.mdx delete mode 100644 docs/quickstart/_blocks/vue-auth-view.mdx delete mode 100644 docs/quickstart/_blocks/vue-main-file.mdx delete mode 100644 docs/quickstart/_blocks/vue-routing.mdx delete mode 100644 docs/quickstart/_category_.json delete mode 100644 docs/quickstart/integrations/_category_.json delete mode 100644 docs/quickstart/integrations/aws-lambda/_category_.json create mode 100644 docs/quickstart/integrations/aws-lambda/meta.ts create mode 100644 docs/quickstart/integrations/meta.ts delete mode 100644 docs/quickstart/integrations/nextjs/_category_.json delete mode 100644 docs/quickstart/integrations/nextjs/app-directory/_category_.json create mode 100644 docs/quickstart/integrations/nextjs/app-directory/meta.ts delete mode 100644 docs/quickstart/integrations/nextjs/app-directory/protecting-backend/_category_.json create mode 100644 docs/quickstart/integrations/nextjs/app-directory/protecting-backend/meta.ts create mode 100644 docs/quickstart/integrations/nextjs/meta.ts delete mode 100644 docs/quickstart/integrations/nextjs/pages-directory/_category_.json create mode 100644 docs/quickstart/integrations/nextjs/pages-directory/meta.ts delete mode 100644 docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/_category_.json create mode 100644 docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/meta.ts create mode 100644 docs/quickstart/meta.ts delete mode 100644 docs/references/_category_.json delete mode 100644 docs/references/backend-sdks/_category_.json create mode 100644 docs/references/backend-sdks/meta.ts delete mode 100644 docs/references/backend-sdks/supertokens-nodejs/_category_.json create mode 100644 docs/references/backend-sdks/supertokens-nodejs/meta.ts delete mode 100644 docs/references/cdi/_category_.json delete mode 100644 docs/references/cdi/account-linking/_category_.json delete mode 100644 docs/references/cdi/account-linking/get-accountlinking-user-link-check.mdx delete mode 100644 docs/references/cdi/account-linking/get-accountlinking-user-primary-check.mdx create mode 100644 docs/references/cdi/account-linking/meta.ts delete mode 100644 docs/references/cdi/account-linking/post-accountlinking-user-link.mdx delete mode 100644 docs/references/cdi/account-linking/post-accountlinking-user-primary.mdx delete mode 100644 docs/references/cdi/account-linking/post-accountlinking-user-unlink.mdx delete mode 100644 docs/references/cdi/core/_category_.json delete mode 100644 docs/references/cdi/core/delete-ee-license.mdx delete mode 100644 docs/references/cdi/core/delete-hello.mdx delete mode 100644 docs/references/cdi/core/get-apiversion.mdx delete mode 100644 docs/references/cdi/core/get-config.mdx delete mode 100644 docs/references/cdi/core/get-ee-featureflag.mdx delete mode 100644 docs/references/cdi/core/get-ee-license.mdx delete mode 100644 docs/references/cdi/core/get-hello.mdx delete mode 100644 docs/references/cdi/core/get-requests-stats.mdx delete mode 100644 docs/references/cdi/core/get-root.mdx delete mode 100644 docs/references/cdi/core/get-telemetry.mdx delete mode 100644 docs/references/cdi/core/get-user-id.mdx delete mode 100644 docs/references/cdi/core/get-user-search-tags.mdx delete mode 100644 docs/references/cdi/core/get-userid-map.mdx delete mode 100644 docs/references/cdi/core/get-users-by-accountinfo.mdx delete mode 100644 docs/references/cdi/core/get-users-count-active.mdx delete mode 100644 docs/references/cdi/core/get-users-count.mdx delete mode 100644 docs/references/cdi/core/get-users.mdx create mode 100644 docs/references/cdi/core/meta.ts delete mode 100644 docs/references/cdi/core/post-hello.mdx delete mode 100644 docs/references/cdi/core/post-user-remove.mdx delete mode 100644 docs/references/cdi/core/post-userid-map-remove.mdx delete mode 100644 docs/references/cdi/core/post-userid-map.mdx delete mode 100644 docs/references/cdi/core/put-ee-license.mdx delete mode 100644 docs/references/cdi/core/put-hello.mdx delete mode 100644 docs/references/cdi/core/put-userid-external-user-id-info.mdx delete mode 100644 docs/references/cdi/dashboard/_category_.json delete mode 100644 docs/references/cdi/dashboard/delete-dashboard-session.mdx delete mode 100644 docs/references/cdi/dashboard/delete-dashboard-user.mdx delete mode 100644 docs/references/cdi/dashboard/get-dashboard-tenant-core-config.mdx delete mode 100644 docs/references/cdi/dashboard/get-dashboard-user-sessions.mdx delete mode 100644 docs/references/cdi/dashboard/get-dashboard-users.mdx create mode 100644 docs/references/cdi/dashboard/meta.ts delete mode 100644 docs/references/cdi/dashboard/post-dashboard-session-verify.mdx delete mode 100644 docs/references/cdi/dashboard/post-dashboard-signin.mdx delete mode 100644 docs/references/cdi/dashboard/post-dashboard-user.mdx delete mode 100644 docs/references/cdi/dashboard/put-dashboard-user.mdx delete mode 100644 docs/references/cdi/email-password/_category_.json delete mode 100644 docs/references/cdi/email-password/get-user.mdx create mode 100644 docs/references/cdi/email-password/meta.ts delete mode 100644 docs/references/cdi/email-password/post-signin.mdx delete mode 100644 docs/references/cdi/email-password/post-signup.mdx delete mode 100644 docs/references/cdi/email-password/post-user-password-reset-token-consume.mdx delete mode 100644 docs/references/cdi/email-password/post-user-password-reset-token.mdx delete mode 100644 docs/references/cdi/email-password/post-user-password-reset.mdx delete mode 100644 docs/references/cdi/email-password/post-user-passwordhash-import.mdx delete mode 100644 docs/references/cdi/email-password/put-user.mdx delete mode 100644 docs/references/cdi/email-verification/_category_.json delete mode 100644 docs/references/cdi/email-verification/get-user-email-verify.mdx create mode 100644 docs/references/cdi/email-verification/meta.ts delete mode 100644 docs/references/cdi/email-verification/post-user-email-verify-remove.mdx delete mode 100644 docs/references/cdi/email-verification/post-user-email-verify-token-remove.mdx delete mode 100644 docs/references/cdi/email-verification/post-user-email-verify-token.mdx delete mode 100644 docs/references/cdi/email-verification/post-user-email-verify.mdx delete mode 100644 docs/references/cdi/import/_category_.json delete mode 100644 docs/references/cdi/import/delete-bulk-import-users.mdx delete mode 100644 docs/references/cdi/import/get-bulk-import-users-count.mdx delete mode 100644 docs/references/cdi/import/get-bulk-import-users.mdx create mode 100644 docs/references/cdi/import/meta.ts delete mode 100644 docs/references/cdi/import/post-bulk-import-import.mdx delete mode 100644 docs/references/cdi/import/post-bulk-import-users.mdx create mode 100644 docs/references/cdi/meta.ts delete mode 100644 docs/references/cdi/mfa/_category_.json delete mode 100644 docs/references/cdi/mfa/get-totp-device-list.mdx create mode 100644 docs/references/cdi/mfa/meta.ts delete mode 100644 docs/references/cdi/mfa/post-totp-device-import.mdx delete mode 100644 docs/references/cdi/mfa/post-totp-device-remove.mdx delete mode 100644 docs/references/cdi/mfa/post-totp-device-verify.mdx delete mode 100644 docs/references/cdi/mfa/post-totp-device.mdx delete mode 100644 docs/references/cdi/mfa/post-totp-verify.mdx delete mode 100644 docs/references/cdi/mfa/put-totp-device.mdx delete mode 100644 docs/references/cdi/multitenancy/_category_.json delete mode 100644 docs/references/cdi/multitenancy/get-multitenancy-app-list-v2.mdx delete mode 100644 docs/references/cdi/multitenancy/get-multitenancy-app-list.mdx delete mode 100644 docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list-v2.mdx delete mode 100644 docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list.mdx delete mode 100644 docs/references/cdi/multitenancy/get-multitenancy-tenant-list-v2.mdx delete mode 100644 docs/references/cdi/multitenancy/get-multitenancy-tenant-list.mdx delete mode 100644 docs/references/cdi/multitenancy/get-multitenancy-tenant-v2.mdx delete mode 100644 docs/references/cdi/multitenancy/get-multitenancy-tenant.mdx create mode 100644 docs/references/cdi/multitenancy/meta.ts delete mode 100644 docs/references/cdi/multitenancy/post-multitenancy-app-remove.mdx delete mode 100644 docs/references/cdi/multitenancy/post-multitenancy-config-thirdparty-remove.mdx delete mode 100644 docs/references/cdi/multitenancy/post-multitenancy-connectionuridomain-remove.mdx delete mode 100644 docs/references/cdi/multitenancy/post-multitenancy-tenant-remove.mdx delete mode 100644 docs/references/cdi/multitenancy/post-multitenancy-tenant-user-remove.mdx delete mode 100644 docs/references/cdi/multitenancy/post-multitenancy-tenant-user.mdx delete mode 100644 docs/references/cdi/multitenancy/put-multitenancy-app-v2.mdx delete mode 100644 docs/references/cdi/multitenancy/put-multitenancy-app.mdx delete mode 100644 docs/references/cdi/multitenancy/put-multitenancy-config-thirdparty.mdx delete mode 100644 docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain-v2.mdx delete mode 100644 docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain.mdx delete mode 100644 docs/references/cdi/multitenancy/put-multitenancy-tenant-v2.mdx delete mode 100644 docs/references/cdi/multitenancy/put-multitenancy-tenant.mdx delete mode 100644 docs/references/cdi/oauth/_category_.json delete mode 100644 docs/references/cdi/oauth/get-jwks.mdx delete mode 100644 docs/references/cdi/oauth/get-oauth2-auth.mdx delete mode 100644 docs/references/cdi/oauth/get-oauth2-client.mdx delete mode 100644 docs/references/cdi/oauth/get-oauth2-clients.mdx delete mode 100644 docs/references/cdi/oauth/get-oauth2-consent-request.mdx delete mode 100644 docs/references/cdi/oauth/get-oauth2-login-request.mdx delete mode 100644 docs/references/cdi/oauth/get-oauth2-sessions-logout.mdx delete mode 100644 docs/references/cdi/oauth/get-oauth2-token.mdx delete mode 100644 docs/references/cdi/oauth/get-well-known-jwks.mdx create mode 100644 docs/references/cdi/oauth/meta.ts delete mode 100644 docs/references/cdi/oauth/post-oauth2-client-remove.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-client.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-consent-request-accept.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-consent-request-reject.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-login-request-accept.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-login-request-reject.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-logout-request-accept.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-logout-request-reject.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-session-revoke.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-token-introspect.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-token-revoke.mdx delete mode 100644 docs/references/cdi/oauth/post-oauth2-tokens-revoke.mdx delete mode 100644 docs/references/cdi/oauth/put-oauth2-client.mdx delete mode 100644 docs/references/cdi/passwordless/_category_.json delete mode 100644 docs/references/cdi/passwordless/get-signinup-codes.mdx delete mode 100644 docs/references/cdi/passwordless/get-user.mdx create mode 100644 docs/references/cdi/passwordless/meta.ts delete mode 100644 docs/references/cdi/passwordless/post-signinup-code-check.mdx delete mode 100644 docs/references/cdi/passwordless/post-signinup-code-consume.mdx delete mode 100644 docs/references/cdi/passwordless/post-signinup-code-remove.mdx delete mode 100644 docs/references/cdi/passwordless/post-signinup-code.mdx delete mode 100644 docs/references/cdi/passwordless/post-signinup-codes-remove.mdx delete mode 100644 docs/references/cdi/passwordless/put-user.mdx delete mode 100644 docs/references/cdi/session/_category_.json delete mode 100644 docs/references/cdi/session/get-jwt-data.mdx delete mode 100644 docs/references/cdi/session/get-session-data.mdx delete mode 100644 docs/references/cdi/session/get-session-user.mdx delete mode 100644 docs/references/cdi/session/get-session.mdx create mode 100644 docs/references/cdi/session/meta.ts delete mode 100644 docs/references/cdi/session/post-jwt.mdx delete mode 100644 docs/references/cdi/session/post-session-refresh.mdx delete mode 100644 docs/references/cdi/session/post-session-regenerate.mdx delete mode 100644 docs/references/cdi/session/post-session-remove.mdx delete mode 100644 docs/references/cdi/session/post-session-verify.mdx delete mode 100644 docs/references/cdi/session/post-session.mdx delete mode 100644 docs/references/cdi/session/put-jwt-data.mdx delete mode 100644 docs/references/cdi/session/put-session-data.mdx delete mode 100644 docs/references/cdi/thirdparty/_category_.json delete mode 100644 docs/references/cdi/thirdparty/get-user.mdx delete mode 100644 docs/references/cdi/thirdparty/get-users-by-email.mdx create mode 100644 docs/references/cdi/thirdparty/meta.ts delete mode 100644 docs/references/cdi/thirdparty/post-signinup.mdx delete mode 100644 docs/references/cdi/user-metadata/_category_.json delete mode 100644 docs/references/cdi/user-metadata/get-user-metadata.mdx create mode 100644 docs/references/cdi/user-metadata/meta.ts delete mode 100644 docs/references/cdi/user-metadata/post-user-metadata-remove.mdx delete mode 100644 docs/references/cdi/user-metadata/put-user-metadata.mdx delete mode 100644 docs/references/cdi/user-roles/_category_.json delete mode 100644 docs/references/cdi/user-roles/get-permission-roles.mdx delete mode 100644 docs/references/cdi/user-roles/get-role-permissions.mdx delete mode 100644 docs/references/cdi/user-roles/get-role-users.mdx delete mode 100644 docs/references/cdi/user-roles/get-roles.mdx delete mode 100644 docs/references/cdi/user-roles/get-user-roles.mdx create mode 100644 docs/references/cdi/user-roles/meta.ts delete mode 100644 docs/references/cdi/user-roles/post-role-permissions-remove.mdx delete mode 100644 docs/references/cdi/user-roles/post-role-remove.mdx delete mode 100644 docs/references/cdi/user-roles/post-user-role-remove.mdx delete mode 100644 docs/references/cdi/user-roles/put-role.mdx delete mode 100644 docs/references/cdi/user-roles/put-user-role.mdx delete mode 100644 docs/references/cdi/webauthn/_category_.json delete mode 100644 docs/references/cdi/webauthn/delete-webauthn-credential.mdx delete mode 100644 docs/references/cdi/webauthn/delete-webauthn-options.mdx delete mode 100644 docs/references/cdi/webauthn/get-webauthn-credential.mdx delete mode 100644 docs/references/cdi/webauthn/get-webauthn-credentials.mdx delete mode 100644 docs/references/cdi/webauthn/get-webauthn-options.mdx create mode 100644 docs/references/cdi/webauthn/meta.ts delete mode 100644 docs/references/cdi/webauthn/post-webauthn-recover.mdx delete mode 100644 docs/references/cdi/webauthn/post-webauthn-register.mdx delete mode 100644 docs/references/cdi/webauthn/post-webauthn-registration-options.mdx delete mode 100644 docs/references/cdi/webauthn/post-webauthn-signin-options.mdx delete mode 100644 docs/references/cdi/webauthn/post-webauthn-signin.mdx delete mode 100644 docs/references/cdi/webauthn/post-webauthn-signup.mdx delete mode 100644 docs/references/cdi/webauthn/post-webauthn-token-consume.mdx delete mode 100644 docs/references/cdi/webauthn/post-webauthn-token-recovery.mdx delete mode 100644 docs/references/cdi/webauthn/put-webauthn-email.mdx delete mode 100644 docs/references/fdi/_category_.json delete mode 100644 docs/references/fdi/email-password/_category_.json delete mode 100644 docs/references/fdi/email-password/get-emailpassword-email-exists.mdx delete mode 100644 docs/references/fdi/email-password/get-signup-email-exists.mdx create mode 100644 docs/references/fdi/email-password/meta.ts delete mode 100644 docs/references/fdi/email-password/post-signin.mdx delete mode 100644 docs/references/fdi/email-password/post-signup.mdx delete mode 100644 docs/references/fdi/email-password/post-user-password-reset-token.mdx delete mode 100644 docs/references/fdi/email-password/post-user-password-reset.mdx delete mode 100644 docs/references/fdi/email-verification/_category_.json delete mode 100644 docs/references/fdi/email-verification/get-user-email-verify.mdx create mode 100644 docs/references/fdi/email-verification/meta.ts delete mode 100644 docs/references/fdi/email-verification/post-user-email-verify-token.mdx delete mode 100644 docs/references/fdi/email-verification/post-user-email-verify.mdx delete mode 100644 docs/references/fdi/get-example.mdx delete mode 100644 docs/references/fdi/get-jwt-jwks-json.mdx delete mode 100644 docs/references/fdi/get-loginmethods.mdx delete mode 100644 docs/references/fdi/get-well-known-openid-configuration.mdx create mode 100644 docs/references/fdi/meta.ts delete mode 100644 docs/references/fdi/mfa/_category_.json delete mode 100644 docs/references/fdi/mfa/get-totp-device-list.mdx create mode 100644 docs/references/fdi/mfa/meta.ts delete mode 100644 docs/references/fdi/mfa/post-totp-device-remove.mdx delete mode 100644 docs/references/fdi/mfa/post-totp-device-verify.mdx delete mode 100644 docs/references/fdi/mfa/post-totp-device.mdx delete mode 100644 docs/references/fdi/mfa/post-totp-verify.mdx delete mode 100644 docs/references/fdi/mfa/put-mfa-info.mdx delete mode 100644 docs/references/fdi/oauth/_category_.json delete mode 100644 docs/references/fdi/oauth/get-oauth-auth.mdx delete mode 100644 docs/references/fdi/oauth/get-oauth-end_session.mdx delete mode 100644 docs/references/fdi/oauth/get-oauth-login.mdx delete mode 100644 docs/references/fdi/oauth/get-oauth-logininfo.mdx delete mode 100644 docs/references/fdi/oauth/get-oauth-userinfo.mdx create mode 100644 docs/references/fdi/oauth/meta.ts delete mode 100644 docs/references/fdi/oauth/post-oauth-end_session.mdx delete mode 100644 docs/references/fdi/oauth/post-oauth-introspect.mdx delete mode 100644 docs/references/fdi/oauth/post-oauth-logout.mdx delete mode 100644 docs/references/fdi/oauth/post-oauth-revoke.mdx delete mode 100644 docs/references/fdi/oauth/post-oauth-token.mdx delete mode 100644 docs/references/fdi/passwordless/_category_.json delete mode 100644 docs/references/fdi/passwordless/get-passwordless-email-exists.mdx delete mode 100644 docs/references/fdi/passwordless/get-passwordless-phoneNumber-exists.mdx delete mode 100644 docs/references/fdi/passwordless/get-signup-email-exists.mdx delete mode 100644 docs/references/fdi/passwordless/get-signup-phoneNumber-exists.mdx create mode 100644 docs/references/fdi/passwordless/meta.ts delete mode 100644 docs/references/fdi/passwordless/post-signinup-code-consume.mdx delete mode 100644 docs/references/fdi/passwordless/post-signinup-code-resend.mdx delete mode 100644 docs/references/fdi/passwordless/post-signinup-code.mdx delete mode 100644 docs/references/fdi/session/_category_.json create mode 100644 docs/references/fdi/session/meta.ts delete mode 100644 docs/references/fdi/session/post-session-refresh.mdx delete mode 100644 docs/references/fdi/session/post-signout.mdx delete mode 100644 docs/references/fdi/thirdparty/_category_.json delete mode 100644 docs/references/fdi/thirdparty/get-authorisationurl.mdx create mode 100644 docs/references/fdi/thirdparty/meta.ts delete mode 100644 docs/references/fdi/thirdparty/post-callback-apple.mdx delete mode 100644 docs/references/fdi/thirdparty/post-signinup.mdx delete mode 100644 docs/references/fdi/webauthn/_category_.json delete mode 100644 docs/references/fdi/webauthn/get-webauthn-email-exists.mdx create mode 100644 docs/references/fdi/webauthn/meta.ts delete mode 100644 docs/references/fdi/webauthn/post-webauthn-credential.mdx delete mode 100644 docs/references/fdi/webauthn/post-webauthn-recover-account-token.mdx delete mode 100644 docs/references/fdi/webauthn/post-webauthn-recover-account.mdx delete mode 100644 docs/references/fdi/webauthn/post-webauthn-register-options.mdx delete mode 100644 docs/references/fdi/webauthn/post-webauthn-signin-options.mdx delete mode 100644 docs/references/fdi/webauthn/post-webauthn-signin.mdx delete mode 100644 docs/references/fdi/webauthn/post-webauthn-signup.mdx delete mode 100644 docs/references/frontend-sdks/_category_.json create mode 100644 docs/references/frontend-sdks/meta.ts delete mode 100644 docs/references/frontend-sdks/prebuilt-ui/_category_.json create mode 100644 docs/references/frontend-sdks/prebuilt-ui/meta.ts delete mode 100644 docs/references/frontend-sdks/supertokens-auth-react/_category_.json create mode 100644 docs/references/frontend-sdks/supertokens-auth-react/meta.ts delete mode 100644 docs/references/frontend-sdks/supertokens-web-js/_category_.json create mode 100644 docs/references/frontend-sdks/supertokens-web-js/meta.ts create mode 100644 docs/references/meta.ts delete mode 100644 docs/references/plugins/_category_.json create mode 100644 docs/references/plugins/meta.ts delete mode 100644 docs/references/testing-and-debugging/_category_.json create mode 100644 docs/references/testing-and-debugging/meta.ts delete mode 100644 docusaurus.config.ts create mode 100644 islands/ExampleAppForm.tsx create mode 100644 islands/SDKCompatibilityTable.tsx create mode 100644 microfrontends.jsonc rename {static => openapi}/cdi.yml (100%) rename {static => openapi}/fdi.yml (100%) rename {static => public}/.nojekyll (100%) rename {static => public}/cdi-file-paths.json (100%) rename {static => public}/cdi-mapping.json (100%) rename {static => public}/cdi.json (100%) create mode 100644 public/cdi.yml rename {static/img => public}/favicon.ico (100%) rename {static => public}/fdi-file-paths.json (100%) rename {static => public}/fdi-mapping.json (100%) rename {static => public}/fdi.json (100%) create mode 100644 public/fdi.yml rename {static => public}/fonts/IBMPlexMono-Regular.ttf (100%) rename {static => public}/fonts/IBMPlexMono-Thin.ttf (100%) rename {static => public}/img/account-linking/err_001.png (100%) rename {static => public}/img/account-linking/err_002.png (100%) rename {static => public}/img/account-linking/err_003.png (100%) rename {static => public}/img/account-linking/err_004.png (100%) rename {static => public}/img/account-linking/err_005.png (100%) rename {static => public}/img/account-linking/err_006.png (100%) rename {static => public}/img/account-linking/err_007.png (100%) rename {static => public}/img/account-linking/err_008.png (100%) rename {static => public}/img/active-recipe-icon.png (100%) rename {static => public}/img/architecture/managed_service.png (100%) rename {static => public}/img/architecture/managed_service_generic.png (100%) rename {static => public}/img/architecture/managed_service_without_dashboard.png (100%) rename {static => public}/img/architecture/self_hosted.png (100%) rename {static => public}/img/architecture/self_hosted_generic.png (100%) rename {static => public}/img/architecture/self_hosted_without_dashboard.png (100%) rename {static => public}/img/arrow-down.svg (100%) rename {static => public}/img/attackprotectionsuite/sequence-diagram.png (100%) rename {static => public}/img/avg-latency.png (100%) rename {static => public}/img/change-user.png (100%) rename {static => public}/img/dashboard/assign-role.png (100%) rename {static => public}/img/dashboard/create-role.gif (100%) rename {static => public}/img/dashboard/create-role.png (100%) rename {static => public}/img/dashboard/csp-error.png (100%) rename {static => public}/img/dashboard/forgot-password.png (100%) rename {static => public}/img/dashboard/login.png (100%) rename {static => public}/img/dashboard/no-roles-created.png (100%) rename {static => public}/img/dashboard/no-users.png (100%) rename {static => public}/img/dashboard/one-user.png (100%) rename {static => public}/img/dashboard/preview-role.png (100%) rename {static => public}/img/dashboard/reset-password.png (100%) rename {static => public}/img/dashboard/roles-list.png (100%) rename {static => public}/img/dashboard/select-tenant.png (100%) rename {static => public}/img/dashboard/signup.png (100%) rename {static => public}/img/dashboard/tenant-management/active-directory.png (100%) rename {static => public}/img/dashboard/tenant-management/add-provider-prompt.png (100%) rename {static => public}/img/dashboard/tenant-management/all-enabled.png (100%) rename {static => public}/img/dashboard/tenant-management/core-config.png (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-active-directory.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-apple.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-bitbucket.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-discord.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-facebook.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-github.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-gitlab.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-google-workspaces.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-google.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-linkedin.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-okta.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-public-google.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-saml.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-provider/create-twitter.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-tenant.gif (100%) rename {static => public}/img/dashboard/tenant-management/create-tenant.png (100%) rename {static => public}/img/dashboard/tenant-management/custom-provider-basic-details.png (100%) rename {static => public}/img/dashboard/tenant-management/custom-tenant-config.png (100%) rename {static => public}/img/dashboard/tenant-management/details.png (100%) rename {static => public}/img/dashboard/tenant-management/edit-core-config.png (100%) rename {static => public}/img/dashboard/tenant-management/enable-ep-tp.png (100%) rename {static => public}/img/dashboard/tenant-management/enable-tp-ep-emailotp.png (100%) rename {static => public}/img/dashboard/tenant-management/ep-create-tenant.gif (100%) rename {static => public}/img/dashboard/tenant-management/ep-enabled.png (100%) rename {static => public}/img/dashboard/tenant-management/landing.png (100%) rename {static => public}/img/dashboard/tenant-management/login-methods.png (100%) rename {static => public}/img/dashboard/tenant-management/new-boxy-config.gif (100%) rename {static => public}/img/dashboard/tenant-management/new-oauth-provider.png (100%) rename {static => public}/img/dashboard/tenant-management/new-oidc-provider.png (100%) rename {static => public}/img/dashboard/tenant-management/new-provider-details.png (100%) rename {static => public}/img/dashboard/tenant-management/new-provider.png (100%) rename {static => public}/img/dashboard/tenant-management/openid-config.png (100%) rename {static => public}/img/dashboard/tenant-management/otp-email-enabled.png (100%) rename {static => public}/img/dashboard/tenant-management/pl-create-tenant.gif (100%) rename {static => public}/img/dashboard/tenant-management/saml-config-via-api.png (100%) rename {static => public}/img/dashboard/tenant-management/saml-config.png (100%) rename {static => public}/img/dashboard/tenant-management/saml-prompt.png (100%) rename {static => public}/img/dashboard/tenant-management/secondary-factors.png (100%) rename {static => public}/img/dashboard/tenant-management/tenant-users.png (100%) rename {static => public}/img/dashboard/tenant-management/third-party-providers.png (100%) rename {static => public}/img/dashboard/tenant-management/tp-create-tenant.gif (100%) rename {static => public}/img/dashboard/tenant-management/tpep-create-tenant.gif (100%) rename {static => public}/img/dashboard/tenant-management/tpep-create-thirdparty.gif (100%) rename {static => public}/img/dashboard/tenant-management/tpl-create-tenant.gif (100%) rename {static => public}/img/dashboard/user-info-continued.png (100%) rename {static => public}/img/dashboard/user-info.png (100%) rename {static => public}/img/dashboard/view-assigned-roles.png (100%) rename {static => public}/img/discord-yellow.png (100%) rename {static => public}/img/discord.png (100%) rename {static => public}/img/docs-left-menu-chevron.png (100%) rename {static => public}/img/email-verification-clicked-no-session.png (100%) rename {static => public}/img/email-verification-link-expired.png (100%) rename {static => public}/img/email-verification-link-generic-error.png (100%) rename {static => public}/img/email-verification-send-email-generic-error.png (100%) rename {static => public}/img/email-verification-send-email.png (100%) rename {static => public}/img/email-verification-success.png (100%) rename {static => public}/img/emailpassword-field-validation-error.png (100%) rename {static => public}/img/emailpassword-general-error.png (100%) rename {static => public}/img/emailpassword-sign-in.png (100%) rename {static => public}/img/emailpassword-sign-up.png (100%) rename {static => public}/img/emailpassword-wrong-cred.png (100%) rename {static => public}/img/emailpassword/buttonText.png (100%) rename {static => public}/img/emailpassword/change-user.png (100%) rename {static => public}/img/emailpassword/custom-field-name-signup-ep.png (100%) rename {static => public}/img/emailpassword/email-verification-successful.png (100%) rename {static => public}/img/emailpassword/email-verify-email.png (100%) rename {static => public}/img/emailpassword/error.png (100%) rename {static => public}/img/emailpassword/input-background.png (100%) rename {static => public}/img/emailpassword/inspect-button-2.png (100%) rename {static => public}/img/emailpassword/inspect-button.png (100%) rename {static => public}/img/emailpassword/modified-formfields.png (100%) rename {static => public}/img/emailpassword/override/find-component.png (100%) rename {static => public}/img/emailpassword/pass-reset-email.png (100%) rename {static => public}/img/emailpassword/password-manager.png (100%) rename {static => public}/img/emailpassword/primary.png (100%) rename {static => public}/img/emailpassword/react-override-octocat.png (100%) rename {static => public}/img/emailpassword/reset-password-enter-email.png (100%) rename {static => public}/img/emailpassword/reset-password-submit-new-password.png (100%) rename {static => public}/img/emailpassword/saas-connect-popup.png (100%) rename {static => public}/img/emailpassword/signin-dark.png (100%) rename {static => public}/img/emailpassword/signin-with-custom-error-msg.png (100%) rename {static => public}/img/emailpassword/signin-with-default-values.png (100%) rename {static => public}/img/emailpassword/signup-centered-blue-button.png (100%) rename {static => public}/img/emailpassword/signup-light.png (100%) rename {static => public}/img/emailpassword/signup-with-custom-components.png (100%) rename {static => public}/img/emailpassword/signup-with-custom-error-msg.png (100%) rename {static => public}/img/emailpassword/signup-with-custom-field-order.png (100%) rename {static => public}/img/emailpassword/signup-with-default-values.png (100%) rename {static => public}/img/emailpassword/signup-with-name-and-age-failure.png (100%) rename {static => public}/img/emailpassword/signup-with-name-and-age.png (100%) rename {static => public}/img/emailpassword/sp-test-signup.png (100%) rename {static => public}/img/emailpassword/st-ep-refresh-cookies.png (100%) rename {static => public}/img/emailpassword/st-ep-refresh.png (100%) rename {static => public}/img/emailpassword/st-ep-signout.png (100%) rename {static => public}/img/emailpassword/st-test-signin-cookies.png (100%) rename {static => public}/img/emailpassword/st-user-unauthorized.png (100%) rename {static => public}/img/emailpassword/success.png (100%) rename {static => public}/img/emailpassword/textInput.png (100%) rename {static => public}/img/emailpassword/textLabel.png (100%) rename {static => public}/img/emailpassword/textPrimary.png (100%) rename {static => public}/img/emailpassword/textTitle.png (100%) rename {static => public}/img/emailpassword/verify-email-screen.png (100%) rename {static => public}/img/emailverification/resend-with-border.png (100%) rename {static => public}/img/enter-otp-error.png (100%) rename {static => public}/img/enter-otp-invalid.png (100%) rename {static => public}/img/enter-otp-screen.png (100%) create mode 100644 public/img/favicon.ico rename {static => public}/img/flutter-debug-logs.png (100%) rename {static => public}/img/form-question.png (100%) rename {static => public}/img/form-submitted-tick.png (100%) rename {static => public}/img/front-debug-logs.png (100%) rename {static => public}/img/guides/API-orange.svg (100%) rename {static => public}/img/guides/API.svg (100%) rename {static => public}/img/guides/MFA-orange.svg (100%) rename {static => public}/img/guides/MFA.svg (100%) rename {static => public}/img/guides/SDK-orange.svg (100%) rename {static => public}/img/guides/SDK.svg (100%) rename {static => public}/img/guides/attackprotectionsuite-orange.svg (100%) rename {static => public}/img/guides/attackprotectionsuite.svg (100%) rename {static => public}/img/guides/dashboard-orange.svg (100%) rename {static => public}/img/guides/dashboard.svg (100%) rename {static => public}/img/guides/emailPass-orange.svg (100%) rename {static => public}/img/guides/emailPass.svg (100%) rename {static => public}/img/guides/emailPassPlusSocial-orange.svg (100%) rename {static => public}/img/guides/emailPassPlusSocial.svg (100%) rename {static => public}/img/guides/emailPassSS.png (100%) rename {static => public}/img/guides/emailSocialSS.png (100%) rename {static => public}/img/guides/micro-orange.svg (100%) rename {static => public}/img/guides/micro.svg (100%) rename {static => public}/img/guides/multitenancy-orange.svg (100%) rename {static => public}/img/guides/multitenancy.svg (100%) rename {static => public}/img/guides/oauth-logo-orange.svg (100%) rename {static => public}/img/guides/oauth-logo.svg (100%) rename {static => public}/img/guides/passLessSocial-orange.svg (100%) rename {static => public}/img/guides/passLessSocial.svg (100%) rename {static => public}/img/guides/passwordless-orange.svg (100%) rename {static => public}/img/guides/passwordless.svg (100%) rename {static => public}/img/guides/passwordlessSS.png (100%) rename {static => public}/img/guides/passwordlessSocialSS.png (100%) rename {static => public}/img/guides/phoneNumberSS.png (100%) rename {static => public}/img/guides/phonePass-orange.svg (100%) rename {static => public}/img/guides/phonePass.svg (100%) rename {static => public}/img/guides/session-orange.svg (100%) rename {static => public}/img/guides/session.svg (100%) rename {static => public}/img/guides/social-orange.svg (100%) rename {static => public}/img/guides/social.svg (100%) rename {static => public}/img/guides/socialSS.png (100%) rename {static => public}/img/guides/unified-login-orange.svg (100%) rename {static => public}/img/guides/unified-login.svg (100%) rename {static => public}/img/guides/userRoles-orange.svg (100%) rename {static => public}/img/guides/userRoles.svg (100%) rename {static => public}/img/ic-binoculars.svg (100%) rename {static => public}/img/icon-plus.png (100%) rename {static => public}/img/icons/android.svg (100%) rename {static => public}/img/icons/check.svg (100%) rename {static => public}/img/icons/chevron-down.svg (100%) rename {static => public}/img/icons/code.svg (100%) rename {static => public}/img/icons/copy.svg (100%) rename {static => public}/img/icons/credit-card.svg (100%) rename {static => public}/img/icons/exclamation-triangle.svg (100%) rename {static => public}/img/icons/external-link.svg (100%) rename {static => public}/img/icons/eye.svg (100%) rename {static => public}/img/icons/file.svg (100%) rename {static => public}/img/icons/flutter.svg (100%) rename {static => public}/img/icons/github.svg (100%) rename {static => public}/img/icons/go.svg (100%) rename {static => public}/img/icons/hash.svg (100%) rename {static => public}/img/icons/info-circled.svg (100%) rename {static => public}/img/icons/info.svg (100%) rename {static => public}/img/icons/ios.svg (100%) rename {static => public}/img/icons/js.svg (100%) rename {static => public}/img/icons/key.svg (100%) rename {static => public}/img/icons/node.svg (100%) rename {static => public}/img/icons/pen.svg (100%) rename {static => public}/img/icons/python.svg (100%) rename {static => public}/img/icons/react.svg (100%) rename {static => public}/img/icons/search.svg (100%) rename {static => public}/img/icons/terminal.svg (100%) rename {static => public}/img/icons/thumbs-down.svg (100%) rename {static => public}/img/icons/thumbs-up.svg (100%) rename {static => public}/img/icons/typescript.svg (100%) rename {static => public}/img/icons/x.svg (100%) rename {static => public}/img/integration-lambda/add-a-layer.png (100%) rename {static => public}/img/integration-lambda/add-auth-middleware-node.png (100%) rename {static => public}/img/integration-lambda/add-env-var-node.png (100%) rename {static => public}/img/integration-lambda/add-layer-detail-node.png (100%) rename {static => public}/img/integration-lambda/click-enable-cors.png (100%) rename {static => public}/img/integration-lambda/configure-cors.png (100%) rename {static => public}/img/integration-lambda/configure-lambda-integration.png (100%) rename {static => public}/img/integration-lambda/create-api-gateway.png (100%) rename {static => public}/img/integration-lambda/create-function-node.png (100%) rename {static => public}/img/integration-lambda/create-function-python.png (100%) rename {static => public}/img/integration-lambda/create-layer.png (100%) rename {static => public}/img/integration-lambda/create-proxy-route.png (100%) rename {static => public}/img/integration-lambda/link-node-layer.jpg (100%) rename {static => public}/img/integration-lambda/link-python-layer.png (100%) rename {static => public}/img/integration-lambda/node-lambda-layer.png (100%) rename {static => public}/img/integration-lambda/python-lambda-layer.png (100%) rename {static => public}/img/integration-lambda/route-creation-complete.png (100%) rename {static => public}/img/integration-lambda/sidebar.png (100%) rename {static => public}/img/logo.svg (100%) rename {static => public}/img/logos/android.svg (100%) rename {static => public}/img/logos/angular.svg (100%) rename {static => public}/img/logos/anthropic.svg (100%) rename {static => public}/img/logos/aws-lambda.svg (100%) rename {static => public}/img/logos/boxyhq.png (100%) rename {static => public}/img/logos/capacitor-js.svg (100%) rename {static => public}/img/logos/capacitorjs-icon.svg (100%) rename {static => public}/img/logos/cdi.svg (100%) rename {static => public}/img/logos/chatgpt.svg (100%) rename {static => public}/img/logos/discord.svg (100%) rename {static => public}/img/logos/django.svg (100%) rename {static => public}/img/logos/electron.svg (100%) rename {static => public}/img/logos/fastapi.svg (100%) rename {static => public}/img/logos/fauna-db.svg (100%) rename {static => public}/img/logos/fdi.svg (100%) rename {static => public}/img/logos/github.svg (100%) rename {static => public}/img/logos/go.svg (100%) rename {static => public}/img/logos/graphql-logo.png (100%) rename {static => public}/img/logos/graphql.svg (100%) rename {static => public}/img/logos/hasura-logo.png (100%) rename {static => public}/img/logos/hasura.svg (100%) rename {static => public}/img/logos/ios.svg (100%) rename {static => public}/img/logos/js.svg (100%) rename {static => public}/img/logos/mcp.svg (100%) rename {static => public}/img/logos/nestjs.svg (100%) rename {static => public}/img/logos/netlify.svg (100%) rename {static => public}/img/logos/next-logo.png (100%) rename {static => public}/img/logos/nextjs.svg (100%) rename {static => public}/img/logos/node.svg (100%) rename {static => public}/img/logos/nodejs-small.svg (100%) rename {static => public}/img/logos/python.svg (100%) rename {static => public}/img/logos/react.svg (100%) rename {static => public}/img/logos/redwood-logo.png (100%) rename {static => public}/img/logos/saml.svg (100%) rename {static => public}/img/logos/supabase-logo.jpg (100%) rename {static => public}/img/logos/supabase.svg (100%) rename {static => public}/img/logos/supertokens-dark.svg (100%) rename {static => public}/img/logos/supertokens-light.svg (100%) rename {static => public}/img/logos/t3-chat.svg (100%) rename {static => public}/img/logos/t4-app.png (100%) rename {static => public}/img/logos/vercel.jpeg (100%) rename {static => public}/img/logos/vercel.svg (100%) rename {static => public}/img/logos/vue.svg (100%) rename {static => public}/img/magic-link-clicked-different-device.png (100%) rename {static => public}/img/magic-link-clicked.png (100%) rename {static => public}/img/magic-link-sent-error.png (100%) rename {static => public}/img/magic-link-sent.png (100%) rename {static => public}/img/microservice_auth/architecture.png (100%) rename {static => public}/img/migration/firebase_password_hashing_params.png (100%) rename {static => public}/img/migration/session-migration-diagram.png (100%) rename {static => public}/img/migration/supertokens_managed_service_edit_configuration_button.png (100%) rename {static => public}/img/migration/supertokens_managed_service_firebase_signer_key.png (100%) rename {static => public}/img/multi-tenancy-architecture.png (100%) rename {static => public}/img/multi-tenant-multi-app-diagram.svg (100%) rename {static => public}/img/multi-tenant-multi-app.png (100%) rename {static => public}/img/multi-tenant-single-app-diagram.svg (100%) rename {static => public}/img/multi-tenant-single-app.png (100%) rename {static => public}/img/new-password-general-error.png (100%) rename {static => public}/img/oauth/authorization-code-flow.png (100%) rename {static => public}/img/oauth/client-credentials-flow.png (100%) rename {static => public}/img/oauth/machine-to-machine.png (100%) rename {static => public}/img/oauth/multiple-frontend-domains-with-a-single-backend.png (100%) rename {static => public}/img/oauth/multiple-frontend-domains-with-separate-backends.png (100%) rename {static => public}/img/oauth/reuse-web-ui-for-mobile.png (100%) rename {static => public}/img/other-framework-setup.png (100%) rename {static => public}/img/otp-magic-link-same-time.png (100%) rename {static => public}/img/passkey.png (100%) rename {static => public}/img/password-reset-general-error.png (100%) rename {static => public}/img/password-reset-success.png (100%) rename {static => public}/img/passwordless-email-phone.png (100%) rename {static => public}/img/passwordless-email.png (100%) rename {static => public}/img/passwordless-invalid-phone-email.png (100%) rename {static => public}/img/passwordless-magic-link-expired.png (100%) rename {static => public}/img/passwordless-passwordless-general-error.png (100%) rename {static => public}/img/passwordless-phone.png (100%) rename {static => public}/img/passwordless-too-many-otp-tries.png (100%) rename {static => public}/img/passwordless/buttonText.png (100%) rename {static => public}/img/passwordless/change-user.png (100%) rename {static => public}/img/passwordless/diagrams/magic_link_flow.png (100%) rename {static => public}/img/passwordless/diagrams/otp_flow.png (100%) rename {static => public}/img/passwordless/diagrams/passwordless-migration-flow.png (100%) rename {static => public}/img/passwordless/error.png (100%) rename {static => public}/img/passwordless/input-background.png (100%) rename {static => public}/img/passwordless/inspect-button.png (100%) rename {static => public}/img/passwordless/modified-formfields.png (100%) rename {static => public}/img/passwordless/override/find-component.png (100%) rename {static => public}/img/passwordless/primary.png (100%) rename {static => public}/img/passwordless/react-override-octocat.png (100%) rename {static => public}/img/passwordless/signinup-centered-blue-button.png (100%) rename {static => public}/img/passwordless/signinup-dark.png (100%) rename {static => public}/img/passwordless/signinup-light.png (100%) rename {static => public}/img/passwordless/sms-api-key.png (100%) rename {static => public}/img/passwordless/sp-test-signup-1.png (100%) rename {static => public}/img/passwordless/sp-test-signup-2.png (100%) rename {static => public}/img/passwordless/st-ep-refresh-cookies.png (100%) rename {static => public}/img/passwordless/st-ep-refresh.png (100%) rename {static => public}/img/passwordless/st-ep-signout.png (100%) rename {static => public}/img/passwordless/st-test-signin-cookies.png (100%) rename {static => public}/img/passwordless/st-user-unauthorized.png (100%) rename {static => public}/img/passwordless/success.png (100%) rename {static => public}/img/passwordless/textInput.png (100%) rename {static => public}/img/passwordless/textLabel.png (100%) rename {static => public}/img/passwordless/textPrimary.png (100%) rename {static => public}/img/passwordless/textTitle.png (100%) rename {static => public}/img/prebuilt-and-custom-ui-screenshot.png (100%) rename {static => public}/img/progressive-profiling.png (100%) rename {static => public}/img/quickstart-next-steps-0.png (100%) rename {static => public}/img/quickstart-next-steps-1.png (100%) rename {static => public}/img/quickstart-next-steps-copy-creds.png (100%) rename {static => public}/img/quickstart-next-steps-create-deployment.png (100%) rename {static => public}/img/react-native-debug-logs.png (100%) rename {static => public}/img/recipe-tabs/recipe-email-social.png (100%) rename {static => public}/img/recipe-tabs/recipe-email.png (100%) rename {static => public}/img/recipe-tabs/recipe-passwordless-social.png (100%) rename {static => public}/img/recipe-tabs/recipe-passwordless.png (100%) rename {static => public}/img/recipe-tabs/recipe-session.png (100%) rename {static => public}/img/recipe-tabs/recipe-social.png (100%) rename {static => public}/img/recipe_selector_close.png (100%) rename {static => public}/img/recipe_selector_open.png (100%) rename {static => public}/img/reset-password-email-sent.png (100%) rename {static => public}/img/reset-password-email.png (100%) rename {static => public}/img/reset-password-new-password-invalid-token.png (100%) rename {static => public}/img/reset-password-new-password.png (100%) rename {static => public}/img/rpm.png (100%) rename {static => public}/img/saas-dev-connect.png (100%) rename {static => public}/img/saas/supertokens-core-deploy.png (100%) rename {static => public}/img/saas/supertokens-core-quicksetup.png (100%) rename {static => public}/img/saas/supertokens-core-success.png (100%) rename {static => public}/img/saml-oauth.png (100%) rename {static => public}/img/saml/supertokens-boxyhq.png (100%) rename {static => public}/img/select.svg (100%) rename {static => public}/img/session_flow.png (100%) rename {static => public}/img/sidebar-category-icons/lightning.png (100%) rename {static => public}/img/sidebar-category-icons/pencil.png (100%) rename {static => public}/img/signupDropdownIcon.png (100%) rename {static => public}/img/signupDropdownIconDisabled.png (100%) rename {static => public}/img/single-tenant-multi-app-diagram.png (100%) rename {static => public}/img/single-tenant-multi-app-diagram.svg (100%) rename {static => public}/img/single-tenant-multi-app.png (100%) rename {static => public}/img/single-tenant-single-app-diagram.svg (100%) rename {static => public}/img/single-tenant-single-app.png (100%) rename {static => public}/img/st-session-cookies.png (100%) rename {static => public}/img/st-session-new-session.png (100%) rename {static => public}/img/st-session-userid.png (100%) rename {static => public}/img/st-thirdparty-change-user.png (100%) rename {static => public}/img/styling/branding_element.png (100%) rename {static => public}/img/tenant-discovery-email-form.png (100%) rename {static => public}/img/thirdparty-general-error.png (100%) rename {static => public}/img/thirdparty-no-email.png (100%) rename {static => public}/img/thirdparty-sign-in-custom-provider.png (100%) rename {static => public}/img/thirdparty-thirdparty-callback.png (100%) rename {static => public}/img/thirdparty/dark-theme.png (100%) rename {static => public}/img/thirdparty/inspect-button-2.png (100%) rename {static => public}/img/thirdparty/inspect-button.png (100%) rename {static => public}/img/thirdparty/override/find-component.png (100%) rename {static => public}/img/thirdparty/react-override-octocat.png (100%) rename {static => public}/img/thirdparty/signup-light.png (100%) rename {static => public}/img/thirdparty/textTitle.png (100%) rename {static => public}/img/thirdparty/title-border.png (100%) rename {static => public}/img/thirdpartyemailpassword-field-validation-error.png (100%) rename {static => public}/img/thirdpartyemailpassword-general-error.png (100%) rename {static => public}/img/thirdpartyemailpassword-no-email.png (100%) rename {static => public}/img/thirdpartyemailpassword-sign-in-custom-provider.png (100%) rename {static => public}/img/thirdpartyemailpassword-sign-in.png (100%) rename {static => public}/img/thirdpartyemailpassword-sign-up.png (100%) rename {static => public}/img/thirdpartyemailpassword-thirdparty-callback.png (100%) rename {static => public}/img/thirdpartyemailpassword-wrong-cred.png (100%) rename {static => public}/img/thirdpartyemailpassword/auth0-database.png (100%) rename {static => public}/img/thirdpartyemailpassword/change-user.png (100%) rename {static => public}/img/thirdpartyemailpassword/custom-field-name-signup-ep.png (100%) rename {static => public}/img/thirdpartyemailpassword/custom-field-name-signup.png (100%) rename {static => public}/img/thirdpartyemailpassword/default-directory-settings.png (100%) rename {static => public}/img/thirdpartyemailpassword/ep-account-migration.png (100%) rename {static => public}/img/thirdpartyemailpassword/modified-formfields.png (100%) rename {static => public}/img/thirdpartyemailpassword/override/find-component.png (100%) rename {static => public}/img/thirdpartyemailpassword/react-override-octocat.png (100%) rename {static => public}/img/thirdpartyemailpassword/session-migration.png (100%) rename {static => public}/img/thirdpartyemailpassword/signin-dark.png (100%) rename {static => public}/img/thirdpartyemailpassword/signin-light.png (100%) rename {static => public}/img/thirdpartyemailpassword/signin-with-custom-error-msg.png (100%) rename {static => public}/img/thirdpartyemailpassword/signin-with-default-values.png (100%) rename {static => public}/img/thirdpartyemailpassword/signup-centered-blue-button.png (100%) rename {static => public}/img/thirdpartyemailpassword/signup-dark.png (100%) rename {static => public}/img/thirdpartyemailpassword/signup-invalid-age-light.png (100%) rename {static => public}/img/thirdpartyemailpassword/signup-light.png (100%) rename {static => public}/img/thirdpartyemailpassword/signup-with-custom-components.png (100%) rename {static => public}/img/thirdpartyemailpassword/signup-with-custom-error-msg.png (100%) rename {static => public}/img/thirdpartyemailpassword/signup-with-custom-field-order.png (100%) rename {static => public}/img/thirdpartyemailpassword/signup-with-default-values.png (100%) rename {static => public}/img/thirdpartyemailpassword/signup-with-name-and-age.png (100%) rename {static => public}/img/thirdpartyemailpassword/supabase/create_policy.png (100%) rename {static => public}/img/thirdpartyemailpassword/supabase/policy_config_insert.png (100%) rename {static => public}/img/thirdpartyemailpassword/supabase/policy_config_select.png (100%) rename {static => public}/img/thirdpartyemailpassword/supabase/supabase_app_authenticated_screen.png (100%) rename {static => public}/img/thirdpartyemailpassword/supabase/supabase_dashboard_create.png (100%) rename {static => public}/img/thirdpartyemailpassword/supabase/supabase_table_create.png (100%) rename {static => public}/img/thirdpartyemailpassword/supabase/table_with_user.png (100%) rename {static => public}/img/thirdpartyemailpassword/tp-account-migration.png (100%) rename {static => public}/img/thirdpartypasswordless-email-phone.png (100%) rename {static => public}/img/thirdpartypasswordless-email.png (100%) rename {static => public}/img/thirdpartypasswordless-general-error.png (100%) rename {static => public}/img/thirdpartypasswordless-invalid-phone-email.png (100%) rename {static => public}/img/thirdpartypasswordless-magic-link-expired.png (100%) rename {static => public}/img/thirdpartypasswordless-no-email.png (100%) rename {static => public}/img/thirdpartypasswordless-passwordless-general-error.png (100%) rename {static => public}/img/thirdpartypasswordless-phone.png (100%) rename {static => public}/img/thirdpartypasswordless-sign-in-custom-provider.png (100%) rename {static => public}/img/thirdpartypasswordless-thirdparty-callback.png (100%) rename {static => public}/img/thirdpartypasswordless-too-many-otp-tries.png (100%) rename {static => public}/img/thirdpartypasswordless/change-user.png (100%) rename {static => public}/img/thirdpartypasswordless/override/find-component.png (100%) rename {static => public}/img/thirdpartypasswordless/signinup-light.png (100%) rename {static => public}/img/ui-switcher-check.svg (100%) rename {static => public}/img/user-banning.png (100%) rename {static => public}/img/user-profile.png (100%) rename {static => public}/img/userroles/user-roles-intro.png (100%) rename {static => public}/img/webauthn-recover-account.png (100%) rename {static => public}/img/webauthn-signin.png (100%) rename {static => public}/img/webauthn-signup.png (100%) rename {static => public}/img/work-in-progress.png (100%) delete mode 100644 scripts/ai.ts create mode 100644 scripts/blume/convert-categories.mjs create mode 100644 scripts/blume/convert-content.mjs create mode 100644 scripts/blume/create-route-manifest.mjs create mode 100644 scripts/blume/fix-legacy-components.mjs create mode 100644 scripts/blume/fix-stale-links.mjs create mode 100644 scripts/blume/openapi-redirects.ts create mode 100644 scripts/blume/prefix-content-assets.mjs create mode 100644 scripts/blume/remove-openapi-stubs.mjs create mode 100644 scripts/blume/restore-frontmatter.mjs create mode 100644 scripts/blume/route-manifest.json delete mode 100644 scripts/generate-api-reference-pages.ts delete mode 100644 scripts/search.ts delete mode 100644 scripts/search/api-reference-index.ts delete mode 100644 scripts/search/index.ts delete mode 100644 scripts/search/sdk-reference-index.ts delete mode 100644 scripts/search/search-index.ts delete mode 100644 sidebars.ts delete mode 100644 src/components/APIRequest/APIRequest.scss delete mode 100644 src/components/APIRequest/APIRequest.tsx delete mode 100644 src/components/APIRequest/APIRequestClient.tsx delete mode 100644 src/components/APIRequest/APIRequestCodeSnippet.tsx delete mode 100644 src/components/APIRequest/APIRequestEditParametersModal.tsx delete mode 100644 src/components/APIRequest/APIRequestPage.tsx delete mode 100644 src/components/APIRequest/APIRequestParametersCard.tsx delete mode 100644 src/components/APIRequest/APIRequestResponsePreview.tsx delete mode 100644 src/components/APIRequest/APIRequestSchemaCard.tsx delete mode 100644 src/components/APIRequest/ApiRequestApiTypeCallout.tsx delete mode 100644 src/components/APIRequest/index.ts delete mode 100644 src/components/Accordion.scss delete mode 100644 src/components/Accordion.tsx delete mode 100644 src/components/BetaBadge.tsx delete mode 100644 src/components/Callouts/OAuthCallouts.tsx delete mode 100644 src/components/Callouts/PaidFeatureCallouts.tsx delete mode 100644 src/components/Callouts/TokensCallout.tsx delete mode 100644 src/components/Callouts/index.ts delete mode 100644 src/components/Cards/APIRequestCard.scss delete mode 100644 src/components/Cards/AccountTypeCard.tsx delete mode 100644 src/components/Cards/CodeSampleCard.tsx delete mode 100644 src/components/Cards/GoFrameworksCard.tsx delete mode 100644 src/components/Cards/HTTPRequestCard.scss delete mode 100644 src/components/Cards/HTTPRequestCard.tsx delete mode 100644 src/components/Cards/JavascriptHttpLibraryCard.tsx delete mode 100644 src/components/Cards/ManagedOrSelfHostedCard.tsx delete mode 100644 src/components/Cards/MobileFrameworksCard.tsx delete mode 100644 src/components/Cards/NodeFrameworksCard.tsx delete mode 100644 src/components/Cards/NodePackageManagerCard.tsx delete mode 100644 src/components/Cards/NpmOrScriptsCard.tsx delete mode 100644 src/components/Cards/PasswordlessConfigCard.tsx delete mode 100644 src/components/Cards/PythonFrameworksCard.tsx delete mode 100644 src/components/Cards/PythonPackageManagerCard.tsx delete mode 100644 src/components/Cards/PythonSyncAsyncCard.tsx delete mode 100644 src/components/Cards/ReferenceCard/ReferenceCard.tsx delete mode 100644 src/components/Cards/ReferenceCard/styles.scss delete mode 100644 src/components/Cards/ThirdPartyBuiltinProvidersCard.tsx delete mode 100644 src/components/Cards/index.ts delete mode 100644 src/components/Cards/styles.scss delete mode 100644 src/components/ColorModeToggle.scss delete mode 100644 src/components/ColorModeToggle.tsx delete mode 100644 src/components/ConditionalContent.tsx delete mode 100644 src/components/CopyPageContentButton.scss delete mode 100644 src/components/CopyPageContentButton.tsx delete mode 100644 src/components/DescriptionText.tsx delete mode 100644 src/components/DocItemContextCondition.tsx delete mode 100644 src/components/DocItemContextValue.tsx delete mode 100644 src/components/Forms/AppInfoForm.scss delete mode 100644 src/components/Forms/AppInfoForm.tsx delete mode 100644 src/components/Forms/ExampleAppForm.scss delete mode 100644 src/components/Forms/ExampleAppForm.tsx delete mode 100644 src/components/Forms/PasswordlessRecipeForm.tsx delete mode 100644 src/components/Forms/index.ts delete mode 100644 src/components/MenuItemIcon.tsx delete mode 100644 src/components/Modal/SideModal.scss delete mode 100644 src/components/Modal/SideModal.tsx delete mode 100644 src/components/Modal/index.tsx delete mode 100644 src/components/NewBadge.tsx delete mode 100644 src/components/PageOptionsDropdownMenu.tsx delete mode 100644 src/components/PaidFeatureCallout.tsx delete mode 100644 src/components/Question.tsx delete mode 100644 src/components/RadioCard.scss delete mode 100644 src/components/RemoveForLLMs.tsx delete mode 100644 src/components/SDKCompatibilityTable.tsx delete mode 100644 src/components/SDKReference/SDKReference.scss delete mode 100644 src/components/SDKReference/SDKReference.tsx delete mode 100644 src/components/SDKReference/index.ts delete mode 100644 src/components/ScrollOffsetFix.tsx delete mode 100644 src/components/Search.scss delete mode 100644 src/components/Search.tsx delete mode 100644 src/components/Select/AccountTypeSelect.tsx delete mode 100644 src/components/Select/AppTypeSelect.tsx delete mode 100644 src/components/Select/GoFrameworksSelect.tsx delete mode 100644 src/components/Select/JavascriptHttpLibrarySelect.tsx delete mode 100644 src/components/Select/MobileFrameworksSelect.tsx delete mode 100644 src/components/Select/NextjsRouterTypeSelect.tsx delete mode 100644 src/components/Select/NodeFrameworksSelect.tsx delete mode 100644 src/components/Select/NodePackageManagerSelect.tsx delete mode 100644 src/components/Select/NpmOrScriptsSelect.tsx delete mode 100644 src/components/Select/PasswordlessContactMethodSelect.tsx delete mode 100644 src/components/Select/PasswordlessFlowTypeSelect.tsx delete mode 100644 src/components/Select/PythonFrameworksSelect.tsx delete mode 100644 src/components/Select/PythonPackageManagerSelect.tsx delete mode 100644 src/components/Select/PythonSyncAsyncSelect.tsx delete mode 100644 src/components/Select/SelfHostedDeploymentTypeSelect.tsx delete mode 100644 src/components/Select/TenantTypeSelect.tsx delete mode 100644 src/components/Select/ThirdpartyBuiltinProvidersSelect.tsx delete mode 100644 src/components/Select/index.ts delete mode 100644 src/components/Separator.tsx delete mode 100644 src/components/Steps.tsx delete mode 100644 src/components/StripParagraph.tsx delete mode 100644 src/components/Tabs/BackendTabs.tsx delete mode 100644 src/components/Tabs/DatabaseTabs.tsx delete mode 100644 src/components/Tabs/FrontendCustomUITabs.tsx delete mode 100644 src/components/Tabs/FrontendPrebuiltUITabs.tsx delete mode 100644 src/components/Tabs/FrontendTabs.tsx delete mode 100644 src/components/Tabs/OSTabs.tsx delete mode 100644 src/components/Tabs/ReactRouterVersionsTabs.tsx delete mode 100644 src/components/Tabs/RowndFrontendTabs.tsx delete mode 100644 src/components/Tabs/SelfHostingTabs.tsx delete mode 100644 src/components/Tabs/index.ts delete mode 100644 src/components/TenantTypeSwitch.tsx delete mode 100644 src/components/Typography.tsx delete mode 100644 src/components/UITypeSwitch.tsx delete mode 100644 src/components/index.ts delete mode 100644 src/context/DocItemContext.tsx delete mode 100644 src/context/TabsContex.tsx delete mode 100644 src/context/index.ts delete mode 100644 src/css/custom.scss delete mode 100644 src/css/fonts.css delete mode 100644 src/css/radix.css delete mode 100644 src/hooks/index.ts delete mode 100644 src/hooks/useDocItemStore.ts delete mode 100644 src/hooks/useDocPageData.ts delete mode 100644 src/hooks/useFilteredTocItems.ts delete mode 100644 src/hooks/useIsVisible.ts delete mode 100644 src/hooks/useLoadOpenApiSchema.ts delete mode 100644 src/hooks/useSelection.ts delete mode 100644 src/hooks/useSelectionStore.ts delete mode 100644 src/hooks/useUIType.ts delete mode 100644 src/lib/amplitude.ts delete mode 100644 src/lib/analytics.ts delete mode 100644 src/lib/api.ts delete mode 100644 src/lib/categoryIcons.tsx delete mode 100644 src/lib/constants.ts delete mode 100644 src/lib/docPageStore.ts delete mode 100644 src/lib/generateCodeSnippetFromAPIRequest.ts delete mode 100644 src/lib/generateExampleFromAPIRequestSchema.ts delete mode 100644 src/lib/getExampleFromSchema.ts delete mode 100644 src/lib/index.ts delete mode 100644 src/lib/normalizeOpenAPIObject.ts delete mode 100644 src/lib/normalizePath.ts delete mode 100644 src/lib/replaceVariablesForScalar.ts delete mode 100644 src/lib/replaceVariablesInApiPath.ts delete mode 100644 src/lib/scrollOffset.ts delete mode 100644 src/lib/search.ts delete mode 100644 src/lib/themeStore.ts delete mode 100644 src/lib/types.ts delete mode 100644 src/plugins/addNofollowToExternalLinks.js delete mode 100644 src/plugins/generateLllmsFullTxt.ts delete mode 100644 src/plugins/generateLllmsTxt.ts delete mode 100644 src/plugins/reactBundle.js delete mode 100644 src/plugins/remarkAddBadgesInHeadings.ts delete mode 100644 src/plugins/remarkAddPaidFeatureCallout.ts delete mode 100644 src/plugins/remarkDocItemContextValues.ts delete mode 100644 src/plugins/remarkDocItemDescription.ts delete mode 100644 src/plugins/remarkRemoveCodeTypeCheckingCommentsAndRows.ts delete mode 100644 src/plugins/remarkRemoveWebJsScriptImports.ts delete mode 100644 src/plugins/transformOpenSearchLink.js delete mode 100644 src/plugins/utils/getAllMdxFiles.ts delete mode 100644 src/theme/Admonition/Icon/Danger.tsx delete mode 100644 src/theme/Admonition/Icon/Info.tsx delete mode 100644 src/theme/Admonition/Icon/Note.tsx delete mode 100644 src/theme/Admonition/Icon/Tip.tsx delete mode 100644 src/theme/Admonition/Icon/Warning.tsx delete mode 100644 src/theme/Admonition/Layout/index.tsx delete mode 100644 src/theme/Admonition/Layout/styles.module.css delete mode 100644 src/theme/Admonition/Type/Caution.tsx delete mode 100644 src/theme/Admonition/Type/Danger.tsx delete mode 100644 src/theme/Admonition/Type/Info.tsx delete mode 100644 src/theme/Admonition/Type/Note.tsx delete mode 100644 src/theme/Admonition/Type/Tip.tsx delete mode 100644 src/theme/Admonition/Type/Warning.tsx delete mode 100644 src/theme/Admonition/Types.tsx delete mode 100644 src/theme/Admonition/admonition.scss delete mode 100644 src/theme/Admonition/index.tsx delete mode 100644 src/theme/CodeBlock/Container/index.tsx delete mode 100644 src/theme/CodeBlock/Container/styles.module.css delete mode 100644 src/theme/CodeBlock/Content/Element.tsx delete mode 100644 src/theme/CodeBlock/Content/String.tsx delete mode 100644 src/theme/CodeBlock/Content/styles.module.css delete mode 100644 src/theme/CodeBlock/CopyButton/index.tsx delete mode 100644 src/theme/CodeBlock/CopyButton/styles.module.css delete mode 100644 src/theme/CodeBlock/Line/index.tsx delete mode 100644 src/theme/CodeBlock/Line/styles.module.css delete mode 100644 src/theme/CodeBlock/WordWrapButton/index.tsx delete mode 100644 src/theme/CodeBlock/WordWrapButton/styles.module.css delete mode 100644 src/theme/CodeBlock/index.tsx delete mode 100644 src/theme/CodeInline/index.scss delete mode 100644 src/theme/CodeInline/index.tsx delete mode 100644 src/theme/DocItem/Content/index.scss delete mode 100644 src/theme/DocItem/Content/index.tsx delete mode 100644 src/theme/DocItem/Footer/index.scss delete mode 100644 src/theme/DocItem/Footer/index.tsx delete mode 100644 src/theme/DocItem/Layout/index.tsx delete mode 100644 src/theme/DocItem/Layout/styles.module.css delete mode 100644 src/theme/DocItem/Metadata/index.tsx delete mode 100644 src/theme/DocItem/Paginator/index.tsx delete mode 100644 src/theme/DocItem/TOC/Desktop/index.tsx delete mode 100644 src/theme/DocItem/TOC/Mobile/index.tsx delete mode 100644 src/theme/DocItem/TOC/Mobile/styles.module.css delete mode 100644 src/theme/DocItem/index.tsx delete mode 100644 src/theme/DocPaginator/index.tsx delete mode 100644 src/theme/DocRoot/Layout/Main/index.tsx delete mode 100644 src/theme/DocRoot/Layout/Main/styles.module.css delete mode 100644 src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.tsx delete mode 100644 src/theme/DocRoot/Layout/Sidebar/ExpandButton/styles.module.css delete mode 100644 src/theme/DocRoot/Layout/Sidebar/index.tsx delete mode 100644 src/theme/DocRoot/Layout/Sidebar/styles.module.css delete mode 100644 src/theme/DocRoot/Layout/index.tsx delete mode 100644 src/theme/DocRoot/Layout/styles.module.css delete mode 100644 src/theme/DocRoot/index.tsx delete mode 100644 src/theme/DocSidebar/AdditionalLinks.scss delete mode 100644 src/theme/DocSidebar/AdditionalLinks.tsx delete mode 100644 src/theme/DocSidebar/Desktop/CollapseButton/index.tsx delete mode 100644 src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css delete mode 100644 src/theme/DocSidebar/Desktop/Content/index.tsx delete mode 100644 src/theme/DocSidebar/Desktop/Content/styles.module.css delete mode 100644 src/theme/DocSidebar/Desktop/index.tsx delete mode 100644 src/theme/DocSidebar/Desktop/styles.module.css delete mode 100644 src/theme/DocSidebar/Mobile/index.scss delete mode 100644 src/theme/DocSidebar/Mobile/index.tsx delete mode 100644 src/theme/DocSidebar/index.tsx delete mode 100644 src/theme/DocSidebarItem/Category/index.tsx delete mode 100644 src/theme/DocSidebarItem/Category/styles.scss delete mode 100644 src/theme/DocSidebarItem/Html/index.tsx delete mode 100644 src/theme/DocSidebarItem/Html/styles.module.css delete mode 100644 src/theme/DocSidebarItem/Link/index.tsx delete mode 100644 src/theme/DocSidebarItem/Link/styles.module.scss delete mode 100644 src/theme/DocSidebarItem/index.tsx delete mode 100644 src/theme/EditMetaRow/index.tsx delete mode 100644 src/theme/EditMetaRow/styles.module.css delete mode 100644 src/theme/EditThisPage/index.tsx delete mode 100644 src/theme/Heading/index.tsx delete mode 100644 src/theme/Heading/styles.module.css delete mode 100644 src/theme/Layout/Provider/index.tsx delete mode 100644 src/theme/Layout/index.tsx delete mode 100644 src/theme/Layout/styles.module.css delete mode 100644 src/theme/Logo/index.tsx delete mode 100644 src/theme/MDXComponents.tsx delete mode 100644 src/theme/MDXComponents/Code.tsx delete mode 100644 src/theme/MDXComponents/Heading.tsx delete mode 100644 src/theme/MDXComponents/Img/index.tsx delete mode 100644 src/theme/MDXComponents/Img/styles.module.css delete mode 100644 src/theme/Navbar/ColorModeToggle/index.tsx delete mode 100644 src/theme/Navbar/ColorModeToggle/styles.module.css delete mode 100644 src/theme/Navbar/Content/index.tsx delete mode 100644 src/theme/Navbar/Content/styles.module.css delete mode 100644 src/theme/Navbar/Layout/index.tsx delete mode 100644 src/theme/Navbar/Layout/styles.module.scss delete mode 100644 src/theme/Navbar/Logo/index.scss delete mode 100644 src/theme/Navbar/Logo/index.tsx delete mode 100644 src/theme/Navbar/MobileSidebar/Header/index.tsx delete mode 100644 src/theme/Navbar/MobileSidebar/Layout/index.scss delete mode 100644 src/theme/Navbar/MobileSidebar/Layout/index.tsx delete mode 100644 src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx delete mode 100644 src/theme/Navbar/MobileSidebar/SecondaryMenu/index.tsx delete mode 100644 src/theme/Navbar/MobileSidebar/Toggle/index.tsx delete mode 100644 src/theme/Navbar/MobileSidebar/index.tsx delete mode 100644 src/theme/Navbar/Search/index.tsx delete mode 100644 src/theme/Navbar/Search/styles.module.css delete mode 100644 src/theme/Navbar/index.tsx delete mode 100644 src/theme/NavbarItem/ComponentTypes.tsx delete mode 100644 src/theme/NavbarItem/DefaultNavbarItem.tsx delete mode 100644 src/theme/NavbarItem/DocNavbarItem.tsx delete mode 100644 src/theme/NavbarItem/DocSidebarNavbarItem.tsx delete mode 100644 src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx delete mode 100644 src/theme/NavbarItem/DocsVersionNavbarItem.tsx delete mode 100644 src/theme/NavbarItem/DropdownNavbarItem/index.tsx delete mode 100644 src/theme/NavbarItem/DropdownNavbarItem/styles.module.css delete mode 100644 src/theme/NavbarItem/HtmlNavbarItem.tsx delete mode 100644 src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx delete mode 100644 src/theme/NavbarItem/LocaleDropdownNavbarItem/styles.module.css delete mode 100644 src/theme/NavbarItem/NavbarNavLink.tsx delete mode 100644 src/theme/NavbarItem/SearchNavbarItem.tsx delete mode 100644 src/theme/NavbarItem/index.tsx delete mode 100644 src/theme/PaginatorNavLink/index.tsx delete mode 100644 src/theme/Root.tsx delete mode 100644 src/theme/SearchBar/index.tsx delete mode 100644 src/theme/SearchBar/styles.css delete mode 100644 src/theme/TOC/index.tsx delete mode 100644 src/theme/TOC/styles.module.css delete mode 100644 src/theme/TOCCollapsible/CollapseButton/index.tsx delete mode 100644 src/theme/TOCCollapsible/CollapseButton/styles.module.css delete mode 100644 src/theme/TOCCollapsible/index.tsx delete mode 100644 src/theme/TOCCollapsible/styles.module.css delete mode 100644 src/theme/TOCItems/Tree.tsx delete mode 100644 src/theme/TOCItems/index.scss delete mode 100644 src/theme/TOCItems/index.tsx delete mode 100644 src/theme/TabItem/index.tsx delete mode 100644 src/theme/TabItem/styles.scss delete mode 100644 src/theme/Tabs/index.tsx delete mode 100644 src/theme/Tabs/styles.module.css delete mode 100644 static/img/docusaurus-social-card.jpg delete mode 100644 static/img/docusaurus.png delete mode 100644 static/img/undraw_docusaurus_mountain.svg delete mode 100644 static/img/undraw_docusaurus_react.svg delete mode 100644 static/img/undraw_docusaurus_tree.svg create mode 100644 task.md create mode 100644 theme.css create mode 100644 vercel.json diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 65a65bcf79..bd2b6e6109 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -9,9 +9,10 @@ ## Checklist -- [ ] Algolia search needs to be updated? (If there is a new sub docs project, then yes) -- [ ] Sitemap needs to be updated? (If there is a new sub docs project, then yes) -- [ ] Checked for broken links? (Run `cd v3 && npm run build`) +- [ ] Ran `npm run build` +- [ ] Ran `npm run typecheck` +- [ ] Ran `npm test` +- [ ] Checked changed routes and redirects - [ ] Changes required to the demo apps corresponding to the docs? ## Remaining TODOs for this PR diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index bd21edd52b..972dac0534 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,13 +1,23 @@ -name: Deploy -run-name: Deploy to ${{ github.ref_name == 'master' && 'the production website' || 'a preview website' }} +name: Build on: pull_request: paths: - "docs/**" - - "static/**" - - "src/**" + - "components/**" + - "islands/**" + - "openapi/**" + - "public/**" + - "scripts/blume/**" + - "blume.config.ts" + - "components.ts" + - "microfrontends.jsonc" + - "theme.css" + - "tsconfig.json" + - "vercel.json" + - ".github/workflows/deploy.yml" - "package-lock.json" + - "package.json" push: branches: - master @@ -21,50 +31,19 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: "20" + node-version: "22.12" cache: "npm" cache-dependency-path: "package-lock.json" - name: Install Dependencies - run: npm install + run: npm ci - - name: Build Docusaurus Site + - name: Build Blume site run: npm run build - name: Upload Build Artifacts uses: actions/upload-artifact@v4 with: - name: docusaurus-build - path: build + name: blume-build + path: dist retention-days: 1 - - trigger: - needs: build - runs-on: ubuntu-latest - steps: - - name: Set STAGE environment variable - shell: bash - run: | - if [[ "${{ github.ref_name }}" == "master" ]]; then - STAGE="production" - else - STAGE="preview" - fi - - echo "STAGE=$STAGE" >> $GITHUB_ENV - - - name: Trigger the backend website CI - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.BACKEND_WEBSITE_TOKEN }} - script: | - github.rest.actions.createWorkflowDispatch({ - owner: 'supertokens', - repo: 'supertokens-backend-website', - workflow_id: 'release-documentation-changes.yml', - ref: 'master', - inputs: { - "run-id": `${{ github.run_id }}`, - "stage": "${{ env.STAGE }}", - } - }) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index caa10dd9b8..332ae69ee7 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,7 +5,8 @@ on: pull_request: paths: - "docs/**" - - "src/**" + - "components/**" + - "islands/**" - "*.md" - ".vale.ini" - ".vale/**" @@ -27,7 +28,8 @@ jobs: files: | **/*.md **/*.mdx - src/**/*.tsx + components/**/*.astro + islands/**/*.tsx .vale.ini .vale/** @@ -37,7 +39,8 @@ jobs: with: files: | docs - src + components + islands CONTRIBUTING.md # format-code: diff --git a/.gitignore b/.gitignore index f0e4f6138d..0f84644033 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,10 @@ /node_modules # Production -/build +/dist +/.blume # Generated files -.docusaurus .cache-loader # Editor config diff --git a/AGENTS.md b/AGENTS.md index 641aad5279..7df5374b5a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,10 +2,11 @@ ## Build/Test Commands -- `npm run build` - Build the Docusaurus site +- `npm run build` - Build the Blume site - `npm run start` - Start development server -- `npm run typecheck` - Run TypeScript type checking +- `npm run typecheck` - Check Blume config, components, islands, and content - `npm run lint:prettier` - Format code with Prettier +- `npm run lint:prettier:check` - Check formatting without writing files - `npm run lint:vale` - Run Vale documentation linting - `npm test` - Run all tests with Vitest - `npm run test:watch` - Run tests in watch mode @@ -23,7 +24,8 @@ ## Project Structure -- Components in `src/components/` with feature-based organization -- Utilities in `src/lib/` and `src/hooks/` +- Astro components in `components/` +- React islands in `islands/` - Documentation content in `docs/` using MDX format +- Navigation metadata in colocated `meta.ts` files - Scripts for automation in `scripts/` directory diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 669e995120..fcffc2e42b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,10 +5,8 @@ This guide provides all the information needed to set up, build, and contribute ## Overview -The documentation project relies on the [Docusaurus](https://docusaurus.io/) framework to transform `MDX` files into an actual static website. MDX allows us to embed React components in the content, unlocking rich, interactive documentation experiences. - -That being said, there are several things that are added on top of the Docusaurus utilities in order to adjust the tooling to our needs. -Those are presented throughout this document. +The documentation site uses [Blume](https://useblume.dev/) to build Markdown and MDX into a static website. +Blume provides file-based navigation, local search, OpenAPI references, and built-in documentation components. ## How to run the project @@ -16,14 +14,14 @@ Those are presented throughout this document. To work with the documentation project locally, ensure you have the following tools installed: -- [Node.js](https://nodejs.org/en/download/) (version 18 or higher) +- [Node.js](https://nodejs.org/en/download/) 22.12 or newer ### Setup Steps -1. Install the dependencies: +1. Install dependencies: ```bash -npm install +npm ci ``` 2. Start the development server: @@ -32,39 +30,33 @@ npm install npm run start ``` +Vercel deploys previews and production from this repository. Production sets the public origin from Vercel's deployment environment; set `DOCS_PUBLIC_ORIGIN` only when a non-Vercel build needs canonical URLs and a sitemap. + ## Project Structure -The two main directories where you will work are: +The main directories are: -- `docs`: This is where the actual content sits. All the `.mdx` files are located here. -- `src`: This is where you will find the React components and the custom logic used in the website's functionality. +- `docs`: Documentation content and colocated `meta.ts` navigation files. +- `components`: Astro components registered for use in MDX. +- `islands`: Interactive React components. +- `openapi`: CDI and FDI OpenAPI specifications. +- `public`: Static assets. Below is a breakdown of the main directories and files in the project: ``` -├── docs # The actual documentation pages -│   ├── _templates # Templates that can be used as a starting point for new docs -│   ├── _blocks # Reusable MDX blocks -│   └── [section-name] -│   └── _category_.json # Info about how the folder will be shown in the left sidebar -├── src # The business logic of the website -│   ├── components -│   ├── context -│   ├── css -│   ├── hooks -│   ├── lib -│   ├── plugins # Plugins used by docusaurus during the build process -│   └── theme # Docusaurus components that get adjusted by us +├── docs # Documentation pages and meta.ts navigation +├── components # Astro MDX components +├── islands # Interactive React components +├── openapi # CDI and FDI specifications +├── public # Static assets ├── scripts -├── sidebars.ts -└── docusaurus.config.ts +└── blume.config.ts ``` ### Routing -The project uses file based routing so it's pretty straightforward to determine the actual path of a page. -Each subfolder has a `_category_.json` file that specifies the name of the sidebar category and the order of the pages inside that category. -Additionally, each MDX file has a `sidebar_position` property that specifies the order of the page inside the sidebar category. +The project uses file-based routing. Use a folder's `meta.ts` to configure category navigation and `sidebar.order` in page frontmatter to order pages. #### Where to place a new page @@ -192,8 +184,11 @@ For install instructions check the [guide](https://docs.docker.com/get-docker/). Use the following commands to perform linting checks on the entire project: -- `npm run lint:prettier`: Runs prettier on the `ts` files. +- `npm run lint:prettier`: Formats supported files with Prettier. +- `npm run lint:prettier:check`: Checks formatting without changing files. - `npm run lint:vale`: Runs Vale on Markdown files and high-signal typo rules on TSX files. +- `npm run validate`: Runs strict navigation and link validation. +- `npm run build`: Regenerates the route manifest and builds the site. #### Validating code blocks diff --git a/blume.config.ts b/blume.config.ts new file mode 100644 index 0000000000..4cf3e21e4c --- /dev/null +++ b/blume.config.ts @@ -0,0 +1,82 @@ +import { defineConfig } from "blume"; + +import { openApiRedirects } from "./scripts/blume/openapi-redirects"; + +const publicOrigin = process.env.DOCS_PUBLIC_ORIGIN; +const sdkReferenceRedirects = [ + { + from: "/references/backend-sdks/supertokens-nodejs", + to: "/references/backend-sdks/supertokens-nodejs/package", + }, + { + from: "/references/frontend-sdks/supertokens-auth-react", + to: "/references/frontend-sdks/supertokens-auth-react/package", + }, +] as const; + +export default defineConfig({ + title: "SuperTokens Docs", + description: "Open Source User Authentication", + logo: { + image: { + light: "/img/logos/supertokens-dark.svg", + dark: "/img/logos/supertokens-light.svg", + alt: "SuperTokens", + }, + text: "", + href: "https://supertokens.com", + }, + github: { + owner: "supertokens", + repo: "docs", + branch: "master", + }, + theme: { + accent: "#ff9933", + mode: "system", + fonts: { + mono: "ibm-plex-mono", + }, + }, + navigation: { + repo: false, + sidebar: { + display: "group", + }, + tabs: [ + { label: "Documentation", path: "/" }, + { label: "References", path: "/references" }, + ], + featured: [ + { label: "Dashboard", href: "https://supertokens.com/dashboard", icon: "layout-dashboard" }, + { label: "GitHub", href: "https://github.com/supertokens/supertokens-core", icon: "github" }, + ], + }, + markdown: { + codeBlocks: { + theme: { + light: "one-dark-pro", + dark: "one-dark-pro", + }, + }, + }, + search: { + provider: "orama", + }, + ai: { + llmsTxt: true, + }, + openapi: { + enabled: true, + sources: [ + { label: "Core Driver Interface", route: "/references/cdi", spec: "./openapi/cdi.yml" }, + { label: "Frontend Driver Interface", route: "/references/fdi", spec: "./openapi/fdi.yml" }, + ], + }, + redirects: [...sdkReferenceRedirects, ...openApiRedirects], + deployment: { + base: "/docs", + output: "static", + ...(publicOrigin ? { site: publicOrigin } : {}), + }, +}); diff --git a/components.ts b/components.ts new file mode 100644 index 0000000000..70fadb5ea1 --- /dev/null +++ b/components.ts @@ -0,0 +1,21 @@ +import { defineComponents } from "blume"; + +import ConditionalContent from "./components/ConditionalContent.astro"; +import ContextCondition from "./components/ContextCondition.astro"; +import NextjsRouterTypeSelect from "./components/NextjsRouterTypeSelect.astro"; +import PasswordlessRecipeForm from "./components/PasswordlessRecipeForm.astro"; +import TenantTypeSwitch from "./components/TenantTypeSwitch.astro"; +import UITypeSwitch from "./components/UITypeSwitch.astro"; +import VariantContent from "./components/VariantContent.astro"; + +export default defineComponents({ + mdx: { + ConditionalContent, + ContextCondition, + NextjsRouterTypeSelect, + PasswordlessRecipeForm, + TenantTypeSwitch, + UITypeSwitch, + VariantContent, + }, +}); diff --git a/components/ConditionalContent.astro b/components/ConditionalContent.astro new file mode 100644 index 0000000000..6b758c40a1 --- /dev/null +++ b/components/ConditionalContent.astro @@ -0,0 +1,15 @@ +--- +import VariantContent from "./VariantContent.astro"; + +interface Props { + propertyName: string; + condition: string; +} + +const { propertyName, condition } = Astro.props; +const storageKey = propertyName === "nextjsRouterType" ? "nextjs-router-type" : propertyName; +--- + + + + diff --git a/components/ContextCondition.astro b/components/ContextCondition.astro new file mode 100644 index 0000000000..f254d1e3e7 --- /dev/null +++ b/components/ContextCondition.astro @@ -0,0 +1,19 @@ +--- +import VariantContent from "./VariantContent.astro"; + +interface Props { + condition: Record; +} + +const { condition } = Astro.props; +const [propertyName, value] = Object.entries(condition)[0] || []; +const storageKeys: Record = { + "recipes.passwordless.contactMethod": "passwordless-contact-method", + "recipes.passwordless.flowType": "passwordless-flow-type", +}; +const storageKey = storageKeys[propertyName] || propertyName; +--- + + + + diff --git a/components/NextjsRouterTypeSelect.astro b/components/NextjsRouterTypeSelect.astro new file mode 100644 index 0000000000..59082ba146 --- /dev/null +++ b/components/NextjsRouterTypeSelect.astro @@ -0,0 +1,10 @@ +--- +import VariantSwitch from "./VariantSwitch.astro"; +--- + + diff --git a/components/PasswordlessRecipeForm.astro b/components/PasswordlessRecipeForm.astro new file mode 100644 index 0000000000..1dc6cab18b --- /dev/null +++ b/components/PasswordlessRecipeForm.astro @@ -0,0 +1,34 @@ +--- +import VariantSwitch from "./VariantSwitch.astro"; +--- + +
+ + +
+ + diff --git a/components/TenantTypeSwitch.astro b/components/TenantTypeSwitch.astro new file mode 100644 index 0000000000..bda96145a3 --- /dev/null +++ b/components/TenantTypeSwitch.astro @@ -0,0 +1,10 @@ +--- +import VariantSwitch from "./VariantSwitch.astro"; +--- + + diff --git a/components/UITypeSwitch.astro b/components/UITypeSwitch.astro new file mode 100644 index 0000000000..1166069020 --- /dev/null +++ b/components/UITypeSwitch.astro @@ -0,0 +1,10 @@ +--- +import VariantSwitch from "./VariantSwitch.astro"; +--- + + diff --git a/components/VariantContent.astro b/components/VariantContent.astro new file mode 100644 index 0000000000..2c10d8713e --- /dev/null +++ b/components/VariantContent.astro @@ -0,0 +1,45 @@ +--- +interface Props { + storageKey: string; + value: string; +} + +const { storageKey, value } = Astro.props; +--- + +
+ +
+ + diff --git a/components/VariantSwitch.astro b/components/VariantSwitch.astro new file mode 100644 index 0000000000..ed5f0832db --- /dev/null +++ b/components/VariantSwitch.astro @@ -0,0 +1,62 @@ +--- +interface Option { + label: string; + value: string; +} + +interface Props { + storageKey: string; + options: Option[]; + defaultValue: string; + label: string; +} + +const { storageKey, options, defaultValue, label } = Astro.props; +--- + + + + + + diff --git a/docs/_blocks/oauth-tokens-callout.mdx b/docs/_blocks/oauth-tokens-callout.mdx deleted file mode 100644 index a2626b2e61..0000000000 --- a/docs/_blocks/oauth-tokens-callout.mdx +++ /dev/null @@ -1,6 +0,0 @@ - -:::caution -This guide only applies to scenarios which involve **SuperTokens Session Access Tokens**. - -If you are implementing either, [**Unified Login**](/docs/authentication/unified-login/introduction) or [**Microservice Authentication**](/docs/authentication/m2m/introduction), features that make use of **OAuth2 Access Tokens**, please check the [separate page](/docs/authentication/unified-login/verify-tokens) that shows you how to verify those types of tokens. -::: diff --git a/docs/_blocks/react-router-callout.mdx b/docs/_blocks/react-router-callout.mdx deleted file mode 100644 index 06e0a538cc..0000000000 --- a/docs/_blocks/react-router-callout.mdx +++ /dev/null @@ -1,37 +0,0 @@ - -:::important -If you are using `useRoutes`, `createBrowserRouter` or have routes defined in a different file, you need to adjust the code sample. -Please see [this issue](https://github.com/supertokens/supertokens-auth-react/issues/581#issuecomment-1246998493) for further details. -```tsx -import React from 'react'; - -import { BrowserRouter, useRoutes } from "react-router-dom"; -import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; -import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; -import * as reactRouterDom from "react-router-dom"; - -function AppRoutes() { - const authRoutes = getSuperTokensRoutesForReactRouterDom( - reactRouterDom, - [/* Add your UI recipes here e.g. EmailPasswordPrebuiltUI, PasswordlessPrebuiltUI, ThirdPartyPrebuiltUI */] - ); - - const routes = useRoutes([ - ...authRoutes.map(route => route.props), - // Include the rest of your app routes - ]); - - return routes; -} - -function App() { - return ( - - - - - - ); -} -``` -::: diff --git a/docs/_templates/api-reference.md b/docs/_templates/api-reference.md index 362d8ed93a..14c863da09 100644 --- a/docs/_templates/api-reference.md +++ b/docs/_templates/api-reference.md @@ -1,4 +1,6 @@ -# API reference template +--- +title: API reference template +--- > The following template is taken from [The Good Docs Project](https://www.thegooddocsproject.dev/template/api-reference) > Some adjustments/clarifications have been made in the context of the **SuperTokens** docs. diff --git a/docs/_templates/how-to-guide.md b/docs/_templates/how-to-guide.md index 5142843b72..9ea4fce5a6 100644 --- a/docs/_templates/how-to-guide.md +++ b/docs/_templates/how-to-guide.md @@ -1,4 +1,6 @@ -# Title +--- +title: Title +--- > The following template is taken from [The Good Docs Project](https://thegooddocsproject.dev/) > Some adjustments/clarifications have been made in the context of the **SuperTokens** docs. diff --git a/docs/_templates/tutorial.md b/docs/_templates/tutorial.md index 920710d916..f1a441d407 100644 --- a/docs/_templates/tutorial.md +++ b/docs/_templates/tutorial.md @@ -1,4 +1,6 @@ -# Title +--- +title: Title +--- > The following template is taken from [The Good Docs Project](https://www.thegooddocsproject.dev/template/tutorial) > Some adjustments/clarifications have been made in the context of the **SuperTokens** docs. diff --git a/docs/additional-verification/_category_.json b/docs/additional-verification/_category_.json deleted file mode 100644 index a8f67b091a..0000000000 --- a/docs/additional-verification/_category_.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "label": "Additional Verification", - "collapsible": true, - "collapsed": true, - "customProps": { - "isMainCategory": true - }, - "position": 4 -} diff --git a/docs/additional-verification/attack-protection-suite/_blocks/anomaly-detection-request.mdx b/docs/additional-verification/attack-protection-suite/_blocks/anomaly-detection-request.mdx deleted file mode 100644 index 2067471253..0000000000 --- a/docs/additional-verification/attack-protection-suite/_blocks/anomaly-detection-request.mdx +++ /dev/null @@ -1,352 +0,0 @@ - - - - Checks for suspicious activity and potential security threats during authentication events. - - - **Authorization**: Set the `Authorization` header to `Bearer ` where `` is your SuperTokens Attack Protection Suite API key. - - - - - -

Request

- -

Body Schema

- -| Name | Type | Description | Required | -| ------------ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | -| `email` | `string` | User's email address. If omitted (along with `phoneNumber`), the system skips impossible travel detection, new device detection, and device count detection. | No | -| `phoneNumber` | `string` | User's phone number. If omitted (along with email), the system skips impossible travel detection, new device detection, and device count detection. | No | -| `passwordHash` | `string` | First 5 characters of the `SHA-1` hash of the password. If omitted, the system skips the password breach check. | No | -| `requestId` | `string` | Frontend-generated request ID. If omitted, the system skips bot detection, impossible travel detection, new device detection, device count detection, and request ID info. | No | -| `actionType` | `ActionType` | Type of authentication action performed | No | -| `bruteForce` | `array` of `BruteForceCheck` | Configuration for brute force detection | No | - -

Action type

- -Action type is a string that can have one of the following values: - -- `emailpassword-sign-in`: Email password sign in attempt -- `emailpassword-sign-up`: Email password sign up attempt -- `send-password-reset-email`: Password reset email request -- `passwordless-send-email`: Passwordless email code/link -- `passwordless-send-sms`: Passwordless SMS code -- `totp-verify-device`: TOTP device verification -- `totp-verify-totp`: TOTP code verification -- `thirdparty-login`: Third-party provider login -- `emailverification-send-email`: Email verification request - -

Brute force check

- -| Name | Type | Description | Required | -| ----------- | ----------------------- | ------------------------------------------------------------------ | -------- | -| `key` | `string` | Unique identifier for rate limiting (for example, email, phone number, IP) | Yes | -| `maxRequests` | `array` of `MaxRequest` | Rate limit rules | Yes | - -

Max request

- -| Name | Type | Description | Required | -| ----------------- | -------- | ---------------------------------- | -------- | -| `limit` | `number` | Maximum number of requests allowed | Yes | -| `perTimeIntervalMS` | `number` | Time window in milliseconds | Yes | - - -

Example

- -```bash -curl --location --request POST 'https://security-us-east-1.aws.supertokens.io/v1/security' \ - --header 'Authorization: Bearer ' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "email": "user@email.com", - "phoneNumber": "+1234567890", - "passwordHash": "9cf95dacd226dcf43da376cdb6cbba7035218920", - "requestId": "some-request-id", - "actionType": "emailpassword-sign-in", - "bruteForce": [ - { - "key": "some-key", - "maxRequests": [ - { - "limit": 1, - "perTimeIntervalMS": 1000 - } - ] - } - ] -}' -``` - -Additional examples that show specific use cases: - -```tsx -const userIp = "127.0.0.1"; // this should be the user's IP address -const userEmail = "user@email.com"; // this should be the user's email - -// Useful for limiting a user's attempt fom the same network -// This is the most common use case -// --- -// This does two check: -// 1. 1 request per second - fast rate of requests -// 2. 100 requests per 60 minutes - slow brute force - some attackers might try sidestepping the regular brute force detection by using a slower rate of requests -const checkUserInSameNetwork = [ - { - key: `${userIp}-${userEmail}`, - maxRequests: [ - { - limit: 1, - perTimeIntervalMS: 1000, - }, - { - limit: 100, - perTimeIntervalMS: 60 * 1000 * 60, - }, - ], - }, -]; - -``` - -```tsx -const userIp = "127.0.0.1"; // this should be the user's IP address - -// Useful for limiting requests from the same network -// This should usually have a higher number of requests/time interval allowed -const checkNetwork = [ - { - key: `${userIp}`, - maxRequests: [ - { - limit: 100, - perTimeIntervalMS: 1000, - }, - ], - }, -]; - -``` - -```tsx -const userEmail = "user@email.com"; // this should be the user's email - -// Useful for limiting requests for the user only -const checkUserOnly = [ - { - key: `${userEmail}`, - maxRequests: [ - { - limit: 1, - perTimeIntervalMS: 1000, - }, - ], - }, -]; - -``` - -```tsx -const userIp = "127.0.0.1"; // this should be the user's IP address -const userEmail = "user@email.com"; // this should be the user's email - -// Checking by multiple keys at once -const checkUserOnly = [ - { - key: `${userEmail}-${userIp}`, - maxRequests: [ - { - limit: 1, - perTimeIntervalMS: 1000, - }, - { - limit: 100, - perTimeIntervalMS: 60 * 1000 * 60, - }, - ], - }, - { - key: `${userIp}`, - maxRequests: [ - { - limit: 100, - perTimeIntervalMS: 1000, - }, - ], - }, -]; - -``` - -

Response

- -

200

- -Returns the anomaly detection results. - -

Response schema

- -| Name | Type | Description | -| ---------------------------- | --------- | -------------------------------------------------------------------------- | -| `id` | `string` | Unique identifier for the anomaly detection check | -| `bruteForce` | `object` | Brute force detection results | -| `emailRisk` | `object` | Email risk assessment results | -| `phoneNumberRisk` | `object` | Phone number risk assessment results | -| `passwordBreaches` | `object` | Password breach check results | -| `isNewDevice` | `boolean` | Whether this is a new device for the user | -| `isImpossibleTravel` | `boolean` | Whether the system detects impossible travel | -| `numberOfUniqueDevicesForUser` | `number` | Number of unique devices used by the user | -| `requestIdInfo` | `object` | Information about the request including Virtual Private Network (VPN) detection, bot detection, etc. | - -

Example

- -```ts -{ - id: "0191bc35-d527-7bbd-88df-1e7669e82cc0", // the id of the anomaly detection check - bruteForce: { - detected: true, - key: "some-key", // this will be present only if brute force has been detected and the value will be the key for which the brute force detection has been detected - }, - emailRisk: null, - phoneNumberRisk: null, - passwordBreaches: { - c1d808e04732adf679965ccc34ca7ae3441: "120", // the suffix of the password hash and the number of times it has been breached - "7acba4f54f55aafc33bb06bbbf6ca803e9a": "399", // the suffix of the password hash and the number of times it has been breached - }, // can be null if the password hash is not provided - isNewDevice: false, // can be null if the email or phone number is not provided - isImpossibleTravel: false, // can be null if the email or phone number is not provided - numberOfUniqueDevicesForUser: 1, // can be null if the email or phone number is not provided - /* - All the values below can be null based on the request ID provided and what has been detected - */ - requestIdInfo: { - // can be null if the request ID is not provided - vpn: { - result: true, // this is true if the user is using a VPN - methods: { - publicVPN: true, // this is true if the user is using a public VPN - osMismatch: false, - auxiliaryMobile: false, - timezoneMismatch: true, - }, - originCountry: "unknown", - originTimezone: "Europe/Bucharest", - }, - frida: false, - proxy: false, // this is true if the user is using a proxy - valid: true, - ipInfo: { - v4: { - asn: { asn: "16509", name: "AMAZON-02", network: "127.0.0.1/13" }, - address: "127.0.0.1", - datacenter: { name: "Amazon AWS", result: true }, - geolocation: { - city: { name: "Frankfurt am Main" }, - country: { code: "DE", name: "Germany" }, - latitude: 51.1187, - timezone: "Europe/Berlin", - continent: { code: "EU", name: "Europe" }, - longitude: 9.6842, - postalCode: "12345", - subdivisions: [{ name: "Hesse", isoCode: "HE" }], - accuracyRadius: 200, - }, - }, - v6: null, // contains same information as v4 if the user is using IPv6 - }, - velocity: { - events: { intervals: { "1h": 3, "5m": 3, "24h": 5 } }, - distinctIp: { intervals: { "1h": 1, "5m": 1, "24h": 1 } }, - distinctCountry: { intervals: { "1h": 1, "5m": 1, "24h": 1 } }, - distinctLinkedId: { intervals: null }, - }, - clonedApp: false, - incognito: false, - tampering: { result: false, anomalyScore: 0 }, - isEmulator: false, - isUsingTor: false, // this is true if the user is using Tor - jailbroken: false, - botDetected: false, // this is true if the user is a bot - ipBlocklist: { - result: false, - details: { emailSpam: false, attackSource: false }, - }, - factoryReset: { time: "1970-01-01T00:00:00Z", timestamp: 0 }, - highActivity: false, - remoteControl: false, - identification: { - tag: { environmentId: "cddd8855-ff50-4bbe-bb82-62b5057fa4f4" }, // this is the environment ID that you will receive from the SuperTokens team - url: "http://example.com/index.html?eid=cddd8855-ff50-4bbe-bb82-62b5057fa4f4", // this is the URL that has been used to generate the request ID - linkedId: null, - timeInMS: 1723130887458, - incognito: false, - requestId: "1723130887451.92r32x", // this is the request ID that has been generated on the frontend - visitorId: "mEYaqlY67Z55cHgzt37y", - confidence: { score: 1 }, - browserDetails: { - os: "Mac OS X", - device: "Other", - osVersion: "10.15.7", - userAgent: - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", - browserName: "Chrome", - browserFullVersion: "127.0.0", - browserMajorVersion: "127", - }, - }, - virtualMachine: false, - privacySettings: false, - locationSpoofing: false, - rawDeviceAttributes: { - // These are the raw device attributes that are being sent from the frontend - // They might vary based on the device and browser that is being used - audio: { value: 124.04346607114712 }, - fonts: { - value: ["Arial Unicode MS", "Gill Sans", "Helvetica Neue", "Menlo"], - }, - canvas: { - value: { - Text: "32a115bd05e0f411c5ecd7e285fd36e2", - Winding: true, - Geometry: "d45e7d71dc99e368affd8a40840c833d", - }, - }, - contrast: { value: 0 }, - cpuClass: {}, - colorDepth: { value: 124.04346607114712 }, - colorGamut: { value: "p3" }, - architecture: { value: 127 }, - cookiesEnabled: { value: true }, - }, - }, -}; -``` - -

400

- -The request was invalid. - -

Example

- -```json -{ - "error": "Invalid request body" -} -``` - -

401

- -Invalid or missing API key. - -

Example

- -```json -{ - "error": "Unauthorized" -} -``` - -

500

- -An internal server error occurred. - -
diff --git a/docs/additional-verification/attack-protection-suite/_category_.json b/docs/additional-verification/attack-protection-suite/_category_.json deleted file mode 100644 index 3f9e570e05..0000000000 --- a/docs/additional-verification/attack-protection-suite/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Attack Protection Suite", - "position": 3 -} diff --git a/docs/additional-verification/attack-protection-suite/initial-setup.mdx b/docs/additional-verification/attack-protection-suite/initial-setup.mdx index 8d7cc3d101..abd6617e24 100644 --- a/docs/additional-verification/attack-protection-suite/initial-setup.mdx +++ b/docs/additional-verification/attack-protection-suite/initial-setup.mdx @@ -1,18 +1,10 @@ --- -sidebar_position: 2 title: Initial setup -toc_max_heading_level: 4 -hide_title: true description: Set up Attack Protection Suite in your **SuperTokens** integration -page_type: guide -category: attack-protection-suite +sidebar: + order: 2 --- - -import AnomalyDetectionRequest from "./_blocks/anomaly-detection-request.mdx"; - -# Initial setup - ## Overview The following page shows you how to include the **Attack Protection Suite** feature in your **SuperTokens** integration. @@ -42,7 +34,7 @@ For social or enterprise login, it is not needed for multiple reasons: The **Attack Protection Suite** feature relies on identifying each request through a unique ID. This way the fingerprinting process can determine if it's a potential threat or not. -:::info Important +:::info[Important] This step applies only to bot detection and anomaly IP-based detection such as impossible travel detection. Also, check for bot detection only on the email password login flows. ::: @@ -55,7 +47,6 @@ This SDK generates a unique request ID for each authentication event attempt. ```tsx const ENVIRONMENT_ID = ""; // Your environment ID that you received from the SuperTokens team // Initialize the agent on page load using your public API key that you received from the SuperTokens team. -// @ts-expect-error const supertokensRequestIdPromise = import("https://deviceid.supertokens.io/PqWNQ35Ydhm6WDUK/k9bwGCuvuA83Ad6s?apiKey=") .then((RequestId: any) => RequestId.load({ endpoint: [ @@ -79,7 +70,7 @@ async function getRequestId() { Include the `requestId` property along with the value as part of the `preAPIHook` body from the initialisation of the recipes. -:::info Important +:::info[Important] If the request ID is not passed to the backend, the anomaly detection can only detect password breaches and brute force attacks. ::: @@ -87,12 +78,11 @@ Below is a full example of how to configure the SDK and pass the request ID to t The request ID generates only for the email password sign in, sign up, and reset password actions because these are the only actions that require bot detection. For all the other recipes, this is not needed. -```tsx +```tsx {34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51} import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; const ENVIRONMENT_ID = ""; // Your environment ID that you received from the SuperTokens team // Initialize the agent on page load using your public API key that you received from the SuperTokens team. -// @ts-expect-error const supertokensRequestIdPromise = import("https://deviceid.supertokens.io/PqWNQ35Ydhm6WDUK/k9bwGCuvuA83Ad6s?apiKey=") .then((RequestId: any) => RequestId.load({ endpoint: [ @@ -122,7 +112,6 @@ export const SuperTokensConfig = { // use from SuperTokens. See the full list here: https://supertokens.com/docs/guides recipeList: [ EmailPassword.init({ - // highlight-start preAPIHook: async (context) => { let url = context.url; let requestInit = context.requestInit; @@ -141,7 +130,6 @@ export const SuperTokensConfig = { requestInit, url }; } - // highlight-end }), ], }; @@ -153,11 +141,11 @@ To retrieve the request ID in the backend you have to override the recipe implem #### Email and password - + - + -```tsx +```tsx {48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -205,7 +193,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start override: { apis: (originalImplementation) => { return { @@ -293,7 +280,6 @@ SuperTokens.init({ }; }, }, - // highlight-end }), ], }); @@ -301,9 +287,9 @@ SuperTokens.init({ ``` - + - + ```go @@ -528,11 +514,11 @@ func main() { } ``` - + - + -```python +```python {38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,165,166,167} from typing import Dict, Any, Union, List from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailpassword @@ -570,7 +556,6 @@ def get_brute_force_config( ] -# highlight-start def override_email_password_apis(original_implementation: APIInterface): original_sign_up_post = original_implementation.sign_up_post @@ -692,36 +677,32 @@ def override_email_password_apis(original_implementation: APIInterface): return original_implementation -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( - # highlight-start override=emailpassword.InputOverrideConfig( apis=override_email_password_apis ) - # highlight-end ) ], ) ``` - + - + #### Passwordless - + - + -```tsx +```tsx {41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85} import SuperTokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; import axios from "axios"; @@ -755,16 +736,13 @@ const getBruteForceConfig = ( userIdentifier: string, ]; SuperTokens.init({ - // @ts-ignore framework: "...", - // @ts-ignore appInfo: { /*...*/ }, recipeList: [ Passwordless.init({ // ... other customisations ... - // highlight-start contactMethod: "EMAIL_OR_PHONE", flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", override: { @@ -810,16 +788,15 @@ SuperTokens.init({ }; }, }, - // highlight-end }), ], }); ``` - + - + ```go import ( @@ -941,11 +918,11 @@ func main() { ``` - + - + -```python +```python {39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,131,132,133} from typing import Dict, Any, Union, List from supertokens_python import init, InputAppInfo from supertokens_python.recipe import passwordless @@ -955,7 +932,6 @@ from supertokens_python.framework import BaseRequest from supertokens_python.recipe.session import SessionContainer - def get_ip_from_request(req: BaseRequest) -> str: forwarded_for = req.get_header("x-forwarded-for") if forwarded_for: @@ -984,7 +960,6 @@ def get_brute_force_config( ] -# highlight-start def override_passwordless_apis(original_implementation: APIInterface): original_create_code_post = original_implementation.create_code_post @@ -1070,19 +1045,14 @@ def override_passwordless_apis(original_implementation: APIInterface): return original_implementation -# highlight-end - - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ passwordless.init( - # highlight-start flow_type="USER_INPUT_CODE_AND_MAGIC_LINK", contact_config=passwordless.ContactEmailOrPhoneConfig(), override=passwordless.InputOverrideConfig(apis=override_passwordless_apis), - # highlight-end ) ], ) @@ -1090,9 +1060,9 @@ init( ``` - + - + ### 3. Call the protection service @@ -1102,8 +1072,8 @@ To use the service, send requests to the appropriate regional endpoint based on - **EU Region (Ireland)**: `https://security-eu-west-1.aws.supertokens.io/v1/security` - **APAC Region (Singapore)**: `https://security-ap-southeast-1.aws.SuperTokens.io/v1/security` - - + + ```bash curl --location --request POST 'https://security-us-east-1.aws.supertokens.io/v1/security' \ @@ -1129,8 +1099,8 @@ curl --location --request POST 'https://security-us-east-1.aws.supertokens.io/v1 }' ``` - - + + ```tsx const REGION = "us-east-1"; // or "eu-west-1" or "ap-southeast-1" @@ -1170,8 +1140,8 @@ fetch(url, { .catch(err => console.error(err)); ``` - - + + ```python import requests @@ -1208,8 +1178,8 @@ response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` - - + + ```go import ( @@ -1263,12 +1233,361 @@ func main() { } ``` - - - - - + + + + + Checks for suspicious activity and potential security threats during authentication events. + + + **Authorization**: Set the `Authorization` header to `Bearer ` where `` is your SuperTokens Attack Protection Suite API key. + + + + + +## Request + +### Body Schema + +| Name | Type | Description | Required | +| ------------ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | +| `email` | `string` | User's email address. If omitted (along with `phoneNumber`), the system skips impossible travel detection, new device detection, and device count detection. | No | +| `phoneNumber` | `string` | User's phone number. If omitted (along with email), the system skips impossible travel detection, new device detection, and device count detection. | No | +| `passwordHash` | `string` | First 5 characters of the `SHA-1` hash of the password. If omitted, the system skips the password breach check. | No | +| `requestId` | `string` | Frontend-generated request ID. If omitted, the system skips bot detection, impossible travel detection, new device detection, device count detection, and request ID info. | No | +| `actionType` | `ActionType` | Type of authentication action performed | No | +| `bruteForce` | `array` of `BruteForceCheck` | Configuration for brute force detection | No | + +#### Action type +Action type is a string that can have one of the following values: + +- `emailpassword-sign-in`: Email password sign in attempt +- `emailpassword-sign-up`: Email password sign up attempt +- `send-password-reset-email`: Password reset email request +- `passwordless-send-email`: Passwordless email code/link +- `passwordless-send-sms`: Passwordless SMS code +- `totp-verify-device`: TOTP device verification +- `totp-verify-totp`: TOTP code verification +- `thirdparty-login`: Third-party provider login +- `emailverification-send-email`: Email verification request + +#### Brute force check + +| Name | Type | Description | Required | +| ----------- | ----------------------- | ------------------------------------------------------------------ | -------- | +| `key` | `string` | Unique identifier for rate limiting (for example, email, phone number, IP) | Yes | +| `maxRequests` | `array` of `MaxRequest` | Rate limit rules | Yes | + +#### Max request + +| Name | Type | Description | Required | +| ----------------- | -------- | ---------------------------------- | -------- | +| `limit` | `number` | Maximum number of requests allowed | Yes | +| `perTimeIntervalMS` | `number` | Time window in milliseconds | Yes | + + +### Example + +```bash +curl --location --request POST 'https://security-us-east-1.aws.supertokens.io/v1/security' \ + --header 'Authorization: Bearer ' \ + --header 'Content-Type: application/json' \ + --data-raw '{ + "email": "user@email.com", + "phoneNumber": "+1234567890", + "passwordHash": "9cf95dacd226dcf43da376cdb6cbba7035218920", + "requestId": "some-request-id", + "actionType": "emailpassword-sign-in", + "bruteForce": [ + { + "key": "some-key", + "maxRequests": [ + { + "limit": 1, + "perTimeIntervalMS": 1000 + } + ] + } + ] +}' +``` + +Additional examples that show specific use cases: + +```tsx +const userIp = "127.0.0.1"; // this should be the user's IP address +const userEmail = "user@email.com"; // this should be the user's email + +// Useful for limiting a user's attempt fom the same network +// This is the most common use case +// --- +// This does two check: +// 1. 1 request per second - fast rate of requests +// 2. 100 requests per 60 minutes - slow brute force - some attackers might try sidestepping the regular brute force detection by using a slower rate of requests +const checkUserInSameNetwork = [ + { + key: `${userIp}-${userEmail}`, + maxRequests: [ + { + limit: 1, + perTimeIntervalMS: 1000, + }, + { + limit: 100, + perTimeIntervalMS: 60 * 1000 * 60, + }, + ], + }, +]; + +``` + +```tsx +const userIp = "127.0.0.1"; // this should be the user's IP address + +// Useful for limiting requests from the same network +// This should usually have a higher number of requests/time interval allowed +const checkNetwork = [ + { + key: `${userIp}`, + maxRequests: [ + { + limit: 100, + perTimeIntervalMS: 1000, + }, + ], + }, +]; + +``` + +```tsx +const userEmail = "user@email.com"; // this should be the user's email + +// Useful for limiting requests for the user only +const checkUserOnly = [ + { + key: `${userEmail}`, + maxRequests: [ + { + limit: 1, + perTimeIntervalMS: 1000, + }, + ], + }, +]; + +``` + +```tsx +const userIp = "127.0.0.1"; // this should be the user's IP address +const userEmail = "user@email.com"; // this should be the user's email + +// Checking by multiple keys at once +const checkUserOnly = [ + { + key: `${userEmail}-${userIp}`, + maxRequests: [ + { + limit: 1, + perTimeIntervalMS: 1000, + }, + { + limit: 100, + perTimeIntervalMS: 60 * 1000 * 60, + }, + ], + }, + { + key: `${userIp}`, + maxRequests: [ + { + limit: 100, + perTimeIntervalMS: 1000, + }, + ], + }, +]; + +``` + +## Response + +### 200 + +Returns the anomaly detection results. + +#### Response schema + +| Name | Type | Description | +| ---------------------------- | --------- | -------------------------------------------------------------------------- | +| `id` | `string` | Unique identifier for the anomaly detection check | +| `bruteForce` | `object` | Brute force detection results | +| `emailRisk` | `object` | Email risk assessment results | +| `phoneNumberRisk` | `object` | Phone number risk assessment results | +| `passwordBreaches` | `object` | Password breach check results | +| `isNewDevice` | `boolean` | Whether this is a new device for the user | +| `isImpossibleTravel` | `boolean` | Whether the system detects impossible travel | +| `numberOfUniqueDevicesForUser` | `number` | Number of unique devices used by the user | +| `requestIdInfo` | `object` | Information about the request including Virtual Private Network (VPN) detection, bot detection, etc. | + +#### Example + +```ts +{ + id: "0191bc35-d527-7bbd-88df-1e7669e82cc0", // the id of the anomaly detection check + bruteForce: { + detected: true, + key: "some-key", // this will be present only if brute force has been detected and the value will be the key for which the brute force detection has been detected + }, + emailRisk: null, + phoneNumberRisk: null, + passwordBreaches: { + c1d808e04732adf679965ccc34ca7ae3441: "120", // the suffix of the password hash and the number of times it has been breached + "7acba4f54f55aafc33bb06bbbf6ca803e9a": "399", // the suffix of the password hash and the number of times it has been breached + }, // can be null if the password hash is not provided + isNewDevice: false, // can be null if the email or phone number is not provided + isImpossibleTravel: false, // can be null if the email or phone number is not provided + numberOfUniqueDevicesForUser: 1, // can be null if the email or phone number is not provided + /* + All the values below can be null based on the request ID provided and what has been detected + */ + requestIdInfo: { + // can be null if the request ID is not provided + vpn: { + result: true, // this is true if the user is using a VPN + methods: { + publicVPN: true, // this is true if the user is using a public VPN + osMismatch: false, + auxiliaryMobile: false, + timezoneMismatch: true, + }, + originCountry: "unknown", + originTimezone: "Europe/Bucharest", + }, + frida: false, + proxy: false, // this is true if the user is using a proxy + valid: true, + ipInfo: { + v4: { + asn: { asn: "16509", name: "AMAZON-02", network: "127.0.0.1/13" }, + address: "127.0.0.1", + datacenter: { name: "Amazon AWS", result: true }, + geolocation: { + city: { name: "Frankfurt am Main" }, + country: { code: "DE", name: "Germany" }, + latitude: 51.1187, + timezone: "Europe/Berlin", + continent: { code: "EU", name: "Europe" }, + longitude: 9.6842, + postalCode: "12345", + subdivisions: [{ name: "Hesse", isoCode: "HE" }], + accuracyRadius: 200, + }, + }, + v6: null, // contains same information as v4 if the user is using IPv6 + }, + velocity: { + events: { intervals: { "1h": 3, "5m": 3, "24h": 5 } }, + distinctIp: { intervals: { "1h": 1, "5m": 1, "24h": 1 } }, + distinctCountry: { intervals: { "1h": 1, "5m": 1, "24h": 1 } }, + distinctLinkedId: { intervals: null }, + }, + clonedApp: false, + incognito: false, + tampering: { result: false, anomalyScore: 0 }, + isEmulator: false, + isUsingTor: false, // this is true if the user is using Tor + jailbroken: false, + botDetected: false, // this is true if the user is a bot + ipBlocklist: { + result: false, + details: { emailSpam: false, attackSource: false }, + }, + factoryReset: { time: "1970-01-01T00:00:00Z", timestamp: 0 }, + highActivity: false, + remoteControl: false, + identification: { + tag: { environmentId: "cddd8855-ff50-4bbe-bb82-62b5057fa4f4" }, // this is the environment ID that you will receive from the SuperTokens team + url: "http://example.com/index.html?eid=cddd8855-ff50-4bbe-bb82-62b5057fa4f4", // this is the URL that has been used to generate the request ID + linkedId: null, + timeInMS: 1723130887458, + incognito: false, + requestId: "1723130887451.92r32x", // this is the request ID that has been generated on the frontend + visitorId: "mEYaqlY67Z55cHgzt37y", + confidence: { score: 1 }, + browserDetails: { + os: "Mac OS X", + device: "Other", + osVersion: "10.15.7", + userAgent: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", + browserName: "Chrome", + browserFullVersion: "127.0.0", + browserMajorVersion: "127", + }, + }, + virtualMachine: false, + privacySettings: false, + locationSpoofing: false, + rawDeviceAttributes: { + // These are the raw device attributes that are being sent from the frontend + // They might vary based on the device and browser that is being used + audio: { value: 124.04346607114712 }, + fonts: { + value: ["Arial Unicode MS", "Gill Sans", "Helvetica Neue", "Menlo"], + }, + canvas: { + value: { + Text: "32a115bd05e0f411c5ecd7e285fd36e2", + Winding: true, + Geometry: "d45e7d71dc99e368affd8a40840c833d", + }, + }, + contrast: { value: 0 }, + cpuClass: {}, + colorDepth: { value: 124.04346607114712 }, + colorGamut: { value: "p3" }, + architecture: { value: 127 }, + cookiesEnabled: { value: true }, + }, + }, +}; +``` + +### 400 + +The request was invalid. + +#### Example + +```json +{ + "error": "Invalid request body" +} +``` + +### 401 + +Invalid or missing API key. + +#### Example + +```json +{ + "error": "Unauthorized" +} +``` + +### 500 + +An internal server error occurred. + + + + ## Examples @@ -1277,11 +1596,11 @@ Use the following examples for complete code references on how to integrate the ### Email and password - + - + -```tsx +```tsx {164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -1445,7 +1764,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start override: { apis: (originalImplementation) => { return { @@ -1573,7 +1891,6 @@ SuperTokens.init({ }; }, }, - // highlight-end }), ], }); @@ -1593,9 +1910,9 @@ The above code overrides the SuperTokens APIs and adding custom logic for anomal - If the request is permissible, it calls the original implementation of the API. - We return the response from the original implementation of the API. - + - + ```go @@ -2025,11 +2342,11 @@ The above code overrides the SuperTokens APIs and adding custom logic for anomal - If the request is permissible, it calls the original implementation of the API. - We return the response from the original implementation of the API. - + - + -```python +```python {112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,312,313,314} from httpx import AsyncClient from hashlib import sha1 from typing import Dict, Any, Union, List @@ -2079,7 +2396,7 @@ async def handle_security_checks( "Authorization": f"Bearer {SECRET_API_KEY}", "Content-Type": "application/json", }, - ) # type: ignore + ) response_data = response.json() except: # silently fail in order to not break the auth flow @@ -2141,7 +2458,6 @@ def get_brute_force_config( ] -# highlight-start def override_email_password_apis(original_implementation: APIInterface): original_sign_up_post = original_implementation.sign_up_post @@ -2336,18 +2652,14 @@ def override_email_password_apis(original_implementation: APIInterface): return original_implementation -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( - # highlight-start override=emailpassword.InputOverrideConfig( apis=override_email_password_apis ) - # highlight-end ) ], ) @@ -2367,17 +2679,17 @@ The above code overrides the SuperTokens APIs and adding custom logic for anomal - If the request is permissible, it calls the original implementation of the API. - We return the response from the original implementation of the API. - + - + ### Passwordless - + - + -```tsx +```tsx {108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172} import SuperTokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; import axios from "axios"; @@ -2478,16 +2790,13 @@ const getBruteForceConfig = ( ]; SuperTokens.init({ - // @ts-ignore framework: "...", - // @ts-ignore appInfo: { /*...*/ }, recipeList: [ Passwordless.init({ // ... other customisations ... - // highlight-start contactMethod: "EMAIL_OR_PHONE", flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", override: { @@ -2553,7 +2862,6 @@ SuperTokens.init({ }; }, }, - // highlight-end }), ], }); @@ -2572,9 +2880,9 @@ The above code overrides the SuperTokens APIs and adding custom logic for anomal - If the request passes the allowed criteria, the original implementation of the API executes. - We return the response from the original implementation of the API. - + - + ```go import ( @@ -2799,11 +3107,11 @@ The above code overrides the SuperTokens APIs and adding custom logic for anomal - We return the response from the original implementation of the API. - + - + -```python +```python {82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,195,196,197} from httpx import AsyncClient from typing import Dict, Any, Union, List from supertokens_python import init, InputAppInfo @@ -2843,7 +3151,7 @@ async def handle_security_checks( "Authorization": f"Bearer {SECRET_API_KEY}", "Content-Type": "application/json", }, - ) # type: ignore + ) response_data = response.json() except: # silently fail in order to not break the auth flow @@ -2885,7 +3193,6 @@ def get_brute_force_config( ] -# highlight-start def override_passwordless_apis(original_implementation: APIInterface): original_create_code_post = original_implementation.create_code_post @@ -2992,19 +3299,14 @@ def override_passwordless_apis(original_implementation: APIInterface): return original_implementation -# highlight-end - - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ passwordless.init( - # highlight-start flow_type="USER_INPUT_CODE_AND_MAGIC_LINK", contact_config=passwordless.ContactEmailOrPhoneConfig(), override=passwordless.InputOverrideConfig(apis=override_passwordless_apis), - # highlight-end ) ], ) @@ -3023,7 +3325,6 @@ The above code overrides the SuperTokens APIs and adding custom logic for anomal - If the request passes the allowed criteria, the original implementation of the API executes. - We return the response from the original implementation of the API. - - - + + diff --git a/docs/additional-verification/attack-protection-suite/introduction.mdx b/docs/additional-verification/attack-protection-suite/introduction.mdx index 3fee223bf9..900702db8f 100644 --- a/docs/additional-verification/attack-protection-suite/introduction.mdx +++ b/docs/additional-verification/attack-protection-suite/introduction.mdx @@ -1,28 +1,24 @@ --- -sidebar_position: 1 title: Introduction -hide_title: true description: Enhance application security with automatic threat detection SuperTokens -page_type: overview -category: attack-protection-suite +sidebar: + order: 1 --- -# Introduction - ## Overview The **Attack Protection Suite** feature identifies and prevents suspicious activities in authentication sessions. It leverages detection methods to enhance the security of your application. -:::info Important +:::info[Important] This feature is **in beta** and not enabled by default. -Check the [quickstart guide](/docs/additional-verification/attack-protection-suite/initial-setup) for instructions on how to set it up. +Check the [quickstart guide](/additional-verification/attack-protection-suite/initial-setup) for instructions on how to set it up. ::: The feature processes requests and provides risk assessments. You can use these assessments to enforce additional security measures, such as requiring two-factor authentication for suspicious logins or blocking high-risk attempts altogether. Check the next diagram for a high-level overview of how the feature's flow works. -Attack Protection Suite flow +Attack Protection Suite flow ### Features @@ -47,11 +43,8 @@ Check the next diagram for a high-level overview of how the feature's flow works ## Getting started -To learn how to use the feature in your application open the [quickstart guide](/docs/additional-verification/attack-protection-suite/initial-setup). +To learn how to use the feature in your application open the [quickstart guide](/additional-verification/attack-protection-suite/initial-setup). -:::info -Use the feature only with either the `Email Password` or `Passwordless` authentication recipes. +:::info[Use the feature only with either the `Email Password` or `Passwordless` authentication recipes.] For social or enterprise login, it is not needed. ::: - - diff --git a/docs/additional-verification/attack-protection-suite/meta.ts b/docs/additional-verification/attack-protection-suite/meta.ts new file mode 100644 index 0000000000..79430d0075 --- /dev/null +++ b/docs/additional-verification/attack-protection-suite/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Attack Protection Suite", + "icon": "shield-plus", + "order": 3 +}); diff --git a/docs/additional-verification/captcha.mdx b/docs/additional-verification/captcha.mdx index ceef31bfd2..a32bd45f08 100644 --- a/docs/additional-verification/captcha.mdx +++ b/docs/additional-verification/captcha.mdx @@ -1,14 +1,11 @@ --- -sidebar_position: 6 title: CAPTCHA -hide_title: true description: Use the plugin to add CAPTCHA to your authentication flow. -page_type: tutorial +sidebar: + badge: New + order: 6 --- - -# CAPTCHA validation - ## Overview This following tutorial shows you how to add CAPTCHA validation to your authentication flows. @@ -28,7 +25,7 @@ You can use the plugin with the following CAPTCHA providers: Make sure to have the appropriate provider keys before starting the tutorial. The implementation is in early stages and APIs might change. -For more information on how plugins work refer to the [references page](/docs/references/plugins/introduction). +For more information on how plugins work refer to the [references page](/references/plugins/introduction). ## Steps @@ -105,8 +102,8 @@ SuperTokens.init({ }); ``` -:::info no-title -If you are using a captcha input that renders an input on the frontend, you will have to [disable the use of shadow DOM](/docs/references/frontend-sdks/prebuilt-ui/shadow-dom) when you initialize the SDK. +:::info +If you are using a captcha input that renders an input on the frontend, you will have to [disable the use of shadow DOM](/references/frontend-sdks/prebuilt-ui/shadow-dom) when you initialize the SDK. ::: ### 3. Customize the plugin @@ -235,33 +232,16 @@ SuperTokens.init({ Besides CAPTCHA validation you can also look into the **Attack Protection Suite** feature which provides prevention against suspicious authentication attempts. - - - - Attack Protection Suite - - - Prevent suspicious authentication attempts. - - - - - - Multi-factor Authentication - - - Add multi-factor authentication to your authentication flows. - - - - - - Plugins Reference - - - General information on how plugins work. - - - + + +Prevent suspicious authentication attempts. + + +Add multi-factor authentication to your authentication flows. + + +General information on how plugins work. + + diff --git a/docs/additional-verification/email-verification/_category_.json b/docs/additional-verification/email-verification/_category_.json deleted file mode 100644 index dc9e532a6f..0000000000 --- a/docs/additional-verification/email-verification/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Email Verification", - "position": 2 -} diff --git a/docs/additional-verification/email-verification/changing-style.mdx b/docs/additional-verification/email-verification/changing-style.mdx index cf657fa504..96b56c08b7 100644 --- a/docs/additional-verification/email-verification/changing-style.mdx +++ b/docs/additional-verification/email-verification/changing-style.mdx @@ -1,16 +1,10 @@ --- title: Customize the pre-built UI -hide_title: true -sidebar_position: 7 description: Update SuperTokens component styles using CSS for customized UI appearance. -page_type: guide -recipe: emailverification -category: email-verification +sidebar: + order: 7 --- - -# Customize the pre-built UI - ## Overview Updating the CSS allows you to change the UI of the components to meet your needs. @@ -26,13 +20,13 @@ This guide is only relevant if you are using the **pre-built UI** components. If ## Global style changes Each stylable component contains the `data-supertokens` attribute (in this example `data-supertokens="link"`). -For more information on how to find a specific selector look over the [changing style page](/docs/references/frontend-sdks/prebuilt-ui/changing-style). +For more information on how to find a specific selector look over the [changing style page](/references/frontend-sdks/prebuilt-ui/changing-style). Let's add a `border` to the `link` elements. The syntax for styling is plain CSS. - - + + -```tsx preview="/img/emailverification/resend-with-border.png" previewAlt="Prebuilt form with custom submit button" +```tsx {13,14,15,16,17,18,19,20} import SuperTokens from "supertokens-auth-react"; import EmailVerification from "supertokens-auth-react/recipe/emailverification"; import Session from "supertokens-auth-react/recipe/session"; @@ -45,7 +39,6 @@ SuperTokens.init({ }, recipeList: [ EmailVerification.init({ - // highlight-start style: ` [data-supertokens~=link] { border: 2px solid #0076ff; @@ -54,20 +47,17 @@ SuperTokens.init({ margin: 0 auto; } `, - // highlight-end }), Session.init() ] }); ``` - + - + -```tsx +```tsx {10,11,12,13,14,15,16,17} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailVerification from "supertokens-auth-react-script/recipe/emailverification"; supertokensUIInit({ appInfo: { apiDomain: "...", @@ -76,7 +66,6 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailVerification.init({ - // highlight-start style: ` [data-supertokens~=link] { border: 2px solid #0076ff; @@ -85,24 +74,23 @@ supertokensUIInit({ margin: 0 auto; } `, - // highlight-end }) ] }); ``` - + - + ### Change fonts By default, SuperTokens uses the `Arial` font. The best way to override this is to add a `font-family` styling to the `container` component in the recipe configuration. - - + + -```tsx +```tsx {13,14,15,16,17} import SuperTokens from "supertokens-auth-react"; import EmailVerification from "supertokens-auth-react/recipe/emailverification"; import Session from "supertokens-auth-react/recipe/session"; @@ -115,25 +103,21 @@ SuperTokens.init({ }, recipeList: [ EmailVerification.init({ - // highlight-start style: ` [data-supertokens~=container] { font-family: cursive } ` - // highlight-end }), Session.init() ] }); ``` - - + + -```tsx +```tsx {10,11,12,13,14} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailVerification from "supertokens-auth-react-script/recipe/emailverification"; supertokensUIInit({ appInfo: { apiDomain: "...", @@ -142,29 +126,27 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailVerification.init({ - // highlight-start style: ` [data-supertokens~=container] { font-family: cursive } ` - // highlight-end }), ] }); ``` - - + + ### Use media queries You may want to have different CSS for different `viewports`. You can achieve this via media queries like this: - - + + -```tsx +```tsx {22,23,24,25,26} import SuperTokens from "supertokens-auth-react"; import EmailVerification from "supertokens-auth-react/recipe/emailverification"; @@ -186,25 +168,21 @@ SuperTokens.init({ margin: 0 auto; } - // highlight-start @media (max-width: 440px) { [data-supertokens~=link] { width: 90%; } } - // highlight-end `, }), ], }); ``` - - + + -```tsx +```tsx {20,21,22,23,24} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailVerification from "supertokens-auth-react-script/recipe/emailverification"; supertokensUIInit({ appInfo: { apiDomain: "...", @@ -223,20 +201,18 @@ supertokensUIInit({ margin: 0 auto; } - // highlight-start @media (max-width: 440px) { [data-supertokens~=link] { width: 90%; } } - // highlight-end `, }), ], }); ``` - - + + ## Customize individual screens @@ -244,10 +220,10 @@ supertokensUIInit({ This screen is where the system redirects the user if you set `mode` to `REQUIRED` and they visit a path that requires a verified email. - - + + -```tsx +```tsx {13,14,15} import SuperTokens from "supertokens-auth-react"; import EmailVerification from "supertokens-auth-react/recipe/emailverification"; import Session from "supertokens-auth-react/recipe/session"; @@ -260,23 +236,19 @@ SuperTokens.init({ }, recipeList: [ EmailVerification.init({ - // highlight-start sendVerifyEmailScreen: { style: ` ... ` } - // highlight-end }), Session.init() ] }); ``` - - + + -```tsx +```tsx {11,12,13} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailVerification from "supertokens-auth-react-script/recipe/emailverification"; supertokensUIInit({ appInfo: { @@ -286,26 +258,24 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailVerification.init({ - // highlight-start sendVerifyEmailScreen: { style: ` ... ` } - // highlight-end }) ] }); ``` - - + + ### Verify link clicked screen This is the screen shown to users that click the email verification link in the email. - - + + -```tsx +```tsx {13,14,15} import SuperTokens from "supertokens-auth-react"; import EmailVerification from "supertokens-auth-react/recipe/emailverification"; import Session from "supertokens-auth-react/recipe/session"; @@ -318,24 +288,20 @@ SuperTokens.init({ }, recipeList: [ EmailVerification.init({ - // highlight-start verifyEmailLinkClickedScreen: { style: ` ... `, } - // highlight-end }), Session.init() ] }); ``` - + - + -```tsx +```tsx {11,12,13} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailVerification from "supertokens-auth-react-script/recipe/emailverification"; supertokensUIInit({ appInfo: { @@ -345,28 +311,26 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailVerification.init({ - // highlight-start verifyEmailLinkClickedScreen: { style: ` ... `, } - // highlight-end }) ] }); ``` - - + + --- ## See also - - - - - - - - + + + + + + + + diff --git a/docs/additional-verification/email-verification/embed-in-page.mdx b/docs/additional-verification/email-verification/embed-in-page.mdx index bd64ff053b..8fd4366311 100644 --- a/docs/additional-verification/email-verification/embed-in-page.mdx +++ b/docs/additional-verification/email-verification/embed-in-page.mdx @@ -1,17 +1,10 @@ --- title: Embed the UI in a page -hide_title: true -toc_max_heading_level: 4 -sidebar_position: 5 description: Embed the email verification UI in a different page. -page_type: guide -recipe: emailverification -category: email-verification +sidebar: + order: 5 --- - -# Embed in a page - ## Overview If you are looking to render the email verification UI in a different page follow this guide. @@ -26,14 +19,13 @@ If you are working with a **custom UI** you need to update the backend configura ### 1. Disable the default implementation -:::note no-title -If you are using a **custom UI** implementation, then you can skip this step. +:::note[If you are using a **custom UI** implementation, then you can skip this step.] ::: - - + + -```tsx +```tsx {13} import SuperTokens from "supertokens-auth-react"; import EmailVerification from "supertokens-auth-react/recipe/emailverification"; @@ -46,9 +38,7 @@ SuperTokens.init({ recipeList: [ EmailVerification.init({ mode: "REQUIRED", - // highlight-start disableDefaultUI: true - // highlight-end }), ] }); @@ -56,14 +46,12 @@ SuperTokens.init({ If you navigate to `/auth/verify-email`, you should not see the widget anymore. - + - + -```tsx +```tsx {12} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailVerification from "supertokens-auth-react-script/recipe/emailverification"; supertokensUIInit({ appInfo: { @@ -74,9 +62,7 @@ supertokensUIInit({ recipeList: [ supertokensUIEmailVerification.init({ mode: "REQUIRED", - // highlight-start disableDefaultUI: true - // highlight-end }), ] }); @@ -84,22 +70,20 @@ supertokensUIInit({ If you navigate to `/auth/verify-email`, you should not see the widget anymore. - - + + ### 2. Render the component yourself -:::note no-title -If you are using a **custom UI** implementation, then you can skip this step. +:::note[If you are using a **custom UI** implementation, then you can skip this step.] ::: - - + + Add the `EmailVerification` component in your app: -```tsx -// highlight-next-line +```tsx {1,8} import React from "react"; import { EmailVerification } from 'supertokens-auth-react/recipe/emailverification/prebuiltui'; @@ -107,26 +91,24 @@ class EmailVerificationPage extends React.Component { render() { return (
- // highlight-next-line
) } } ``` -
+ - + -:::caution -You have to build your own UI instead. +:::warning[You have to build your own UI instead.] ::: - -
+ + -### 3. Change the website path for the email verification UI {{optional}} +### 3. Change the website path for the email verification UI (optional) The default path for this is component is `/{websiteBasePath}/verify-email`. @@ -134,10 +116,10 @@ If you are displaying this at some custom path, then you need add additional con #### 3.1 Update the backend configuration - - + + -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33} import SuperTokens from "supertokens-node"; import EmailVerification from "supertokens-node/recipe/emailverification"; @@ -153,7 +135,6 @@ SuperTokens.init({ recipeList: [ EmailVerification.init({ mode: "OPTIONAL", - // highlight-start emailDelivery: { override: (originalImplementation) => { return { @@ -162,7 +143,7 @@ SuperTokens.init({ return originalImplementation.sendEmail({ ...input, emailVerifyLink: input.emailVerifyLink.replace( - // This is: `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/verify-email` + // This is: `/auth/verify-email` "http://localhost:3000/auth/verify-email", "http://localhost:3000/your/path" ) @@ -172,15 +153,14 @@ SuperTokens.init({ } } } - // highlight-end }) ] }); ``` - - + + -```go +```go {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30} import ( "strings" @@ -195,13 +175,12 @@ func main() { RecipeList: []supertokens.Recipe{ emailverification.Init(evmodels.TypeInput{ Mode: evmodels.ModeOptional, - // highlight-start EmailDelivery: &emaildelivery.TypeInput{ Override: func(originalImplementation emaildelivery.EmailDeliveryInterface) emaildelivery.EmailDeliveryInterface { ogSendEmail := *originalImplementation.SendEmail (*originalImplementation.SendEmail) = func(input emaildelivery.EmailType, userContext supertokens.UserContext) error { - // This is: `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/verify-email` + // This is: `/auth/verify-email` input.EmailVerification.EmailVerifyLink = strings.Replace( input.EmailVerification.EmailVerifyLink, "http://localhost:3000/auth/verify-email", @@ -212,16 +191,15 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {11,12,13,14,15,16,17,30} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailverification from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConfig @@ -232,15 +210,13 @@ from typing import Dict, Any def custom_email_delivery(original_implementation: EmailDeliveryOverrideInput) -> EmailDeliveryOverrideInput: original_send_email = original_implementation.send_email - # highlight-start async def send_email(template_vars: EmailTemplateVars, user_context: Dict[str, Any]) -> None: - # This is: `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/verify-email` + # This is: `/auth/verify-email` template_vars.email_verify_link = template_vars.email_verify_link.replace( "http://localhost:3000/auth/verify-email", "http://localhost:3000/your/path") return await original_send_email(template_vars, user_context) - # highlight-end original_implementation.send_email = send_email return original_implementation @@ -249,29 +225,27 @@ def custom_email_delivery(original_implementation: EmailDeliveryOverrideInput) - init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailverification.init( mode="OPTIONAL", - # highlight-next-line email_delivery=EmailDeliveryConfig(override=custom_email_delivery)) ] ) ``` - - + + #### 3.2 Update the frontend configuration -:::note no-title -If you are using a **custom UI** implementation, then you can skip this step. +:::note[If you are using a **custom UI** implementation, then you can skip this step.] ::: - - + + -```tsx +```tsx {13,14,15,16,17,18,19} import SuperTokens from "supertokens-auth-react"; import EmailVerification from "supertokens-auth-react/recipe/emailverification"; @@ -284,7 +258,6 @@ SuperTokens.init({ recipeList: [ EmailVerification.init({ mode: "REQUIRED", - //highlight-start // The user will be taken to the custom path when they need to get their email verified. getRedirectionURL: async (context) => { @@ -292,19 +265,16 @@ SuperTokens.init({ return "/custom-email-verification-path"; }; } - //highlight-end }) ] }) ``` - + - + -```tsx +```tsx {12,13,14,15,16,17,18} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailVerification from "supertokens-auth-react-script/recipe/emailverification"; supertokensUIInit({ appInfo: { @@ -315,7 +285,6 @@ supertokensUIInit({ recipeList: [ supertokensUIEmailVerification.init({ mode: "REQUIRED", - //highlight-start // The user will be taken to the custom path when they need to get their email verified. getRedirectionURL: async (context) => { @@ -323,10 +292,9 @@ supertokensUIInit({ return "/custom-email-verification-path"; }; } - //highlight-end }) ] }) ``` - - + + diff --git a/docs/additional-verification/email-verification/hooks-and-overrides.mdx b/docs/additional-verification/email-verification/hooks-and-overrides.mdx index 64aff97eba..39bb01ae88 100644 --- a/docs/additional-verification/email-verification/hooks-and-overrides.mdx +++ b/docs/additional-verification/email-verification/hooks-and-overrides.mdx @@ -1,23 +1,14 @@ --- title: Hooks and overrides -hide_title: true -sidebar_position: 7 -description: >- - Add custom logic in the email verification flow by overriding the SuperTokens - APIs. -page_type: guide -recipe: emailverification -category: email-verification +description: Add custom logic in the email verification flow by overriding the SuperTokens APIs. +sidebar: + order: 7 --- - -# Hooks and overrides - - **SuperTokens** exposes a set of constructs that allow you to trigger different actions during the authentication lifecycle or to even fully customize the logic based on your use case. The following sections describe how you can modify adjust the `emailverification` recipe to your needs. -Explore the [references pages](/docs/references) for a more in depth guide on hooks and overrides. +Explore the [references pages](/references) for a more in depth guide on hooks and overrides. ## Backend override @@ -25,10 +16,10 @@ Explore the [references pages](/docs/references) for a more in depth guide on ho To perform any task post email verification like analytics, sending a user a welcome email or notifying an internal dashboard, you need to override the `verifyEmailPOST` API. - - + + -```tsx +```tsx {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36} import SuperTokens from 'supertokens-node'; import EmailVerification from "supertokens-node/recipe/emailverification"; import Session from "supertokens-node/recipe/session"; @@ -42,7 +33,6 @@ SuperTokens.init({ recipeList: [ EmailVerification.init({ mode: "REQUIRED", - // highlight-start override: { apis: (originalImplementation) => { return { @@ -66,16 +56,15 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init() ] }); ``` - - + + -```go +```go {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36} import ( "fmt" @@ -90,7 +79,6 @@ func main() { RecipeList: []supertokens.Recipe{ emailverification.Init(evmodels.TypeInput{ Mode: evmodels.ModeRequired, - // highlight-start Override: &evmodels.OverrideStruct{ APIs: func(originalImplementation evmodels.APIInterface) evmodels.APIInterface { ogVerifyEmailPOST := *originalImplementation.VerifyEmailPOST @@ -113,23 +101,21 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,34,35,36} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailverification from supertokens_python.recipe.emailverification.interfaces import APIInterface, APIOptions, EmailVerifyPostOkResult from typing import Dict, Any, Optional from supertokens_python.recipe.session.interfaces import SessionContainer -# highlight-start def override_email_verification_apis(original_implementation_email_verification: APIInterface): original_email_verify_post = original_implementation_email_verification.email_verify_post @@ -149,24 +135,21 @@ def override_email_verification_apis(original_implementation_email_verification: original_implementation_email_verification.email_verify_post = email_verify_post return original_implementation_email_verification -# highlight-end init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailverification.init( mode="REQUIRED", - # highlight-start override=emailverification.InputOverrideConfig( apis=override_email_verification_apis ) - # highlight-end ) ] ) ``` - - + + diff --git a/docs/additional-verification/email-verification/initial-setup.mdx b/docs/additional-verification/email-verification/initial-setup.mdx index b84b797ce7..091c7ed7cb 100644 --- a/docs/additional-verification/email-verification/initial-setup.mdx +++ b/docs/additional-verification/email-verification/initial-setup.mdx @@ -1,19 +1,10 @@ --- title: Initial Setup -hide_title: true -toc_max_heading_level: 4 -sidebar_position: 2 -description: >- - Enable email verification to ensure user authenticity and protect application - routes. -page_type: tutorial -recipe: emailverification -category: email-verification +description: Enable email verification to ensure user authenticity and protect application routes. +sidebar: + order: 2 --- -# Enable email verification - - ## Overview Email verification needs to be explicitly configured to work in your **SuperTokens** integration. @@ -24,12 +15,12 @@ The functionality offers two ways to set it up: ## Before you start - +:::info[Access token guidance] -If you are implementing [**Unified Login**](/docs/authentication/unified-login/introduction) you must manually check the `email_verified` claim on the **OAuth2 Access Tokens**. -Please read the [separate page](/docs/authentication/unified-login/verify-tokens) that shows you how to verify the token. +If you are implementing [**Unified Login**](/authentication/unified-login/introduction) you must manually check the `email_verified` claim on the **OAuth2 Access Tokens**. +Please read the [separate page](/authentication/unified-login/verify-tokens) that shows you how to verify the token. - +::: For passwordless login, with email, a user's email is automatically marked as verified when they login. Therefore, this flow only triggers if a user changes their email during a session. @@ -38,10 +29,10 @@ Therefore, this flow only triggers if a user changes their email during a sessio ### 1. Initialize the backend recipe - - + + -```tsx +```tsx {12,13,14} import SuperTokens from "supertokens-node"; import EmailVerification from "supertokens-node/recipe/emailverification"; import Session from "supertokens-node/recipe/session"; @@ -53,20 +44,18 @@ SuperTokens.init({ websiteDomain: "...", }, recipeList: [ - // highlight-start EmailVerification.init({ mode: "REQUIRED", // or "OPTIONAL" }), - // highlight-end Session.init(), ], }); ``` - - + + -```go +```go {12,13,14} import ( "github.com/supertokens/supertokens-golang/recipe/emailverification" "github.com/supertokens/supertokens-golang/recipe/emailverification/evmodels" @@ -78,21 +67,19 @@ import ( func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ - // highlight-start emailverification.Init(evmodels.TypeInput{ Mode: evmodels.ModeRequired, // or evmodels.ModeOptional }), - // highlight-end session.Init(&sessmodels.TypeInput{}), }, }) } ``` - - + + -```python +```python {10} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session from supertokens_python.recipe import emailverification @@ -100,35 +87,32 @@ from supertokens_python.recipe import emailverification init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ - # highlight-start emailverification.init(mode='REQUIRED'), # or 'OPTIONAL' - # highlight-end session.init() ] ) ``` - - + + - + ### 2. Initialize the frontend recipe - + - + - + - - + + -```tsx +```tsx {15,16,17,29} import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; import EmailVerification from "supertokens-auth-react/recipe/emailverification"; @@ -143,11 +127,9 @@ SuperTokens.init({ websiteDomain: "...", }, recipeList: [ - // highlight-start EmailVerification.init({ mode: "REQUIRED", // or "OPTIONAL" }), - // highlight-end Session.init(), ], }); @@ -159,9 +141,7 @@ function App() {
- // highlight-start {getSuperTokensRoutesForReactRouterDom(reactRouterDOM, [/* Other pre-built UI */ EmailVerificationPreBuiltUI])} - // highlight-end // ... other routes
@@ -172,11 +152,11 @@ function App() { } ``` -
+
- + -```tsx +```tsx {14,15,16,22,23,24} import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; import EmailVerification from "supertokens-auth-react/recipe/emailverification"; @@ -190,42 +170,36 @@ SuperTokens.init({ websiteDomain: "...", }, recipeList: [ - // highlight-start EmailVerification.init({ mode: "REQUIRED", // or "OPTIONAL" }), - // highlight-end Session.init(), ], }); function App() { - // highlight-start if (canHandleRoute([/* Other pre-built UI */ EmailVerificationPreBuiltUI])) { return getRoutingComponent([/* Other pre-built UI */ EmailVerificationPreBuiltUI]) } - // highlight-end return ( {/*Your app*/} ); } ``` - + - +
- + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: This change is in your auth route configuration. -```tsx +```tsx {10,11,12} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailVerification from "supertokens-auth-react-script/recipe/emailverification"; supertokensUIInit({ appInfo: { @@ -234,18 +208,16 @@ supertokensUIInit({ websiteDomain: "...", }, recipeList: [ - // highlight-start supertokensUIEmailVerification.init({ mode: "REQUIRED", // or "OPTIONAL" }), - // highlight-end ], }); ``` This change goes in the `supertokens-web-js` SDK configuration at the root of your application: -```tsx +```tsx {11} import SuperTokens from "supertokens-web-js"; import EmailVerification from "supertokens-web-js/recipe/emailverification"; import Session from "supertokens-web-js/recipe/session"; @@ -256,20 +228,17 @@ SuperTokens.init({ appName: "...", }, recipeList: [ - // highlight-next-line EmailVerification.init(), Session.init(), ], }); ``` - + -
+ -:::important - -SuperTokens triggers verification emails by redirecting the user to the email verification path when the mode is `REQUIRED`. +:::note[SuperTokens triggers verification emails by redirecting the user to the email verification path when the mode is `REQUIRED`.] If you have set the mode to `OPTIONAL` or are **NOT** using the `SessionAuth` wrapper, you need to manually trigger the verification email. The guide on [protecting API and website routes](./protecting-routes) covers the changes that you need to make. @@ -278,22 +247,22 @@ Redirect the user to the email verification path to trigger the sending of the v This happens automatically when using the prebuilt UI and in `REQUIRED` mode. ::: -
+ - + ### 2. Initialize the frontend recipe - + - - + + - - + + -```tsx +```tsx {11,12,13,14} import SuperTokens from "supertokens-web-js"; import EmailVerification from "supertokens-web-js/recipe/emailverification"; import Session from "supertokens-web-js/recipe/session"; @@ -304,66 +273,60 @@ SuperTokens.init({ appName: "...", }, recipeList: [ - // highlight-start EmailVerification.init(), Session.init(), ], }); ``` - - + + Add the following ` + ``` Then call the `supertokensEmailVerification.init` function as shown below -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensEmailVerification from "supertokens-web-js-script/recipe/emailverification"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; +```tsx {7,8,9,10} supertokens.init({ appInfo: { apiDomain: "...", appName: "...", }, recipeList: [ - // highlight-start supertokensEmailVerification.init(), supertokensSession.init(), ], }); ``` - - + + - + - + -:::success -No specific action required here. +:::success[No specific action required here.] ::: - - + + ### 3. Send the email verification email After a user signs up, or when the email verification validators fail, you need to tell the user about the email verification process. Redirect them to a screen that informs them about the current status and call the verification API. - - + + - - + + ```tsx import { sendVerificationEmail } from "supertokens-web-js/recipe/emailverification"; @@ -390,8 +353,8 @@ async function sendEmail() { } ``` - - + + ```tsx import supertokensEmailVerification from "supertokens-web-js/recipe/emailverification"; @@ -418,20 +381,19 @@ async function sendEmail() { } ``` - - + + - + - + - Create a new screen on your app that asks the user to enter their email to receive an email. This screen should ideally link to the sign in form. Once the user has enters their email, you can call the following API to send an email verification email to that user: ```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/user/email/verify/token' \ +curl --location --request POST '/auth/user/email/verify/token' \ --header 'Authorization: Bearer ...' ``` @@ -440,18 +402,16 @@ The response body from the API call has a `status` property in it: - `status: "EMAIL_ALREADY_VERIFIED_ERROR"`: This status can return if the info about email verification in the session was outdated. Redirect the user to the home page. - `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. -:::info Multi Tenancy +:::info[Multi Tenancy] You do not need to add the tenant ID to the path here because the backend fetches the `tenantId` of the user from the session token. ::: - - - -:::note + + -The API for sending an email verification email requires an active session. If you are using the frontend SDKs, then the session tokens should automatically get attached to the request. +:::note[The API for sending an email verification email requires an active session. If you are using the frontend SDKs, then the session tokens should automatically get attached to the request.] ::: #### Change the email verification link @@ -460,10 +420,10 @@ By default, the email verification link points to the `websiteDomain` configured That would be the `/auth/verify-email` route if `/auth` is the value of `websiteBasePath`. If you want to change this to something different, follow the next example: - - + + -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33} import SuperTokens from "supertokens-node"; import EmailVerification from "supertokens-node/recipe/emailverification"; @@ -479,7 +439,6 @@ SuperTokens.init({ recipeList: [ EmailVerification.init({ mode: "OPTIONAL", - // highlight-start emailDelivery: { override: (originalImplementation) => { return { @@ -488,7 +447,7 @@ SuperTokens.init({ return originalImplementation.sendEmail({ ...input, emailVerifyLink: input.emailVerifyLink.replace( - // This is: `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/verify-email` + // This is: `/auth/verify-email` "http://localhost:3000/auth/verify-email", "http://localhost:3000/your/path" ) @@ -498,15 +457,14 @@ SuperTokens.init({ } } } - // highlight-end }) ] }); ``` - - + + -```go +```go {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30} import ( "strings" @@ -521,13 +479,12 @@ func main() { RecipeList: []supertokens.Recipe{ emailverification.Init(evmodels.TypeInput{ Mode: evmodels.ModeOptional, - // highlight-start EmailDelivery: &emaildelivery.TypeInput{ Override: func(originalImplementation emaildelivery.EmailDeliveryInterface) emaildelivery.EmailDeliveryInterface { ogSendEmail := *originalImplementation.SendEmail (*originalImplementation.SendEmail) = func(input emaildelivery.EmailType, userContext supertokens.UserContext) error { - // This is: `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/verify-email` + // This is: `/auth/verify-email` input.EmailVerification.EmailVerifyLink = strings.Replace( input.EmailVerification.EmailVerifyLink, "http://localhost:3000/auth/verify-email", @@ -538,16 +495,15 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {11,12,13,14,15,16,17,30} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailverification from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConfig @@ -558,15 +514,13 @@ from typing import Dict, Any def custom_email_delivery(original_implementation: EmailDeliveryOverrideInput) -> EmailDeliveryOverrideInput: original_send_email = original_implementation.send_email - # highlight-start async def send_email(template_vars: EmailTemplateVars, user_context: Dict[str, Any]) -> None: - # This is: `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/verify-email` + # This is: `/auth/verify-email` template_vars.email_verify_link = template_vars.email_verify_link.replace( "http://localhost:3000/auth/verify-email", "http://localhost:3000/your/path") return await original_send_email(template_vars, user_context) - # highlight-end original_implementation.send_email = send_email return original_implementation @@ -575,20 +529,19 @@ def custom_email_delivery(original_implementation: EmailDeliveryOverrideInput) - init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailverification.init( mode="OPTIONAL", - # highlight-next-line email_delivery=EmailDeliveryConfig(override=custom_email_delivery)) ] ) ``` - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] For a multi tenant setup, the input to the `sendEmail` function also contains the `tenantId`. You can use this to determine the correct value to set for the `websiteDomain` in the generated link. @@ -599,11 +552,11 @@ For a multi tenant setup, the input to the `sendEmail` function also contains th Once the user clicks the email verification link, and it opens your app, call the following function. It extracts the token and `tenantId` (if you use a multi tenant setup) from the link and calls the token verification API. - - + + - - + + ```tsx import { verifyEmail } from "supertokens-web-js/recipe/emailverification"; @@ -631,8 +584,8 @@ async function consumeVerificationCode() { } ``` - - + + ```tsx import supertokensEmailVerification from "supertokens-web-js/recipe/emailverification"; @@ -660,19 +613,18 @@ async function consumeVerificationCode() { } ``` - - + + - + - + - When the user clicks the email verification link, and it opens as a deep link into your mobile app, you can remove the token and call the verification API. ```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/user/email/verify' \ +curl --location --request POST '/auth/user/email/verify' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "method": "token", @@ -680,7 +632,7 @@ curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/user/ }' ``` -:::info Multi Tenancy +:::info[Multi Tenancy] For a multi tenancy setup, the `` value can fetch from `tenantId` query parameter from the email verification link. If it's not there in the link, you can use the value `"public"` (which is the default tenant). @@ -691,18 +643,17 @@ The response body from the API call has a `status` property in it: - `status: "EMAIL_VERIFICATION_INVALID_TOKEN_ERROR"`: This can happen if the verification code expires or is invalid. You should ask the user to retry. - `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. - - + + -:::caution -- This API doesn't require an active session to succeed. +:::warning[- This API doesn't require an active session to succeed.] - If you are calling the above API on page load, there is an edge case in which email clients might open the verification link in the email (for scanning purposes) and consume the token in the URL. This would lead to issues in which an attacker could sign up using someone else’s email and end up with a verified status! To prevent this, on page load, you should check if a session exists, and if it does, only then call the above API. If a session does not exist, you should first show a button, which when clicked would call the above API (email clients do not automatically click on this button). The button text could be something like "Click here to verify your email". ::: - + ## References @@ -711,39 +662,38 @@ The response body from the API call has a `status` property in it: This is how the email that the user receives looks like: -UI of the verification email sent to the registered user +UI of the verification email sent to the registered user You can find the [source code of this template on GitHub](https://github.com/supertokens/email-sms-templates/blob/master/email-html/email-verification.html) -To understand more about how you can customize the check the [email delivery](/docs/platform-configuration/email-delivery) section. +To understand more about how you can customize the check the [email delivery](/platform-configuration/email-delivery) section. ### Verification link lifetime By default, the email verification link's lifetime is **1 day**. This can change via a core's configuration (time in milliseconds): - - - + + + - Go to the [SuperTokens SaaS dashboard](https://supertokens.com/dashboard) and select the relevant **Managed** deployment. - Open **Configuration** and find the **Email Verification** configuration card. - Change the `email_verification_token_lifetime` value. Configuration changes are saved automatically. - - - + + + -```bash +```bash {5} # Here we set the lifetime to 2 hours. docker run \ -p 3567:3567 \ - // highlight-next-line -e EMAIL_VERIFICATION_TOKEN_LIFETIME=7200000 \ -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -752,30 +702,30 @@ docker run \ email_verification_token_lifetime: 7200000 ``` - - + + ## Next steps - - -Change the email verification status manually - - -Generate email verification links manually - - -Protect routes based on the email verification status - - -Post email verification action - - -Customize the email delivery method - - -Session claim validators - - + + + + + + + + + + + + + + + + + + + + diff --git a/docs/additional-verification/email-verification/introduction.mdx b/docs/additional-verification/email-verification/introduction.mdx index 1198e3fd6f..80b69fc269 100644 --- a/docs/additional-verification/email-verification/introduction.mdx +++ b/docs/additional-verification/email-verification/introduction.mdx @@ -1,19 +1,10 @@ --- -sidebar_position: 1 title: Introduction -hide_title: true -skip_llms_txt: true -description: >- - Use email verification to ensure user authenticity and protect application - routes. -page_type: overview -recipe: emailverification -category: email-verification +description: Use email verification to ensure user authenticity and protect application routes. +sidebar: + order: 1 --- - -# Email verification - ## Overview With the **Email Verification** recipe, you can confirm the email address of a user before they can use your application. @@ -22,48 +13,25 @@ With the **Email Verification** recipe, you can confirm the email address of a u You can go through the *Initial Setup* page for a quick tutorial on how to configure the feature. - - - - Quickstart - - - Go through a quick tutorial that shows you how to add the **Email Verification** recipe to your application. - - - + + +Go through a quick tutorial that shows you how to add the **Email Verification** recipe to your application. + + ## Customization To adjust the functionality to fit your use case you can explore different sections from the documentation. - - - - Protect frontend and backend routes - - - Limit the access to your frontend and backend routes to users who have confirmed their email address. - - - - - Manual actions - - - Generate verification links and change the email verification status manually. - - - - - Customize the pre-built UI - - - Learn how to change the look of the pre-built UI. - - - - - - + + +Limit the access to your frontend and backend routes to users who have confirmed their email address. + + +Generate verification links and change the email verification status manually. + + +Learn how to change the look of the pre-built UI. + + diff --git a/docs/additional-verification/email-verification/manual-actions.mdx b/docs/additional-verification/email-verification/manual-actions.mdx index afb29d6828..ebe84c0186 100644 --- a/docs/additional-verification/email-verification/manual-actions.mdx +++ b/docs/additional-verification/email-verification/manual-actions.mdx @@ -1,18 +1,10 @@ --- title: Manual actions -hide_title: true -sidebar_position: 4 -description: >- - See how you can directly generate email verification links and set emails as - verified through manual actions. -page_type: guide -recipe: emailverification -category: email-verification +description: See how you can directly generate email verification links and set emails as verified through manual actions. +sidebar: + order: 4 --- - -# Manual actions - ## Overview Although the **SuperTokens** covers the entire email verification process you can also intervene manually in the process. @@ -24,8 +16,8 @@ The following page shows you what SDK methods you can use to adjust the verifica You can use the backend SDK to generate the email verification link as shown below: - - + + ```tsx import EmailVerification from "supertokens-node/recipe/emailverification"; @@ -47,8 +39,8 @@ async function createEmailVerificationLink(recipeUserId: supertokens.RecipeUserI } ``` - - + + ```go import ( @@ -77,11 +69,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.emailverification.asyncio import create_email_verification_link @@ -98,8 +90,8 @@ async def create_link(recipe_user_id: RecipeUserId, email: str): else: print("user's email is already verified") ``` - - + + ```python from supertokens_python.recipe.emailverification.syncio import create_email_verification_link @@ -117,13 +109,13 @@ def create_link(recipe_user_id: RecipeUserId, email: str): print("user's email is already verified") ``` - - + + - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] Notice that the first argument to the function call above is `"public"`. This refers to the default tenant ID that SuperTokens uses. It means that users belonging to the `"public"` tenant can only consume the generated email verification link. @@ -139,8 +131,8 @@ Finally, the generated link uses the configured `websiteDomain` from the `appInf To manually mark an email as verified, you need to first create an email verification token for the user and then use the token to verify the user's email. - - + + ```tsx import EmailVerification from "supertokens-node/recipe/emailverification"; @@ -161,8 +153,8 @@ async function manuallyVerifyEmail(recipeUserId: supertokens.RecipeUserId) { } ``` - - + + ```go import ( @@ -187,11 +179,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.emailverification.asyncio import create_email_verification_token, verify_email_using_token @@ -209,8 +201,8 @@ async def manually_verify_email(recipe_user_id: RecipeUserId): except Exception as e: print(e) ``` - - + + ```python from supertokens_python.recipe.emailverification.syncio import create_email_verification_token, verify_email_using_token @@ -229,13 +221,13 @@ def manually_verify_email(recipe_user_id: RecipeUserId): print(e) ``` - - + + - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] Notice that the first argument of the function call above is `"public"`. This refers to the `"public"` `tenantId` (which is the default `tenantId`). In case you are using the multi tenancy feature, you can still pass in the `"public"` tenant ID here. Even if the user ID is not part of that tenant, you can pass it because the system creates and consumes the token in one shot. @@ -247,8 +239,8 @@ In case you are using the multi tenancy feature, you can still pass in the `"pub To manually mark an email as unverified, you need to first retrieve the user's email address and then update their email verification status in the database. - - + + ```tsx import EmailVerification from "supertokens-node/recipe/emailverification"; @@ -264,8 +256,8 @@ async function manuallyUnverifyEmail(recipeUserId: supertokens.RecipeUserId) { } ``` - - + + ```go import ( @@ -282,11 +274,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.emailverification.asyncio import unverify_email @@ -299,8 +291,8 @@ async def manually_unverify_email(recipe_user_id: RecipeUserId): print(e) ``` - - + + ```python from supertokens_python.recipe.emailverification.syncio import unverify_email @@ -313,13 +305,13 @@ def manually_unverify_email(recipe_user_id: RecipeUserId): except Exception as e: print(e) ``` - - + + - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] For a multi tenant setup, the function above does not take a tenant ID. A user ID and the associated email verification status is unique on an app level (and not a tenant level). ::: @@ -329,9 +321,9 @@ A user ID and the associated email verification status is unique on an app level ## See also - - - - - - + + + + + + diff --git a/docs/additional-verification/email-verification/meta.ts b/docs/additional-verification/email-verification/meta.ts new file mode 100644 index 0000000000..fd60b03db2 --- /dev/null +++ b/docs/additional-verification/email-verification/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Email Verification", + "icon": "mail-check", + "order": 2 +}); diff --git a/docs/additional-verification/email-verification/protecting-routes.mdx b/docs/additional-verification/email-verification/protecting-routes.mdx index 41b30f0ed4..3796331c0d 100644 --- a/docs/additional-verification/email-verification/protecting-routes.mdx +++ b/docs/additional-verification/email-verification/protecting-routes.mdx @@ -1,19 +1,10 @@ --- title: Protect frontend and backend routes -hide_title: true -sidebar_position: 2 -description: >- - Protect API and website routes by implementing email verification checks for - secure access. -page_type: guide -recipe: emailverification -category: email-verification +description: Protect API and website routes by implementing email verification checks for secure access. +sidebar: + order: 2 --- - - -# Protecting backend and frontend routes - ## Overview The `EmailVerification` claim shows the status of the email verification process. @@ -21,12 +12,12 @@ Follow this page to understand how to limit access based on whether the user has ## Before you start - +:::info[Access token guidance] -If you are implementing [**Unified Login**](/docs/authentication/unified-login/introduction), you must manually check the `email_verified` claim on the **OAuth2 Access Tokens**. -Please read the [separate page](/docs/authentication/unified-login/verify-tokens) that shows you how to verify the token. +If you are implementing [**Unified Login**](/authentication/unified-login/introduction), you must manually check the `email_verified` claim on the **OAuth2 Access Tokens**. +Please read the [separate page](/authentication/unified-login/verify-tokens) that shows you how to verify the token. - +::: --- @@ -37,10 +28,10 @@ Please read the [separate page](/docs/authentication/unified-login/verify-tokens If you want to protect all your backend API routes with email verification checks, set the `mode` to `REQUIRED` in the `EmailVerification` configuration. Routes protected with the `verifySession` middleware additionally check for email verification status. - - + + -```tsx +```tsx {12,13,14,15} import SuperTokens from 'supertokens-node'; import EmailVerification from "supertokens-node/recipe/emailverification"; import Session from "supertokens-node/recipe/session"; @@ -52,20 +43,18 @@ SuperTokens.init({ websiteDomain: "..." }, recipeList: [ - // highlight-start EmailVerification.init({ // This means that verifySession will now only allow calls if the user has verified their email mode: "REQUIRED", }), - // highlight-end Session.init() ] }); ``` - - + + -```go +```go {12,13,14,15} import ( "github.com/supertokens/supertokens-golang/recipe/emailverification" "github.com/supertokens/supertokens-golang/recipe/emailverification/evmodels" @@ -77,21 +66,19 @@ import ( func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ - // highlight-start emailverification.Init(evmodels.TypeInput{ // This means that VerifySession will now only allow calls if the user has verified their email Mode: evmodels.ModeRequired, }), - // highlight-end session.Init(&sessmodels.TypeInput{}), }, }) } ``` - - + + -```python +```python {10,11} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session from supertokens_python.recipe import emailverification @@ -99,28 +86,26 @@ from supertokens_python.recipe import emailverification init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ - # highlight-start # This means that VerifySession will now only allow calls if the user has verified their email emailverification.init(mode='REQUIRED'), - # highlight-end session.init() ] ) ``` - - + + In case you have set the email verification mode to `REQUIRED` but want to disable the check for a specific route, you can make the following changes to the `verifySession` middleware: - - - - + + + + -```tsx +```tsx {11} import { verifySession } from "supertokens-node/recipe/session/framework/express"; import express from "express"; import { SessionRequest } from "supertokens-node/framework/express"; @@ -131,7 +116,6 @@ let app = express(); app.post( "/update-blog", verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => globalValidators.filter(v => v.id !== EmailVerificationClaim.key), }), async (req: SessionRequest, res) => { @@ -139,10 +123,10 @@ app.post( } ); ``` - - + + -```tsx +```tsx {15} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import {SessionRequest} from "supertokens-node/framework/hapi"; @@ -157,7 +141,6 @@ server.route({ pre: [ { method: verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => globalValidators.filter(v => v.id !== EmailVerificationClaim.key), }), }, @@ -168,10 +151,10 @@ server.route({ } }) ``` - - + + -```tsx +```tsx {10} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import { SessionRequest } from "supertokens-node/framework/fastify"; @@ -181,7 +164,6 @@ let fastify = Fastify(); fastify.post("/update-blog", { preHandler: verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => globalValidators.filter(v => v.id !== EmailVerificationClaim.key), }), }, async (req: SessionRequest, res) => { @@ -189,10 +171,10 @@ fastify.post("/update-blog", { }); ``` - - + + -```tsx +```tsx {10} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification"; @@ -202,15 +184,14 @@ async function updateBlog(awsEvent: SessionEvent) { }; exports.handler = verifySession(updateBlog, { - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => globalValidators.filter(v => v.id !== EmailVerificationClaim.key) }); ``` - - + + -```tsx +```tsx {9} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import {SessionContext} from "supertokens-node/framework/koa"; @@ -219,17 +200,16 @@ import { EmailVerificationClaim } from "supertokens-node/recipe/emailverificatio let router = new KoaRouter(); router.post("/update-blog", verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => globalValidators.filter(v => v.id !== EmailVerificationClaim.key) }), async (ctx: SessionContext, next) => { // All validator checks have passed and the user has a verified email address }); ``` - - + + -```tsx +```tsx {11} import { inject, intercept } from "@loopback/core"; import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; @@ -240,7 +220,6 @@ class SetRole { constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { } @post("/update-blog") @intercept(verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => globalValidators.filter(v => v.id !== EmailVerificationClaim.key) })) @response(200) @@ -250,27 +229,25 @@ class SetRole { } ``` - - + + + - - + -```tsx +```tsx {6,7,8,9,10,11,12,13,14,15,16,17} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification"; -// highlight-start export default async function setRole(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { await verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => globalValidators.filter(v => v.id !== EmailVerificationClaim.key) })(req, res, next); }, @@ -284,12 +261,11 @@ export default async function setRole(req: SessionRequest, res: any) { -```tsx +```tsx {18} import SuperTokens from "supertokens-node"; import { NextResponse, NextRequest } from "next/server"; import { withSession } from "supertokens-node/nextjs"; import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -303,7 +279,6 @@ export async function POST(request: NextRequest) { return NextResponse.json({}); }, { - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => globalValidators.filter(v => v.id !== EmailVerificationClaim.key) } ); @@ -312,13 +287,12 @@ export async function POST(request: NextRequest) { - - + + -```tsx +```tsx {10} import { Controller, Post, UseGuards, Request, Response, Session } from "@nestjs/common"; import { SessionContainer, SessionClaimValidator } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification"; @@ -326,7 +300,6 @@ import { EmailVerificationClaim } from "supertokens-node/recipe/emailverificatio export class ExampleController { @Post('example') @UseGuards(new AuthGuard({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators: SessionClaimValidator[]) => globalValidators.filter(v => v.id !== EmailVerificationClaim.key) })) async postExample(@Session() session: SessionContainer): Promise { @@ -335,15 +308,15 @@ export class ExampleController { } } ``` - + - - - - - + + + + + -```go +```go {14,15,16,17,18,19,20,21,22,23,24} import ( "net/http" @@ -357,7 +330,6 @@ import ( func main() { _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { filtered := []claims.SessionClaimValidator{} for _, v := range globalClaimValidators { @@ -369,7 +341,6 @@ func main() { } return filtered, nil }, - // highlight-end }, exampleAPI).ServeHTTP(rw, r) }) } @@ -379,10 +350,10 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + -```go +```go {17,18,19,20,21,22,23,24,25,26,27} import ( "net/http" @@ -399,7 +370,6 @@ func main() { // Wrap the API handler in session.VerifySession router.POST("/likecomment", verifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { filtered := []claims.SessionClaimValidator{} for _, v := range globalClaimValidators { @@ -411,7 +381,6 @@ func main() { } return filtered, nil }, - // highlight-end }), exampleAPI) } @@ -433,10 +402,10 @@ func exampleAPI(c *gin.Context) { } ``` - - + + -```go +```go {17,18,19,20,21,22,23,24,25,26,27} import ( "net/http" @@ -453,7 +422,6 @@ func main() { // Wrap the API handler in session.VerifySession r.Post("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { filtered := []claims.SessionClaimValidator{} for _, v := range globalClaimValidators { @@ -465,7 +433,6 @@ func main() { } return filtered, nil }, - // highlight-end }, exampleAPI)) } @@ -475,10 +442,10 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { ``` - - + + -```go +```go {17,18,19,20,21,22,23,24,25,26,27} import ( "net/http" @@ -495,7 +462,6 @@ func main() { // Wrap the API handler in session.VerifySession router.HandleFunc("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { filtered := []claims.SessionClaimValidator{} for _, v := range globalClaimValidators { @@ -507,7 +473,6 @@ func main() { } return filtered, nil }, - // highlight-end }, exampleAPI)).Methods(http.MethodPost) } @@ -516,91 +481,85 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + - - + + -```python +```python {9,10,11} from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.emailverification import EmailVerificationClaim from supertokens_python.recipe.session import SessionContainer from fastapi import Depends -@app.post('/like_comment') # type: ignore +@app.post('/like_comment') async def like_comment(session: SessionContainer = Depends( verify_session( - # highlight-start # We keep all validators except for the EmailVerification ones override_global_claim_validators=lambda global_validators, session, user_context: [ validators for validators in global_validators if validators.id != EmailVerificationClaim.key] - # highlight-end ) )): # All validator checks have passed and the user has a verified email address pass ``` - - + + -```python +```python {6,7,8} from supertokens_python.recipe.session.framework.flask import verify_session from supertokens_python.recipe.emailverification import EmailVerificationClaim -@app.route('/update-jwt', methods=['POST']) # type: ignore +@app.route('/update-jwt', methods=['POST']) @verify_session( - # highlight-start # We keep all validators except for the EmailVerification ones override_global_claim_validators=lambda global_validators, session, user_context: [ validators for validators in global_validators if validators.id != EmailVerificationClaim.key] - # highlight-end ) def like_comment(): # All validator checks have passed and the user has a verified email address pass ``` - - + + -```python +```python {6,7,8} from supertokens_python.recipe.session.framework.django.asyncio import verify_session from django.http import HttpRequest from supertokens_python.recipe.emailverification import EmailVerificationClaim @verify_session( - # highlight-start # We keep all validators except for the EmailVerification ones override_global_claim_validators=lambda global_validators, session, user_context: [ validators for validators in global_validators if validators.id != EmailVerificationClaim.key] - # highlight-end ) async def like_comment(request: HttpRequest): # All validator checks have passed and the user has a verified email address pass ``` - - + + - - + + ### Add email verification checks to specific routes If you want to protect specific backend API routes with email verification checks, set the `mode` to `OPTIONAL` in the `EmailVerification` configuration. You then override the `verifySession` middleware protecting the route to check for email verification status. - - - - + + + + -```tsx +```tsx {11} import { verifySession } from "supertokens-node/recipe/session/framework/express"; import express from "express"; import { SessionRequest } from "supertokens-node/framework/express"; @@ -611,7 +570,6 @@ let app = express(); app.post( "/update-blog", verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => [...globalValidators, EmailVerificationClaim.validators.isVerified()], }), async (req: SessionRequest, res) => { @@ -619,10 +577,10 @@ app.post( } ); ``` - - + + -```tsx +```tsx {15} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import {SessionRequest} from "supertokens-node/framework/hapi"; @@ -637,7 +595,6 @@ server.route({ pre: [ { method: verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => [...globalValidators, EmailVerificationClaim.validators.isVerified()], }), }, @@ -648,10 +605,10 @@ server.route({ } }) ``` - - + + -```tsx +```tsx {10} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import { SessionRequest } from "supertokens-node/framework/fastify"; @@ -661,7 +618,6 @@ let fastify = Fastify(); fastify.post("/update-blog", { preHandler: verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => [...globalValidators, EmailVerificationClaim.validators.isVerified()], }), }, async (req: SessionRequest, res) => { @@ -669,10 +625,10 @@ fastify.post("/update-blog", { }); ``` - - + + -```tsx +```tsx {10} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification"; @@ -682,15 +638,14 @@ async function updateBlog(awsEvent: SessionEvent) { }; exports.handler = verifySession(updateBlog, { - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => [...globalValidators, EmailVerificationClaim.validators.isVerified()] }); ``` - - + + -```tsx +```tsx {9} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import {SessionContext} from "supertokens-node/framework/koa"; @@ -699,17 +654,16 @@ import { EmailVerificationClaim } from "supertokens-node/recipe/emailverificatio let router = new KoaRouter(); router.post("/update-blog", verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => [...globalValidators, EmailVerificationClaim.validators.isVerified()] }), async (ctx: SessionContext, next) => { // All validator checks have passed and the user has a verified email address }); ``` - - + + -```tsx +```tsx {11} import { inject, intercept } from "@loopback/core"; import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; @@ -720,7 +674,6 @@ class SetRole { constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { } @post("/update-blog") @intercept(verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => [...globalValidators, EmailVerificationClaim.validators.isVerified()] })) @response(200) @@ -730,27 +683,25 @@ class SetRole { } ``` - - + + + - - + -```tsx +```tsx {6,7,8,9,10,11,12,13,14,15,16,17} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification"; -// highlight-start export default async function setRole(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { await verifySession({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => [...globalValidators, EmailVerificationClaim.validators.isVerified()] })(req, res, next); }, @@ -764,12 +715,11 @@ export default async function setRole(req: SessionRequest, res: any) { -```tsx +```tsx {18} import SuperTokens from "supertokens-node"; import { NextResponse, NextRequest } from "next/server"; import { withSession } from "supertokens-node/nextjs"; import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -783,7 +733,6 @@ export async function POST(request: NextRequest) { return NextResponse.json({}); }, { - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators) => [...globalValidators, EmailVerificationClaim.validators.isVerified()] } ); @@ -792,13 +741,12 @@ export async function POST(request: NextRequest) { - - + + -```tsx +```tsx {10} import { Controller, Post, UseGuards, Request, Response, Session } from "@nestjs/common"; import { SessionContainer, SessionClaimValidator } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification"; @@ -806,7 +754,6 @@ import { EmailVerificationClaim } from "supertokens-node/recipe/emailverificatio export class ExampleController { @Post('example') @UseGuards(new AuthGuard({ - // highlight-next-line overrideGlobalClaimValidators: async (globalValidators: SessionClaimValidator[]) => [...globalValidators, EmailVerificationClaim.validators.isVerified()] })) async postExample(@Session() session: SessionContainer): Promise { @@ -815,15 +762,15 @@ export class ExampleController { } } ``` - + - - - - - + + + + + -```go +```go {14,15,16,17} import ( "net/http" @@ -837,12 +784,10 @@ import ( func main() { _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, evclaims.EmailVerificationClaimValidators.IsVerified(nil, nil)) return globalClaimValidators, nil }, - // highlight-end }, exampleAPI).ServeHTTP(rw, r) }) } @@ -852,10 +797,10 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + -```go +```go {17,18,19,20} import ( "net/http" @@ -872,12 +817,10 @@ func main() { // Wrap the API handler in session.VerifySession router.POST("/likecomment", verifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, evclaims.EmailVerificationClaimValidators.IsVerified(nil, nil)) return globalClaimValidators, nil }, - // highlight-end }), exampleAPI) } @@ -899,10 +842,10 @@ func exampleAPI(c *gin.Context) { } ``` - - + + -```go +```go {17,18,19,20} import ( "net/http" @@ -919,12 +862,10 @@ func main() { // Wrap the API handler in session.VerifySession r.Post("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, evclaims.EmailVerificationClaimValidators.IsVerified(nil, nil)) return globalClaimValidators, nil }, - // highlight-end }, exampleAPI)) } @@ -933,10 +874,10 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + -```go +```go {17,18,19,20} import ( "net/http" @@ -953,12 +894,10 @@ func main() { // Wrap the API handler in session.VerifySession router.HandleFunc("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, evclaims.EmailVerificationClaimValidators.IsVerified(nil, nil)) return globalClaimValidators, nil }, - // highlight-end }, exampleAPI)).Methods(http.MethodPost) } @@ -967,92 +906,86 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + - - + + -```python +```python {9,10,11} from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.emailverification import EmailVerificationClaim from supertokens_python.recipe.session import SessionContainer from fastapi import Depends -@app.post('/like_comment') # type: ignore +@app.post('/like_comment') async def like_comment(session: SessionContainer = Depends( verify_session( - # highlight-start # We add the EmailVerificationClaim's is_verified validator override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \ [EmailVerificationClaim.validators.is_verified()] - # highlight-end ) )): # All validator checks have passed and the user has a verified email address pass ``` - - + + -```python +```python {6,7,8} from supertokens_python.recipe.session.framework.flask import verify_session from supertokens_python.recipe.emailverification import EmailVerificationClaim -@app.route('/update-jwt', methods=['POST']) # type: ignore +@app.route('/update-jwt', methods=['POST']) @verify_session( - # highlight-start # We add the EmailVerificationClaim's is_verified validator override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \ [EmailVerificationClaim.validators.is_verified()] - # highlight-end ) def like_comment(): # All validator checks have passed and the user has a verified email address pass ``` - - + + -```python +```python {6,7,8} from supertokens_python.recipe.session.framework.django.asyncio import verify_session from django.http import HttpRequest from supertokens_python.recipe.emailverification import EmailVerificationClaim @verify_session( - # highlight-start # We add the EmailVerificationClaim's is_verified validator override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \ [EmailVerificationClaim.validators.is_verified()] - # highlight-end ) async def like_comment(request: HttpRequest): # All validator checks have passed and the user has a verified email address pass ``` - - + + - - + + - + --- ## Protect frontend routes - + - + - + ### Protect all frontend routes @@ -1103,8 +1036,7 @@ The `` component automatically adds the `EmailVerificationClaim` va Finally, check the result of the validation in the `InvalidClaimHandler` component which displays `"You cannot access this page because your email address is not verified. "` if the `EmailVerificationClaim` validator failed. Alternatively you could also redirect the user to the default email verification path to trigger the sending of the verification email. -:::note -You can extend the `VerifiedRoute` component to check for other types of validators as well. +:::note[You can extend the `VerifiedRoute` component to check for other types of validators as well.] This component can then reuse to protect all your app's components (In this case, you may want to rename this component to something more appropriate, like `ProtectedRoute`). ::: @@ -1133,10 +1065,9 @@ function ProtectedComponent() { ``` + - - - + ```tsx import Session from "supertokens-web-js/recipe/session"; @@ -1171,13 +1102,12 @@ The `EmailVerificationClaim` validator is automatically checked by this function In case the `validationErrors` array is not empty, you can loop through the errors to know which claim has failed: -```tsx +```tsx {6,7,8,9,10,11,12} import Session from "supertokens-web-js/recipe/session"; import { EmailVerificationClaim } from "supertokens-web-js/recipe/emailverification"; async function shouldLoadRoute() { let validationErrors = await Session.validateClaims(/*{...}*/); - // highlight-start for (const err of validationErrors) { if (err.id === EmailVerificationClaim.id) { // email verification claim check failed @@ -1185,29 +1115,25 @@ async function shouldLoadRoute() { // some other claim check failed (from the global validators list) } } - // highlight-end } ``` - ### Check the verification status manually If you want to have more complex access control, you can either create your own validator, or you can get the boolean from the session as follows. Check it yourself: -```tsx +```tsx {6,7,8,9,10} import Session from "supertokens-web-js/recipe/session"; import { EmailVerificationClaim } from "supertokens-web-js/recipe/emailverification"; async function shouldLoadRoute(): Promise { if (await Session.doesSessionExist()) { - // highlight-start let isVerified = await Session.getClaimValue({claim: EmailVerificationClaim}); if (isVerified) { // user has verified their email address return true; } - // highlight-end } // either a session does not exist, or the user has not verified their email address return false @@ -1215,33 +1141,31 @@ async function shouldLoadRoute(): Promise { ``` + - - - + - + - + ## Protect frontend routes - + - + - + - - + + -```tsx +```tsx {6,7,8,9,10,11,12,13,14,15,16,17,18,19} import Session from "supertokens-web-js/recipe/session"; import { EmailVerificationClaim, sendVerificationEmail } from "supertokens-web-js/recipe/emailverification"; async function shouldLoadRoute(): Promise { if (await Session.doesSessionExist()) { - // highlight-start let validationErrors = await Session.validateClaims(); if (validationErrors.length === 0) { @@ -1256,7 +1180,6 @@ async function shouldLoadRoute(): Promise { } } } - // highlight-end } // a session does not exist, or email is not verified return false @@ -1285,15 +1208,12 @@ async function sendEmail() { ``` - - + + -```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensEmailVerification from "supertokens-web-js-script/recipe/emailverification"; +```tsx {3,4,5,6,7,8,9,10,11,12,13,14,15,16} async function shouldLoadRoute(): Promise { if (await supertokensSession.doesSessionExist()) { - // highlight-start let validationErrors = await supertokensSession.validateClaims(); if (validationErrors.length === 0) { @@ -1308,7 +1228,6 @@ async function shouldLoadRoute(): Promise { } } } - // highlight-end } // a session does not exist, or email is not verified return false @@ -1336,14 +1255,13 @@ async function sendEmail() { } ``` - + -:::note -The API for sending an email verification email requires an active session. +:::note[The API for sending an email verification email requires an active session.] If you are using the frontend SDKs, then the session tokens should automatically get attached to the request. ::: - + In your protected routes, you need to first check if a session exists, and then call the `Session.validateClaims` function as shown above. This function inspects the session's contents and runs claim validators on them. @@ -1353,20 +1271,18 @@ The `EmailVerificationClaim` validator is automatically checked by this function ### Handle 403 responses on the frontend - If your frontend queries a protected API on your backend and it fails with a 403, you can call the `validateClaims` function. Loop through the errors to know which claim has failed: -```tsx +```tsx {9,10,11,12,13,14,15,16,17,18,19} import axios from "axios"; import Session from "supertokens-web-js/recipe/session"; import { EmailVerificationClaim } from "supertokens-web-js/recipe/emailverification"; async function callProtectedRoute() { try { - let response = await axios.get("^{appInfo.apiDomain}/protectedroute"); + let response = await axios.get("/protectedroute"); } catch (error) { - // highlight-start if (axios.isAxiosError(error) && error.response?.status === 403) { let validationErrors = await Session.validateClaims(); for (let err of validationErrors) { @@ -1378,7 +1294,6 @@ async function callProtectedRoute() { // some other claim check failed (from the global validators list) } } - // highlight-end } } @@ -1386,40 +1301,35 @@ async function callProtectedRoute() { ``` + + - - - - + - + - - -```tsx +```tsx {6,7,8,9,10,11,12} import SuperTokens from 'supertokens-react-native'; async function checkIfEmailIsVerified() { if (await SuperTokens.doesSessionExist()) { - // highlight-start let isVerified: boolean = (await SuperTokens.getAccessTokenPayloadSecurely())["st-ev"].v; if (isVerified) { // TODO.. } else { - // You can trigger the sending of the verification email by calling `^{appInfo.apiDomain}^{appInfo.apiBasePath}/user/email/verify/token` + // You can trigger the sending of the verification email by calling `/auth/user/email/verify/token` } - // highlight-end } } ``` - + - + ```kotlin import android.app.Application @@ -1433,15 +1343,15 @@ class MainApplication: Application() { if (isVerified) { // TODO.. } else { - // You can trigger the sending of the verification email by calling `^{appInfo.apiDomain}^{appInfo.apiBasePath}/user/email/verify/token` + // You can trigger the sending of the verification email by calling `/auth/user/email/verify/token` } } } ``` - + - + ```swift import UIKit @@ -1453,16 +1363,16 @@ fileprivate class ViewController: UIViewController { if isVerified { // Email is verified } else { - // You can trigger the sending of the verification email by calling `^{appInfo.apiDomain}^{appInfo.apiBasePath}/user/email/verify/token` + // You can trigger the sending of the verification email by calling `/auth/user/email/verify/token` } } } } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -1479,34 +1389,34 @@ Future checkIfEmailIsVerified() async { if (isVerified) { // Email is verified } else { - // You can trigger the sending of the verification email by calling `^{appInfo.apiDomain}^{appInfo.apiBasePath}/user/email/verify/token` + // You can trigger the sending of the verification email by calling `/auth/user/email/verify/token` } } } } ``` - + - + ### Handle 403 responses on the frontend If your frontend queries a protected API on your backend and it fails with a 403, you can check the value of the `st-ev` claim in the access token payload. If it is false you can send the verification email - - + + - + --- ## See also - - - - - - + + + + + + diff --git a/docs/additional-verification/meta.ts b/docs/additional-verification/meta.ts new file mode 100644 index 0000000000..72f29c6b5e --- /dev/null +++ b/docs/additional-verification/meta.ts @@ -0,0 +1,8 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Additional Verification", + "icon": "shield-check", + "order": 4, + "collapsed": true +}); diff --git a/docs/additional-verification/mfa/_blocks/paid-feature-callout.mdx b/docs/additional-verification/mfa/_blocks/paid-feature-callout.mdx deleted file mode 100644 index 96a38808a7..0000000000 --- a/docs/additional-verification/mfa/_blocks/paid-feature-callout.mdx +++ /dev/null @@ -1,8 +0,0 @@ - -:::warning Paid Feature -This is a paid feature. - -For self hosted users, [Sign up](https://supertokens.com/auth) to get a license key and follow the instructions sent to you by email. Using the `dev` license key is free. Charging only starts once you enable the feature in production using the provided production license key. - -For managed service users, open the [SaaS Dashboard](https://supertokens.com/dashboard), select the relevant **Managed** deployment, and enable this feature from **Features**. Changes are saved automatically. Once enabled, this feature is free on the provided development environment. -::: diff --git a/docs/additional-verification/mfa/_category_.json b/docs/additional-verification/mfa/_category_.json deleted file mode 100644 index 3f68d29e7c..0000000000 --- a/docs/additional-verification/mfa/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Multi Factor Authentication", - "position": 1.2 -} diff --git a/docs/additional-verification/mfa/backup-codes.mdx b/docs/additional-verification/mfa/backup-codes.mdx index caa2311cc7..7fdd6acd03 100644 --- a/docs/additional-verification/mfa/backup-codes.mdx +++ b/docs/additional-verification/mfa/backup-codes.mdx @@ -1,25 +1,16 @@ --- title: Implement recovery codes -hide_title: true -sidebar_position: 7 -description: >- - Implement backup codes for account recovery by customizing SuperTokens SDKs - for MFA users. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Implement backup codes for account recovery by customizing SuperTokens SDKs for MFA users. +sidebar: + order: 7 --- - -# Implement recovery codes - - ## Overview Backup codes is one of the ways in which end users can recover their account in case they lose their second factor device. At the moment, SuperTokens does not have an in-built implementation for backup codes, however, you can customize the SDKs to add it. -:::info Note +:::info[Note] [Here is an example](https://github.com/supertokens/supertokens-auth-react/tree/master/examples/with-multifactorauth-recovery-codes) of how you can implement backup codes in your application if you are using the pre-built UI. ::: @@ -34,10 +25,12 @@ User can then go about adding a new device and completing MFA using that. ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: These instructions assume that you already have some knowledge of MFA. -If you are not familiar with terms like authentication factors and challenges, please go through the [MFA concepts page](/docs/additional-verification/mfa/important-concepts). +If you are not familiar with terms like authentication factors and challenges, please go through the [MFA concepts page](/additional-verification/mfa/important-concepts). The guide below focuses on Time-based One-Time Password (TOTP) as a second factor, but you can implement something similar for Passwordless as well. @@ -51,9 +44,9 @@ This API returns the plain text recovery code to the frontend to display to the ### 2. Allow users to generate a backup code when they finish MFA setup - + - + After the user has successfully set up their second factor (during sign up or during recovery process), they navigate to a page which shows them their backup code. @@ -74,9 +67,9 @@ Note that calling this API replaces the older recovery code, but since it's all [Here is an example](https://github.com/supertokens/supertokens-auth-react/tree/master/examples/with-multifactorauth-recovery-codes/frontend/src/CreateRecoveryCode/index.tsx) of how to implement this page. - + - + For custom UI, the UI for where and how you show the recovery code page is up to you. It is advisable to show the user this page post sign up, or whenever they create a new MFA device successfully. @@ -97,12 +90,12 @@ Note that calling this API replaces the older recovery code, but since it's all [Here is an example](https://github.com/supertokens/supertokens-auth-react/tree/master/examples/with-multifactorauth-recovery-codes/frontend/src/CreateRecoveryCode/index.tsx) of how to implement this page. - + ### 3. Show how to use backup codes on the MFA challenge UI - + You can achieve this by creating a "Lost device?" button in the pre-built UI that asks the user to enter the Time-based One-Time Password (TOTP) challenge. Once they click on this, users redirect to a page where they can enter their backup code. After verification, they further redirect to the create a new Time-based One-Time Password (TOTP) device page. @@ -111,14 +104,14 @@ Once they click on this, users redirect to a page where they can enter their bac [Here is an example implementation](https://github.com/supertokens/supertokens-auth-react/tree/master/examples/with-multifactorauth-recovery-codes/frontend/src/RecoveryCode/index.tsx) of a page which asks the user to enter their backup code. It then calls an API (see next step) to check if the code is correct or not. - + - + You should make a UI that asks the user to enter their backup code and call the API to verify it and mark it as "in use" (see next step). You want to give the option for users to enter their backup code when asked for the MFA challenge. - + ### 4. Modify the user's session to mark that they have verified their backup code @@ -126,18 +119,18 @@ On the backend, you set up an API that accepts the recovery code entered by the You achieve this by saving the `recoverCodeHash` in the session payload, which is then checked in the next step to force enable Time-based One-Time Password (TOTP) device creation. - + On the frontend, once this API returns a success, the user should navigate to the create a new Time-based One-Time Password (TOTP) device screen. You can see how this process completes in the [index.tsx file](https://github.com/supertokens/supertokens-auth-react/tree/master/examples/with-multifactorauth-recovery-codes/frontend/src/RecoveryCode/index.tsx#L20). - + - + On the frontend, once this API returns a success, the user should navigate to the create a new Time-based One-Time Password (TOTP) device screen. - + ### 5. Force users to setup a new device @@ -162,11 +155,9 @@ Finally, after successfully creating a new Time-based One-Time Password (TOTP) d ## See also - - - - - - - - + + + + + + diff --git a/docs/additional-verification/mfa/email-sms-otp/_category_.json b/docs/additional-verification/mfa/email-sms-otp/_category_.json deleted file mode 100644 index 35f798b184..0000000000 --- a/docs/additional-verification/mfa/email-sms-otp/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "OTP", - "position": 6 -} diff --git a/docs/additional-verification/mfa/email-sms-otp/meta.ts b/docs/additional-verification/mfa/email-sms-otp/meta.ts new file mode 100644 index 0000000000..3ae39d3ed1 --- /dev/null +++ b/docs/additional-verification/mfa/email-sms-otp/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "OTP", + "icon": "smartphone", + "order": 6 +}); diff --git a/docs/additional-verification/mfa/email-sms-otp/otp-for-all-users.mdx b/docs/additional-verification/mfa/email-sms-otp/otp-for-all-users.mdx index 73e4eca714..1d41828938 100644 --- a/docs/additional-verification/mfa/email-sms-otp/otp-for-all-users.mdx +++ b/docs/additional-verification/mfa/email-sms-otp/otp-for-all-users.mdx @@ -1,23 +1,13 @@ --- -id: otp-for-all-users title: OTP required for all users -hide_title: true -sidebar_position: 1 -description: >- - Implement a multi-factor authentication policy requiring all users to complete - an OTP challenge. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Implement a multi-factor authentication policy requiring all users to complete an OTP challenge. +sidebar: + order: 1 --- - -# OTP required for all users - This page shows how to implement an MFA policy that requires all users to complete an OTP challenge before accessing your application. The OTP can be sent via email or phone. -:::note -Assume that the first factor is email password or social login, but the same set of steps applies to other first factor types as well. +:::note[Assume that the first factor is email password or social login, but the same set of steps applies to other first factor types as well.] ::: ## Single tenant setup @@ -25,10 +15,10 @@ Assume that the first factor is email password or social login, but the same set ### Backend setup To start with, configure the backend in the following way: - - + + -```ts +```ts {29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,61,62,63,64,65,66,67,68,69,70} import supertokens, { User, RecipeUserId, } from "supertokens-node"; import { UserContext } from "supertokens-node/types"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -57,7 +47,6 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-start Passwordless.init({ contactMethod: "EMAIL", flowType: "USER_INPUT_CODE" @@ -85,13 +74,11 @@ supertokens.init({ }; } }), - // highlight-end MultiFactorAuth.init({ firstFactors: [ MultiFactorAuth.FactorIds.EMAILPASSWORD, MultiFactorAuth.FactorIds.THIRDPARTY ], - // highlight-start override: { functions: (originalImplementation) => { return { @@ -102,23 +89,21 @@ supertokens.init({ } } } - // highlight-end }) ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + -```python +```python {48} from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import multifactorauth, accountlinking from supertokens_python.recipe.multifactorauth.types import FactorIds, OverrideConfig, MFARequirementList @@ -166,7 +151,6 @@ def override_functions(original_implementation: RecipeInterface): required_secondary_factors_for_tenant: Callable[[], Awaitable[List[str]]], user_context: Dict[str, Any], ) -> MFARequirementList: - # highlight-next-line return [FactorIds.OTP_EMAIL] original_implementation.get_mfa_requirements_for_auth = ( @@ -184,7 +168,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ multifactorauth.init( first_factors=[FactorIds.EMAILPASSWORD, FactorIds.THIRDPARTY], @@ -195,11 +179,11 @@ init( ) ``` - - + + - Notice that the Passwordless recipe initializes in the `recipeList`. In this example, only email-based OTP is enabled, with `contactMethod` set to `EMAIL` and `flowType` to `USER_INPUT_CODE` (that is, `otp`). If you want to use phone SMS-based OTP, set the contact method to `PHONE`. If you want to give users both options, or for some users use email, and for others use phone, set `contactMethod` to `EMAIL_OR_PHONE`. -- We have also enabled the account linking feature since it's required for MFA to work. The above enables account linking for second factor only, but if you also want to enable it for first factor, see [this section](/docs/post-authentication/account-linking/automatic-account-linking). +- We have also enabled the account linking feature since it's required for MFA to work. The above enables account linking for second factor only, but if you also want to enable it for first factor, see [this section](/post-authentication/account-linking/automatic-account-linking). - Notice that `shouldRequireVerification: false` configures account linking. It means that the second factor can link to the first factor even though the first factor is not verified. If you want to do email verification of the first factor before setting up the second factor (for example if the first factor is email password, and the second is phone OTP), then you can set this boolean to `true`, and also init the email verification recipe on the frontend and backend in `REQUIRED` mode. - The `getMFARequirementsForAuth` function is overridden to indicate that `otp-email` must be completed before the user can access the app. Notice that `userId` is not checked there, and `otp-email` is returned for all users. You can also return `otp-phone` instead if you want users to complete the OTP challenge via a phone SMS. Finally, if you want to give users an option for email or phone, you can return the following array from the function: @@ -238,24 +222,23 @@ The `v` being `false` indicates that there are still factors that are pending. A Indicating that the user has finished all required factors, and should be allowed to access the app. -:::caution -If you are already using `Passwordless` or `ThirdPartyPasswordless` in your app as a first factor, you do not need to explicitly initialize the Passwordless recipe again. Ensure that the `contactMethod` and `flowType` are set correctly. +:::warning[If you are already using `Passwordless` or `ThirdPartyPasswordless` in your app as a first factor, you do not need to explicitly initialize the Passwordless recipe again. Ensure that the `contactMethod` and `flowType` are set correctly.] ::: ### Frontend setup - + - + We start by modifying the `init` function call on the frontend like this: - + - + -```tsx +```tsx {16,17,18,19,20,21,22,23,24} import supertokens from "supertokens-auth-react" import ThirdParty from "supertokens-auth-react/recipe/thirdparty" import EmailPassword from "supertokens-auth-react/recipe/emailpassword" @@ -271,7 +254,6 @@ supertokens.init({ recipeList: [ ThirdParty.init(/* ... */), EmailPassword.init( /* ... */), - // highlight-start Passwordless.init({ contactMethod: "EMAIL" }), @@ -281,26 +263,20 @@ supertokens.init({ MultiFactorAuth.FactorIds.THIRDPARTY ] }) - // highlight-end ] }) ``` - + - + You have to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: This change is in your auth route configuration. -```tsx +```tsx {12,13,14,15,16,17,18,19,20} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIThirdParty from "supertokens-auth-react-script/recipe/thirdparty" -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword" -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless" -import supertokensUIMultiFactorAuth from "supertokens-auth-react-script/recipe/multifactorauth" supertokensUIInit({ appInfo: { @@ -311,7 +287,6 @@ supertokensUIInit({ recipeList: [ supertokensUIThirdParty.init(/* ... */), supertokensUIEmailPassword.init( /* ... */), - // highlight-start supertokensUIPasswordless.init({ contactMethod: "EMAIL" }), @@ -321,14 +296,13 @@ supertokensUIInit({ supertokensUIMultiFactorAuth.FactorIds.THIRDPARTY ] }) - // highlight-end ] }) ``` This change goes in the `supertokens-web-js` SDK configuration at the root of your application: -```tsx +```tsx {13,14} import SuperTokens from 'supertokens-web-js'; import MultiFactorAuth from 'supertokens-web-js/recipe/multifactorauth'; import Passwordless from "supertokens-web-js/recipe/passwordless"; @@ -341,32 +315,29 @@ SuperTokens.init({ }, recipeList: [ // other recipes... - // highlight-start MultiFactorAuth.init(), Passwordless.init() - // highlight-end ], }); ``` - + - + - Like on the backend, the `passwordless` recipe initializes in the `recipeList`. The `contactMethod` needs to be consistent with the backend setting. - The `MultiFactorAuth` recipe is also initialized, and the first factors to use are included. In this case, that would be `emailpassword` and `thirdparty` - same as the backend. Next, add the Passwordless pre-built UI when rendering the SuperTokens component: - + - + - - + + -```tsx +```tsx {16} import { SuperTokensWrapper } from "supertokens-auth-react"; import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui"; @@ -382,9 +353,7 @@ function App() {
- // highlight-start {getSuperTokensRoutesForReactRouterDom(reactRouterDOM, [EmailPasswordPreBuiltUI, ThirdPartyPreBuiltUI, PasswordlessPreBuiltUI, MultiFactorAuthPreBuiltUI])} - // highlight-end // ... other routes
@@ -395,11 +364,11 @@ function App() { } ``` -
+
- + -```tsx +```tsx {9,10,11} import { SuperTokensWrapper } from "supertokens-auth-react"; import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui"; @@ -408,56 +377,52 @@ import { MultiFactorAuthPreBuiltUI } from "supertokens-auth-react/recipe/multifa import { PasswordlessPreBuiltUI } from "supertokens-auth-react/recipe/passwordless/prebuiltui"; function App() { - // highlight-start if (canHandleRoute([EmailPasswordPreBuiltUI, ThirdPartyPreBuiltUI, PasswordlessPreBuiltUI, MultiFactorAuthPreBuiltUI])) { return getRoutingComponent([EmailPasswordPreBuiltUI, ThirdPartyPreBuiltUI, PasswordlessPreBuiltUI, MultiFactorAuthPreBuiltUI]) } - // highlight-end return ( {/*Your app*/} ); } ``` - + - +
- + - + -:::success -This step is not required for non React apps, since all the pre-built UI components are already added into the bundle. +:::success[This step is not required for non React apps, since all the pre-built UI components are already added into the bundle.] ::: - + -
+ With the above configuration, users see `emailpassword` or social login UI when they visit the auth page. After completing that, users redirect to `/auth/mfa/otp-email` (assuming that the `websiteBasePath` is `/auth`) where they are asked to complete the OTP challenge. The UI for this screen looks like: - [Factor Setup UI](https://master--6571be2867f75556541fde98.chromatic.com/?path=/story/passwordless-mfa--setup-email) (This is in case the first factor doesn't provide an email for the user. In this example, the first factor does provide an email since it's email password or social login). - [Verification UI](https://master--6571be2867f75556541fde98.chromatic.com/?path=/story/passwordless-mfa--verification). -:::caution -If you are already using `Passwordless` or `ThirdPartyPasswordless` in your app as a first factor, you do not need to explicitly initialize the Passwordless recipe again. Ensure that the `contactMethod` is set correctly. +:::warning[If you are already using `Passwordless` or `ThirdPartyPasswordless` in your app as a first factor, you do not need to explicitly initialize the Passwordless recipe again. Ensure that the `contactMethod` is set correctly.] ::: -
+ - + We start by initializing the MFA and Passwordless recipe on the frontend like this: - + - + - + - + -```tsx +```tsx {13,14} import SuperTokens from 'supertokens-web-js'; import MultiFactorAuth from 'supertokens-web-js/recipe/multifactorauth'; import Passwordless from "supertokens-web-js/recipe/passwordless"; @@ -470,22 +435,17 @@ SuperTokens.init({ }, recipeList: [ // other recipes... - // highlight-start MultiFactorAuth.init(), Passwordless.init() - // highlight-end ], }); ``` - + - + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensMultiFactorAuth from 'supertokens-web-js-script/recipe/multifactorauth'; -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; +```tsx {9,10} supertokens.init({ appInfo: { apiDomain: "...", @@ -494,68 +454,64 @@ supertokens.init({ }, recipeList: [ // other recipes... - // highlight-start supertokensMultiFactorAuth.init(), supertokensPasswordless.init() - // highlight-end ], }); ``` - + - + - + - + -:::success -This step is not applicable for mobile apps. Please continue reading. +:::success[This step is not applicable for mobile apps. Please continue reading.] ::: - + - + -After the first factor login, you should start by [checking the access token payload and see if the MFA claim's `v` boolean is `false`](../frontend-setup#step-2-checking-the---custv-boolean-value-in-the-mfa-claim--cust). If it's not, then the user can redirect to the application page. +After the first factor login, you should start by [checking the access token payload and see if the MFA claim's `v` boolean is `false`](/additional-verification/mfa/initial-setup#12-add-the-mfa-flow). If it's not, then the user can redirect to the application page. -If it's `false`, the frontend then needs to [call the MFA endpoint](../frontend-setup#mfa-info-endpoint) to get information about which factor the user should complete next. Based on the backend configuration in this page, the `next` array contains `["otp-email"]`. +If it's `false`, the frontend then needs to [call the MFA endpoint](/additional-verification/mfa/initial-setup#the-mfa-info-endpoint) to get information about which factor the user should complete next. Based on the backend configuration in this page, the `next` array contains `["otp-email"]`. Two possibilities exist here: - Case 1: The user needs to set up an email to send the OTP to. This only happens if the first factor doesn't provide an email from the user (for example, if you used phone-based `otp` as the first factor). In this example on this doc, an email is always obtained from the first factor, so you do not need to build UI for this step (but this will still be discussed later on). - Case 2: The user already has an email associated with them and need to complete the OTP challenge. -We can know which case it is by checking if the `emails` object returned from [MFA Info endpoint](../frontend-setup#mfa-info-endpoint) contains any emails associated with the `otp-email` key. If the `emails["otp-email"]` property of the response is `undefined` or an empty array, then it's case 1, else it's case 2. +We can know which case it is by checking if the `emails` object returned from [MFA Info endpoint](/additional-verification/mfa/initial-setup#the-mfa-info-endpoint) contains any emails associated with the `otp-email` key. If the `emails["otp-email"]` property of the response is `undefined` or an empty array, then it's case 1, else it's case 2. #### Case 1 implementation: User needs to enter their email -In this case, a form needs to be created wherein the user can enter their email. Once they submit the form, the [`createCode` API](/docs/passwordless/custom-ui/login-otp) needs to be called. +In this case, a form needs to be created wherein the user can enter their email. Once they submit the form, the [`createCode` API](/authentication/passwordless/initial-setup#21-creating-and-sending-the-otp) needs to be called. -After this API call, you can show the user the enter OTP screen, and call the [`consumeCode` API](/docs/passwordless/custom-ui/login-otp#step-3-verifying-the-input-otp). If the API call returns a `RESTART_FLOW_ERROR`, you can handle this by asking the user to enter their email once again and then call the `createCode` function. +After this API call, you can show the user the enter OTP screen, and call the [`consumeCode` API](/authentication/passwordless/initial-setup#23-verifying-the-otp). If the API call returns a `RESTART_FLOW_ERROR`, you can handle this by asking the user to enter their email once again and then call the `createCode` function. #### Case 2 implementation: User needs to complete the OTP challenge -This case is when the user already has an email associated with their account and you can directly send a code to that email. You can get the email to send the code to from the result of the [MFA Info endpoint](../frontend-setup#mfa-info-endpoint). Specifically, from the response, you can read the email from the `emails` property like this: `emails["otp-email"][0]`. The first item in the array of email is picked since the emails are ordered based on: +This case is when the user already has an email associated with their account and you can directly send a code to that email. You can get the email to send the code to from the result of the [MFA Info endpoint](/additional-verification/mfa/initial-setup#the-mfa-info-endpoint). Specifically, from the response, you can read the email from the `emails` property like this: `emails["otp-email"][0]`. The first item in the array of email is picked since the emails are ordered based on: - Index 0 contains the email that belongs to the session's user. If the user's first factor was email password, the email in the 0th index of the array is that email. - The other emails in the array (if they exist), are from other login methods for this user ordered based on the oldest login method first. -You can even show a UI here asking the user to pick an email from the array if you like. Either way, when you have an email, you can call the [`createCode` API](/docs/passwordless/custom-ui/login-otp) to send the code to that email. +You can even show a UI here asking the user to pick an email from the array if you like. Either way, when you have an email, you can call the [`createCode` API](/authentication/passwordless/initial-setup#21-creating-and-sending-the-otp) to send the code to that email. -After this API call, you can show the user the enter OTP screen, and call the [`consumeCode` API](/docs/passwordless/custom-ui/login-otp#step-3-verifying-the-input-otp). If the API call returns a `RESTART_FLOW_ERROR`, you can handle this by calling the `createCode` function once again in the background. +After this API call, you can show the user the enter OTP screen, and call the [`consumeCode` API](/authentication/passwordless/initial-setup#23-verifying-the-otp). If the API call returns a `RESTART_FLOW_ERROR`, you can handle this by calling the `createCode` function once again in the background. -:::note -Notice that in Case 2, there is no UI for the user to enter an email. That happens. The user only sees the enter OTP screen. +:::note[Notice that in Case 2, there is no UI for the user to enter an email. That happens. The user only sees the enter OTP screen.] ::: We recommend that you add a sign out button when showing the second factor (case 1 or case 2) so that users can use this to escape out of the flow in case they are unable to complete the second factor. When the sign out button is clicked, you want to: - Call the `await clearLoginAttemptInfo()` function (if on web) to clear the state that's set in the browser storage when calling the `createCode` function. - Call the sign out function / API to clear the tokens. -On successful verification of the code, the `otp-email` factor is marked as completed and the `v` value is updated in the session based on if there are any more factors that the user needs to complete. The next step would be to check this `v` value in the MFA claim and redirect the user to the application page, or get information about the next factor using the [MFA info endpoint](../frontend-setup#mfa-info-endpoint). +On successful verification of the code, the `otp-email` factor is marked as completed and the `v` value is updated in the session based on if there are any more factors that the user needs to complete. The next step would be to check this `v` value in the MFA claim and redirect the user to the application page, or get information about the next factor using the [MFA info endpoint](/additional-verification/mfa/initial-setup#the-mfa-info-endpoint). - + ## Multi tenant setup @@ -565,10 +521,10 @@ In a multi-tenancy setup, you may want to enable email / phone OTP for all users To start, initialize the Passwordless and the MultiFactorAuth recipes in the following way: - - + + -```ts +```ts {29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56} import supertokens, { User, RecipeUserId, } from "supertokens-node"; import { UserContext } from "supertokens-node/types"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -597,7 +553,6 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-start Passwordless.init({ contactMethod: "EMAIL", flowType: "USER_INPUT_CODE" @@ -626,20 +581,18 @@ supertokens.init({ } }), MultiFactorAuth.init() - // highlight-end ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -685,7 +638,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ multifactorauth.init(), accountlinking.init(should_do_automatic_account_linking=should_do_automatic_account_linking) @@ -693,14 +646,14 @@ init( ) ``` - - + + Unlike the single tenant setup, no configuration is provided to the `MultiFactorAuth` recipe because all the necessary configuration is done on a tenant level. - + - + To configure otp-email requirement for a tenant, the following API can be called: @@ -728,18 +681,17 @@ async function createNewTenant() { - In the above, the `firstFactors` are set to `["emailpassword", "thirdparty"]` to indicate that the first factor can be either `emailpassword` or `thirdparty`. - The `requiredSecondaryFactors` is set to `["otp-email"]` to indicate that OTP email is required for all users in this tenant. The default implementation of `getMFARequirementsForAuth` in the `MultiFactorAuth` takes this into account. - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant @@ -764,8 +716,8 @@ async def create_new_tenant(): pass ``` - - + + ```python from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant @@ -791,12 +743,12 @@ def create_new_tenant(): pass ``` - - + + - + - + To configure otp-email requirement for a tenant, the following API can be called: @@ -814,17 +766,17 @@ curl --location --request PUT 'http://localhost:3567/recipe/multitenancy/tenant/ - In the above, the `firstFactors` are set to `["emailpassword", "thirdparty"]` to indicate that the first factor can be either `emailpassword` or `thirdparty`. - The `requiredSecondaryFactors` is set to `["otp-email"]` to indicate that OTP email is required for all users in this tenant. The default implementation of `getMFARequirementsForAuth` in the `MultiFactorAuth` takes this into account. - + - + -Enable EmailPassword and ThirdParty, OTP-Email +Enable EmailPassword and ThirdParty, OTP-Email As shown above, enable **Email Password** and **Third Party** in the Login methods section and enable **OTP - Email** in the Secondary Factors Section. - + - + Once the user finishes the first factor (for example, with `emailpassword`), their session access token payload looks like this: @@ -855,23 +807,22 @@ The `v` being `false` indicates that there are still factors that are pending. A Indicating that the user has finished all required factors, and should be allowed to access the app. -:::caution -If you are already using `Passwordless` or `ThirdPartyPasswordless` in your app as a first factor, you do not need to explicitly initialize the Passwordless recipe again. Ensure that the `contactMethod` and `flowType` are set correctly. +:::warning[If you are already using `Passwordless` or `ThirdPartyPasswordless` in your app as a first factor, you do not need to explicitly initialize the Passwordless recipe again. Ensure that the `contactMethod` and `flowType` are set correctly.] ::: ### Frontend setup - + We start by modifying the `init` function call on the frontend like this: - + - + -```tsx +```tsx {14,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37} import supertokens from "supertokens-auth-react" import ThirdParty from "supertokens-auth-react/recipe/thirdparty" import EmailPassword from "supertokens-auth-react/recipe/emailpassword" @@ -885,7 +836,6 @@ supertokens.init({ apiDomain: "...", websiteDomain: "...", }, - // highlight-next-line usesDynamicLoginMethods: true, recipeList: [ ThirdParty.init({ @@ -894,7 +844,6 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-start Passwordless.init({ contactMethod: "EMAIL" }), @@ -911,27 +860,20 @@ supertokens.init({ } } }) - // highlight-end ] }) ``` - + - + You have to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: This change is in your auth route configuration. -```tsx +```tsx {9,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIThirdParty from "supertokens-auth-react-script/recipe/thirdparty" -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword" -import supertokensUIMultiFactorAuth from "supertokens-auth-react-script/recipe/multifactorauth" -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless" -import supertokensUIMultitenancy from "supertokens-auth-react-script/recipe/multitenancy" supertokensUIInit({ appInfo: { @@ -939,7 +881,6 @@ supertokensUIInit({ apiDomain: "...", websiteDomain: "...", }, - // highlight-next-line usesDynamicLoginMethods: true, recipeList: [ supertokensUIThirdParty.init({ @@ -948,7 +889,6 @@ supertokensUIInit({ supertokensUIEmailPassword.init({ //... }), - // highlight-start supertokensUIPasswordless.init({ contactMethod: "EMAIL" }), @@ -965,17 +905,13 @@ supertokensUIInit({ } } }) - // highlight-end ] }) ``` This change goes in the `supertokens-web-js` SDK configuration at the root of your application: -```tsx -import supertokens from "supertokens-web-js-script"; -import MultiFactorAuth from 'supertokens-web-js-script/recipe/multifactorauth'; -import Session from "supertokens-web-js-script/recipe/session"; +```tsx {9,10} supertokens.init({ appInfo: { @@ -984,17 +920,15 @@ supertokens.init({ appName: "...", }, recipeList: [ - // highlight-start Session.init(), MultiFactorAuth.init(), - // highlight-end ], }); ``` - + - + - Like on the backend, the `Passwordless` recipe initializes in the `recipeList`. Make sure that the configuration for it is consistent with what's on the backend. - The `MultiFactorAuth` recipe is also initialized. Notice that unlike the single tenant setup, the `firstFactors` are not specified here. That information is fetched based on the `tenantId` you provide the SDK with. @@ -1003,15 +937,14 @@ supertokens.init({ Next, add the Passwordless pre-built UI when rendering the SuperTokens component: - + - + - - + + -```tsx +```tsx {16} import { SuperTokensWrapper } from "supertokens-auth-react"; import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui"; @@ -1027,9 +960,7 @@ function App() {
- // highlight-start {getSuperTokensRoutesForReactRouterDom(reactRouterDOM, [EmailPasswordPreBuiltUI, ThirdPartyPreBuiltUI, PasswordlessPreBuiltUI, MultiFactorAuthPreBuiltUI])} - // highlight-end // ... other routes
@@ -1040,11 +971,11 @@ function App() { } ``` -
+
- + -```tsx +```tsx {9,10,11} import { SuperTokensWrapper } from "supertokens-auth-react"; import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui"; @@ -1053,48 +984,44 @@ import { MultiFactorAuthPreBuiltUI } from "supertokens-auth-react/recipe/multifa import { PasswordlessPreBuiltUI } from "supertokens-auth-react/recipe/passwordless/prebuiltui"; function App() { - // highlight-start if (canHandleRoute([EmailPasswordPreBuiltUI, ThirdPartyPreBuiltUI, PasswordlessPreBuiltUI, MultiFactorAuthPreBuiltUI])) { return getRoutingComponent([EmailPasswordPreBuiltUI, ThirdPartyPreBuiltUI, PasswordlessPreBuiltUI, MultiFactorAuthPreBuiltUI]) } - // highlight-end return ( {/*Your app*/} ); } ``` - + - +
- + - + -:::success -This step is not required for non React apps, since all the pre-built UI components are already added into the bundle. +:::success[This step is not required for non React apps, since all the pre-built UI components are already added into the bundle.] ::: - + -
+ With the above configuration, users see the first and second factor based on the tenant configuration. For the tenant configured above, users see email password or social login first. After completing that, users redirect to `/auth/mfa/otp-email` (assuming that the `websiteBasePath` is `/auth`) where they are asked to complete the OTP challenge. The UI for this screen looks like: - [Factor Setup UI](https://master--6571be2867f75556541fde98.chromatic.com/?path=/story/passwordless-mfa--setup-email) (This is in case the first factor doesn't provide an email for the user. In this example, the first factor does provide an email since it's email password or social login). - [Verification UI](https://master--6571be2867f75556541fde98.chromatic.com/?path=/story/passwordless-mfa--verification). -:::caution -If you are already using `Passwordless` or `ThirdPartyPasswordless` in your app as a first factor, you do not need to explicitly initialize the Passwordless recipe again. Ensure that the `contactMethod` is set correctly. +:::warning[If you are already using `Passwordless` or `ThirdPartyPasswordless` in your app as a first factor, you do not need to explicitly initialize the Passwordless recipe again. Ensure that the `contactMethod` is set correctly.] ::: -
+ - + The steps here are the same as in [the single tenant setup above](#frontend-setup). - + ## Protecting frontend and backend routes @@ -1104,5 +1031,5 @@ See the section on [protecting frontend and backend routes](../protect-routes). By default, the email template used for otp-email login is [as shown here](https://github.com/SuperTokens/email-sms-templates?tab=readme-ov-file#otp-login), and the default SMS template is [as shown here](https://github.com/SuperTokens/email-sms-templates?tab=readme-ov-file#otp-login-1). The method for sending them is via an email and SMS sending service that is provided. If you would like to learn more about this, or change the content of the email, or the method by which they are sent, checkout the email / SMS delivery section in the recipe docs: -- [Email delivery configuration](/docs/platform-configuration/email-delivery) -- [SMS delivery configuration](/docs/platform-configuration/sms-delivery) +- [Email delivery configuration](/platform-configuration/email-delivery) +- [SMS delivery configuration](/platform-configuration/sms-delivery) diff --git a/docs/additional-verification/mfa/email-sms-otp/otp-for-opt-in-users.mdx b/docs/additional-verification/mfa/email-sms-otp/otp-for-opt-in-users.mdx index 225f260ac4..0383a04b49 100644 --- a/docs/additional-verification/mfa/email-sms-otp/otp-for-opt-in-users.mdx +++ b/docs/additional-verification/mfa/email-sms-otp/otp-for-opt-in-users.mdx @@ -1,20 +1,11 @@ --- -id: otp-for-opt-in-users title: OTP for specific users -hide_title: true -sidebar_position: 2 -description: >- - Implement MFA policy for specific users using OTP via email or SMS based on - defined criteria. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Implement MFA policy for specific users using OTP via email or SMS based on defined criteria. +sidebar: + order: 2 --- - -# OTP for specific users - -:::important +:::note Before reading the below, please first go through the setup for [OTP for all users](./otp-for-all-users) to understand the basics of how MFA with OTP works, and then come back here. ::: @@ -25,8 +16,7 @@ This page shows how to implement an MFA policy that requires certain users to do Whatever the criteria is, the steps to implementing this type of a flow is the same. -:::note -Assume that the first factor is email password or social login, but the same set of steps applies to other first factor types as well. +:::note[Assume that the first factor is email password or social login, but the same set of steps applies to other first factor types as well.] ::: ## Single tenant setup @@ -38,10 +28,10 @@ Assume that the first factor is email password or social login, but the same set To start with, configure the backend in the following way: - - + + -```ts +```ts {31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79} import supertokens, { User, RecipeUserId, } from "supertokens-node"; import { UserContext } from "supertokens-node/types"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -72,7 +62,6 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-start Passwordless.init({ contactMethod: "EMAIL", flowType: "USER_INPUT_CODE" @@ -105,7 +94,6 @@ supertokens.init({ MultiFactorAuth.FactorIds.EMAILPASSWORD, MultiFactorAuth.FactorIds.THIRDPARTY ], - // highlight-start override: { functions: (originalImplementation) => { return { @@ -123,21 +111,19 @@ supertokens.init({ } } } - // highlight-end }) ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -217,7 +203,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ multifactorauth.init( first_factors=[FactorIds.EMAILPASSWORD, FactorIds.THIRDPARTY], @@ -230,23 +216,20 @@ init( ) ``` - - + + Override the `getMFARequirementsForAuth` function to indicate that `otp-email` applies only to users with the `admin` role. You can also have any other criteria here. - - - #### Example 2: Ask for OTP only for users that have enabled OTP on their account To start with, configure the backend in the following way: - - + + -```ts +```ts {29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80} import supertokens, { User, RecipeUserId, } from "supertokens-node"; import { UserContext } from "supertokens-node/types"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -275,7 +258,6 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-start Passwordless.init({ contactMethod: "EMAIL", flowType: "USER_INPUT_CODE", @@ -328,20 +310,18 @@ supertokens.init({ MultiFactorAuth.FactorIds.THIRDPARTY ] }) - // highlight-end ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -434,7 +414,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ passwordless.init( contact_config=passwordless.ContactEmailOnlyConfig(), @@ -451,17 +431,16 @@ init( ) ``` - - + + - Initialize the multi-factor auth recipe here without any override to `getMFARequirementsForAuth`. The default implementation of this function already checks what factors a user has enabled and returns those. All that is needed is to mark `otp-email` as enabled for a user as soon as they have completed the OTP challenge successfully. This happens in the `consumeCodePOST` API override as shown above. Once the code is consumed successfully, mark the `otp-email` factor as enabled for the user, and the next time they login, they will be asked to complete the OTP challenge. - Notice that before calling `addToRequiredSecondaryFactorsForUser`, check if there is an input session or not. Only call `addToRequiredSecondaryFactorsForUser` function if there is a session which indicates that the user has finished some first factor already. - In both of the examples above, notice that the Passwordless recipe initializes in the `recipeList`. In this example, only email-based OTP is enabled, set the `contactMethod` to `EMAIL` and `flowType` to `USER_INPUT_CODE` (that is, OTP). If instead, you want to use phone SMS-based OTP, set the contact method to `PHONE`. If you want to give users both options, or for some users use email, and for others use phone, set `contactMethod` to `EMAIL_OR_PHONE`. -We have also enabled the account linking feature since it's required for MFA to work. The above enables account linking for second factor only, but if you also want to enable it for first factor, see [this section](/docs/post-authentication/account-linking/automatic-account-linking). +We have also enabled the account linking feature since it's required for MFA to work. The above enables account linking for second factor only, but if you also want to enable it for first factor, see [this section](/post-authentication/account-linking/automatic-account-linking). Notice that `shouldRequireVerification: false` configures account linking. It means that the second factor can link to the first factor even though the first factor is not verified. If you want to do email verification of the first factor before setting up the second factor (for example if the first factor is email password, and the second is phone OTP), then set this boolean to `true`, and also init the email verification recipe on the frontend and backend in `REQUIRED` mode. @@ -493,8 +472,7 @@ The `v` being `false` indicates that there are still factors that are pending. A Indicating that the user has finished all required factors, and should access the app. -:::caution -If you are already using `Passwordless` or `ThirdPartyPasswordless` in your app as a first factor, you do not need to explicitly initialize the Passwordless recipe again. +:::warning[If you are already using `Passwordless` or `ThirdPartyPasswordless` in your app as a first factor, you do not need to explicitly initialize the Passwordless recipe again.] ::: ### Frontend setup @@ -511,8 +489,8 @@ The second part, which is only applicable in case you want to allow users to ena To know if the user has enabled OTP, you can make an API your backend which calls the following function: - - + + ```ts import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; @@ -523,15 +501,14 @@ async function isOTPEmailEnabledForUser(userId: string) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python.recipe.multifactorauth.asyncio import get_required_secondary_factors_for_user @@ -542,13 +519,13 @@ async def is_otp_email_factor_enabled_for_user(user_id: str) -> bool: return FactorIds.OTP_EMAIL in factors ``` - - + + If the user wants to enable or disable otp-email for them, you can make an API on your backend which calls the following function: - - + + ```ts import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; @@ -562,15 +539,14 @@ async function disableMFAForUser(userId: string) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python.recipe.multifactorauth.asyncio import ( @@ -587,11 +563,10 @@ async def disable_mfa_for_user(user_id: str) -> None: await remove_from_required_secondary_factors_for_user(user_id, FactorIds.OTP_EMAIL) ``` - - + + -:::note -If instead you want to work with `otp-phone`, you can replace `otp-email` with `otp-phone` in the above snippets. Also make sure that the `contactMethod` configures to `PHONE` in the Passwordless recipe on the frontend (for pre-built UI) and backend. +:::note[If instead you want to work with `otp-phone`, you can replace `otp-email` with `otp-phone` in the above snippets. Also make sure that the `contactMethod` configures to `PHONE` in the Passwordless recipe on the frontend (for pre-built UI) and backend.] ::: @@ -604,10 +579,10 @@ However, if you want OTP to be active for a specific user, for a specific tenant #### Example 1: Only enable OTP for users that have an `admin` role - - + + -```ts +```ts {32,70} import supertokens, { User, RecipeUserId, } from "supertokens-node"; import { UserContext } from "supertokens-node/types"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -639,7 +614,6 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-next-line Passwordless.init({ contactMethod: "EMAIL", flowType: "USER_INPUT_CODE" @@ -678,7 +652,6 @@ supertokens.init({ ...originalImplementation, getMFARequirementsForAuth: async function (input) { let roles = await UserRoles.getRolesForUser(input.tenantId, (await input.user).id) - // highlight-next-line if (roles.roles.includes("admin") && (await input.requiredSecondaryFactorsForTenant).includes(MultiFactorAuth.FactorIds.OTP_EMAIL)) { // we only want otp-email for admins return [MultiFactorAuth.FactorIds.OTP_EMAIL] @@ -695,15 +668,14 @@ supertokens.init({ }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -787,7 +759,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ passwordless.init( contact_config=ContactEmailOnlyConfig(), flow_type="USER_INPUT_CODE" @@ -803,19 +775,18 @@ init( ) ``` - - + + - The implementation of `shouldRequireOTPEmailForTenant` is entirely up to you. - #### Example 2: Ask for OTP only for users that have enabled OTP on their account - - + + -```ts +```ts {80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95} import supertokens, { User, RecipeUserId, } from "supertokens-node"; import { UserContext } from "supertokens-node/types"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -895,7 +866,6 @@ supertokens.init({ MultiFactorAuth.FactorIds.EMAILPASSWORD, MultiFactorAuth.FactorIds.THIRDPARTY ], - // highlight-start override: { functions: (originalImplementation) => { return { @@ -912,21 +882,19 @@ supertokens.init({ } } } - // highlight-end }) ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -1048,7 +1016,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ passwordless.init( contact_config=ContactEmailOnlyConfig(), @@ -1066,13 +1034,12 @@ init( ) ``` - - + + An override for `getMFARequirementsForAuth` is available, which checks if otp-email is active for the user, and also considers the `tenantId` to decide if this user should go through the otp-email flow while logging into this tenant. The implementation of `shouldRequireOTPEmailForTenant` is entirely up to you. - ### Frontend setup The frontend setup is identical to the [frontend setup](#frontend-setup) section above. @@ -1085,6 +1052,5 @@ See the section on [protecting frontend and backend routes](../protect-routes). By default, the email template used for otp-email login is [as shown here](https://github.com/SuperTokens/email-sms-templates?tab=readme-ov-file#otp-login), and the default SMS template is [as shown here](https://github.com/SuperTokens/email-sms-templates?tab=readme-ov-file#otp-login-1). The method for sending them is via an email and SMS sending service that is available. If you would like to learn more about this, or change the content of the email, or the method by which they send, checkout the email / SMS delivery section in the recipe docs: -- [Email delivery configuration](/docs/platform-configuration/email-delivery) -- [SMS delivery configuration](/docs/platform-configuration/sms-delivery) - +- [Email delivery configuration](/platform-configuration/email-delivery) +- [SMS delivery configuration](/platform-configuration/sms-delivery) diff --git a/docs/additional-verification/mfa/embed-the-prebuilt-ui.mdx b/docs/additional-verification/mfa/embed-the-prebuilt-ui.mdx index 666b71d6bf..db27803c5d 100644 --- a/docs/additional-verification/mfa/embed-the-prebuilt-ui.mdx +++ b/docs/additional-verification/mfa/embed-the-prebuilt-ui.mdx @@ -1,16 +1,10 @@ --- title: Embed the pre-built UI component -hide_title: true -sidebar_position: 8 description: Embed and customize a prebuilt MFA UI component. -page_type: guide -recipe: mfa -category: multi-factor-authentication +sidebar: + order: 8 --- - -# Embed the pre-built UI component - ## Overview ## Before you start @@ -26,26 +20,22 @@ The tutorial configures `TOTP` as a secondary factor, but the same set of steps The following example shows the scenario where you have a dedicated route, such as `/totp`, for rendering the TOTP Widget. Upon a successful login, the user will be automatically redirected to the return value of `getRedirectionURL` (defaulting to `/`). - - + + - - + + - + - + -```tsx +```tsx {4,22,23,24,25,26,27,28,39} import SuperTokens from "supertokens-auth-react"; import TOTP from "supertokens-auth-react/recipe/totp"; import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth"; -// highlight-start import { MFATOTP } from 'supertokens-auth-react/recipe/totp/prebuiltui'; -// highlight-end -// @ts-ignore import Header from "./header"; -// @ts-ignore import Footer from "./footer"; import { useNavigate } from "react-router-dom"; @@ -62,7 +52,6 @@ SuperTokens.init({ } }), MultiFactorAuth.init({ - // highlight-start getRedirectionURL: async (context) => { if (context.action === "GO_TO_FACTOR") { if (context.factorId === "totp") { @@ -70,7 +59,6 @@ SuperTokens.init({ } } } - // highlight-end }) // ... ], @@ -81,7 +69,6 @@ function TOTPPage() { return (
- // highlight-next-line
@@ -89,21 +76,17 @@ function TOTPPage() { } ``` -
+
- + -```tsx +```tsx {5,23,24,25,26,27,28,29,40} import React from "react"; import SuperTokens from "supertokens-auth-react"; import TOTP from "supertokens-auth-react/recipe/totp"; import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth"; -// highlight-start import { MFATOTP } from 'supertokens-auth-react/recipe/totp/prebuiltui'; -// highlight-end -// @ts-ignore import Header from "./header"; -// @ts-ignore import Footer from "./footer"; import { useHistory } from "react-router-dom5"; @@ -120,7 +103,6 @@ SuperTokens.init({ }, }), MultiFactorAuth.init({ - // highlight-start getRedirectionURL: async (context) => { if (context.action === "GO_TO_FACTOR") { if (context.factorId === "totp") { @@ -128,7 +110,6 @@ SuperTokens.init({ } } } - // highlight-end }) // ... ], @@ -139,7 +120,6 @@ function TOTPPage() { return (
- // highlight-next-line
@@ -147,24 +127,20 @@ function TOTPPage() { } ``` -
+
- +
- - + + -```tsx +```tsx {5,38} import React from "react"; import SuperTokens from "supertokens-auth-react"; import TOTP from "supertokens-auth-react/recipe/totp"; import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth"; -// highlight-start import { MFATOTP } from 'supertokens-auth-react/recipe/totp/prebuiltui'; -// highlight-end -// @ts-ignore import Header from "./header"; -// @ts-ignore import Footer from "./footer"; SuperTokens.init({ @@ -196,15 +172,14 @@ function TOTPPage() { return (
- // highlight-next-line
) } ``` -
- + + In the above code snippet, we: @@ -213,17 +188,16 @@ In the above code snippet, we: Feel free to customize the redirection URLs as needed. -
+ - + -:::caution -Not applicable to non-react apps. Please build your own custom UI instead. +:::warning[Not applicable to non-react apps. Please build your own custom UI instead.] ::: - + -
+ --- @@ -232,27 +206,25 @@ Not applicable to non-react apps. Please build your own custom UI instead. The following example shows the scenario where you embed the TOTP Widget in a popup, and upon successful login, you aim to close the popup. This is especially useful for step up auth. - + - + - - + + - + - + -```tsx +```tsx {6,7,49} import React, { useState, useEffect } from "react"; import Modal from "react-modal"; import SuperTokens from "supertokens-auth-react"; import TOTP from "supertokens-auth-react/recipe/totp"; import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth"; -// highlight-start import { MFATOTP } from 'supertokens-auth-react/recipe/totp/prebuiltui'; import Session from "supertokens-auth-react/recipe/session"; -// highlight-end import { useNavigate } from "react-router-dom"; SuperTokens.init({ @@ -294,7 +266,6 @@ function TOTPPopup() { isOpen={isModalOpen} contentLabel="TOTP Modal" > - {/* highlight-next-line */} @@ -302,20 +273,18 @@ function TOTPPopup() { } ``` - + - + -```tsx +```tsx {6,7,49} import React, { useState, useEffect } from "react"; import Modal from "react-modal"; import SuperTokens from "supertokens-auth-react"; import TOTP from "supertokens-auth-react/recipe/totp"; import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth"; -// highlight-start import { MFATOTP } from 'supertokens-auth-react/recipe/totp/prebuiltui'; import Session from "supertokens-auth-react/recipe/session"; -// highlight-end import { useHistory } from "react-router-dom5"; SuperTokens.init({ @@ -357,7 +326,6 @@ function TOTPPopup() { isOpen={isModalOpen} contentLabel="TOTP Modal" > - {/* highlight-next-line */} @@ -365,23 +333,21 @@ function TOTPPopup() { } ``` - + - + - - + + -```tsx +```tsx {6,7,47} import React, { useState, useEffect } from "react"; import Modal from "react-modal"; import SuperTokens from "supertokens-auth-react"; import TOTP from "supertokens-auth-react/recipe/totp"; import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth"; -// highlight-start import { MFATOTP } from 'supertokens-auth-react/recipe/totp/prebuiltui'; import Session from "supertokens-auth-react/recipe/session"; -// highlight-end SuperTokens.init({ appInfo: { @@ -421,25 +387,23 @@ function TOTPPopup() { isOpen={isModalOpen} contentLabel="TOTP Modal" > - {/* highlight-next-line */} ); } ``` - - + + - + - + -:::caution -Not applicable to non-react apps. Please build your own custom UI instead. +:::warning[Not applicable to non-react apps. Please build your own custom UI instead.] ::: - + - + diff --git a/docs/additional-verification/mfa/hooks-and-overrides.mdx b/docs/additional-verification/mfa/hooks-and-overrides.mdx index f761315c1c..45175a135e 100644 --- a/docs/additional-verification/mfa/hooks-and-overrides.mdx +++ b/docs/additional-verification/mfa/hooks-and-overrides.mdx @@ -1,30 +1,22 @@ --- title: Hooks and overrides -hide_title: true -sidebar_position: 9 -description: >- - Configure your application for multi-factor authentication with account - linking and tenant-specific configurations. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Configure your application for multi-factor authentication with account linking and tenant-specific configurations. +sidebar: + order: 9 --- - -# Hooks and overrides - **SuperTokens** exposes a set of constructs that allow you to trigger different actions during the authentication lifecycle or to even fully customize the logic based on your use case. The following sections describe how you can modify adjust the `mfa` recipe to your needs. -Explore the [references pages](/docs/references) for a more in depth guide on hooks and overrides. +Explore the [references pages](/references) for a more in depth guide on hooks and overrides. ## Frontend event hooks The pre-built UI emits a few events that you can listen to on the frontend. As an example, you can use these for analytics: - + - + ```tsx import SuperTokens from "supertokens-auth-react" @@ -79,16 +71,12 @@ SuperTokens.init({ }) ``` - + - + ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIMultiFactorAuth from "supertokens-auth-react-script/recipe/multifactorauth" -import supertokensUITOTP from "supertokens-auth-react-script/recipe/totp"; -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless"; supertokensUIInit({ appInfo: { @@ -137,18 +125,18 @@ supertokensUIInit({ }) ``` - + - + ## Backend overrides It's a common use case to want to override the default behavior of SuperTokens after a user signs up or signs in. For example, you may want to change your database state whenever someone signs up. You can do this by overriding the sign up / sign in recipe functions in the backend SDK: -- [Passwordless recipe](/docs/authentication/passwordless/hooks-and-overrides) -- [EmailPassword recipe](/docs/authentication/email-password/hooks-and-overrides) -- [ThirdParty recipe](/docs/authentication/social/hooks-and-overrides) +- [Passwordless recipe](/authentication/passwordless/hooks-and-overrides) +- [EmailPassword recipe](/authentication/email-password/hooks-and-overrides) +- [ThirdParty recipe](/authentication/social/hooks-and-overrides) Since the sign up / sign in APIs share functionality for first factor and second factor login, your override applies to both first and second factor login. If you want to have different behavior for first and second factor login, you can use the `input` argument to the function to determine if the user is doing first or second factor login. diff --git a/docs/additional-verification/mfa/important-concepts.mdx b/docs/additional-verification/mfa/important-concepts.mdx index 3b0a5486fe..1744b977d6 100644 --- a/docs/additional-verification/mfa/important-concepts.mdx +++ b/docs/additional-verification/mfa/important-concepts.mdx @@ -1,20 +1,10 @@ --- -id: important-concepts title: Important concepts -hide_title: true -sidebar_position: 2 -toc_max_heading_level: 4 -description: >- - Understand SuperTokens auth factor IDs, completion status, and multi-factor - authentication setup. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Understand SuperTokens auth factor IDs, completion status, and multi-factor authentication setup. +sidebar: + order: 2 --- - -# Important concepts - ## Overview If you are new to Multi-factor authentication, MFA, this page provides a quick summary of how it works and the main terminology used in it. @@ -22,19 +12,15 @@ If you are new to Multi-factor authentication, MFA, this page provides a quick s MFA enhances security by requiring users to authenticate through: - -## **Initial login** - - The user enters their primary credentials, typically a username and password (first factor). - -## **Authentication challenge** - + +The user enters their primary credentials, typically a username and password (first factor). + + Upon successful entry of the primary credentials, the user receives an authentication challenge, prompting them to provide a secondary factor, such as an OTP or biometric verification. - -## **Access granted** - + + Access to the account or service is only granted when both the primary and secondary factors are successfully verified. - + This layered approach reduces the risk of unauthorized access, as an attacker would need to compromise multiple authentication methods to gain access. @@ -110,8 +96,6 @@ The first factors are those allowed to create a new session, whereas any other f In case the user calls an additional factor's API without a session, the API responds with a `401` error. - - ### Account linking Account linking refers to the process of connecting multiple accounts or identities across platforms or services. @@ -133,11 +117,10 @@ In the MFA guide, first factor account linking is not enabled, but you can enabl ## See also - - - - - - - - + + + + + + + diff --git a/docs/additional-verification/mfa/initial-setup.mdx b/docs/additional-verification/mfa/initial-setup.mdx index 430571ad5d..b0f148977c 100644 --- a/docs/additional-verification/mfa/initial-setup.mdx +++ b/docs/additional-verification/mfa/initial-setup.mdx @@ -1,20 +1,10 @@ --- title: Initial setup -hide_title: true -toc_max_heading_level: 4 -sidebar_position: 3 -description: >- - Configure your application for multi-factor authentication with account - linking and tenant-specific configurations. -page_type: tutorial -recipe: mfa -category: multi-factor-authentication +description: Configure your application for multi-factor authentication with account linking and tenant-specific configurations. +sidebar: + order: 3 --- - -# Initial setup - - ## Overview To integrate multi-factor authentication, MFA, in your application, you first need to decide on what factors you want to support and when to ask for them. @@ -22,17 +12,19 @@ The following guide shows you how to implement a basic setup while also covering ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: These instructions assume that you already have some knowledge of MFA. -If you are not familiar with terms like authentication factors and challenges, please go through the [MFA concepts page](/docs/additional-verification/mfa/important-concepts). +If you are not familiar with terms like authentication factors and challenges, please go through the [MFA concepts page](/additional-verification/mfa/important-concepts). If you plan to use the `otp-email` factor as a form of email verification, you also need to initialize the `emailverification` recipe in `REQUIRED` mode on the backend. This configuration ensures that the email verification process passes only if the originally provided email has been verified. ## Steps - + ### 1. Set up the backend @@ -40,10 +32,10 @@ This configuration ensures that the email verification process passes only if th MFA requires account linking to be active. You can enable it in the following way: - - + + -```ts +```ts {18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40} import SuperTokens, { User, RecipeUserId, } from "supertokens-node"; import { UserContext } from "supertokens-node/types"; import AccountLinking from "supertokens-node/recipe/accountlinking" @@ -61,7 +53,6 @@ SuperTokens.init({ }, recipeList: [ // ... - // highlight-start AccountLinking.init({ shouldDoAutomaticAccountLinking: async (newAccountInfo: AccountInfoWithRecipeId & { recipeUserId?: RecipeUserId }, user: User | undefined, session: SessionContainerInterface | undefined, tenantId: string, userContext: UserContext) => { if (session === undefined) { @@ -85,20 +76,18 @@ SuperTokens.init({ }; } }), - // highlight-end ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -139,37 +128,36 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework='...', # type: ignore + framework='...', recipe_list=[ accountlinking.init(should_do_automatic_account_linking=should_do_automatic_account_linking) ], ) ``` - - + + - The above snippet enables auto account linking only during the second factor and not for the first factor login. This means that if a user has an email password account, and then they login via Google (with the same email), those two accounts are not linked. However, if the second factor for logging in is email or phone OTP, then that passwordless account links to the first factor login method of that session. - Notice that `shouldRequireVerification: false` configures account linking. It means that the second factor can connect to the first factor even though the first factor is not verified. If you want to do email verification of the first factor before setting up the second factor (for example if the first factor is email password, and the second is phone OTP), then you can set this boolean to `true`, and also init the email verification recipe on the frontend and backend in `REQUIRED` mode. -- If you also want to enable first factor automatic account linking, see [this link](/docs/post-authentication/account-linking/automatic-account-linking). +- If you also want to enable first factor automatic account linking, see [this link](/post-authentication/account-linking/automatic-account-linking). -:::important -Account linking is a paid feature, and you need to generate a license key to enable it. Enabling the MFA feature also enables account linking automatically, meaning you don't need to check the account linking feature. +:::note[Account linking is a paid feature, and you need to generate a license key to enable it. Enabling the MFA feature also enables account linking automatically, meaning you don't need to check the account linking feature.] ::: #### 1.2 Configure the first factors - + -We start by initializing the MFA recipe on the backend and specifying the list of first factors using their [factor IDs](/docs/additional-verification/mfa/important-concepts#factors). You still have to initialize all the auth recipes in the `recipeList`, and configure them based on your needs. +We start by initializing the MFA recipe on the backend and specifying the list of first factors using their [factor IDs](/additional-verification/mfa/important-concepts#factors). You still have to initialize all the auth recipes in the `recipeList`, and configure them based on your needs. For example, the code below initializes `thirdparty`, `emailpassword` and `passwordless` recipes and sets the `firstFactor` array to be `["emailpassword", "thirdparty"]`. This means that email password and social login appear to the user as the first factor (using the `thirdparty` + `emailpassword` recipe), and `passwordless` serves as the second factor. - - + + -```ts +```ts {18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33} import supertokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty" import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -187,7 +175,6 @@ supertokens.init({ }, recipeList: [ // ... - // highlight-start ThirdParty.init({ //... }), @@ -204,20 +191,18 @@ supertokens.init({ MultiFactorAuth.FactorIds.THIRDPARTY ] }) - // highlight-end ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -234,7 +219,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init(), thirdparty.init(), @@ -245,21 +230,21 @@ init( ) ``` - - + + Other combinations of first factors exists. For example, if you want passwordless as the first factor, then you would init the passwordless recipe and add `"passwordless"` in the `firstFactors` array. - + - + For a multi-tenancy setup, where each tenant can have a different set of first factors, you can leave the `firstFactors` array as `undefined` in the `MultiFactorAuth.init`. Configure the `firstFactors` on a per-tenant basis when creating or updating a tenant as shown below: - + - + ```tsx import Multitenancy from "supertokens-node/recipe/multitenancy"; @@ -280,23 +265,21 @@ async function createNewTenant() { `firstFactors` includes only `"emailpassword"`. This means that users who login to this tenant can only use email password as the first factor. Later on, the configuration for passwordless as a second factor for this tenant appears. -:::important -- If you do not configure `firstFactors` array on a tenant configuration, then no factors activate for that tenant by default. +:::note[- If you do not configure `firstFactors` array on a tenant configuration, then no factors activate for that tenant by default.] - To remove the `firstFactors` configuration for a tenant, you can pass a `null` value for the `firstFactors` key in the tenant configuration. For that tenant, this makes SuperTokens default to the `firstFactors` array in the `MultiFactorAuth.init` from the backend `init` configuration. ::: - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant @@ -317,8 +300,8 @@ async def create_new_tenant(): pass ``` - - + + ```python from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant @@ -339,14 +322,14 @@ def create_new_tenant(): pass ``` - - + + - + - + -```bash showAppTypeSelect +```bash curl --location --request PUT 'http://localhost:3567/recipe/multitenancy/tenant/v2' \ --header 'api-key: YOUR_API_KEY' \ --header 'Content-Type: application/json' \ @@ -358,40 +341,39 @@ curl --location --request PUT 'http://localhost:3567/recipe/multitenancy/tenant/ `firstFactors` includes only `"emailpassword"`. This means that users who login to this tenant can only use email password as the first factor. Later on, the configuration for passwordless as a second factor for this tenant appears. -:::important -- If you do not configure `firstFactors` array on a tenant configuration, then no factors activate for that tenant by default. +:::note[- If you do not configure `firstFactors` array on a tenant configuration, then no factors activate for that tenant by default.] - To remove the `firstFactors` configuration for a tenant, you can pass a `null` value for the `firstFactors` key in the tenant configuration. For that tenant, this makes SuperTokens default to the `firstFactors` array in the `MultiFactorAuth.init` from the backend `init` configuration. ::: - + - + -Email Password enabled +Email Password enabled In the above setting, Email Password is active in the **Login Methods** section. This means that users who login to this tenant can only use email password as the first factor. Later on, the configuration for passwordless as a second factor for this tenant appears. By default, no login methods activate for a tenant. - + - + - + #### 1.3 Configure the second factor This section explains how to configure SuperTokens such that a second factor is necessary for all users during sign up and during sign in. TOTP serves as an example for the second factor. - + The following code snippet accomplishes this: - - + + -```ts +```ts {40,41,42,43,44,45,46,47,48,49} import SuperTokens, { User, RecipeUserId, } from "supertokens-node"; import { UserContext } from "supertokens-node/types"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -431,7 +413,6 @@ SuperTokens.init({ MultiFactorAuth.FactorIds.EMAILPASSWORD, MultiFactorAuth.FactorIds.THIRDPARTY ], - // highlight-start override: { functions: (originalImplementation) => { return { @@ -442,21 +423,19 @@ SuperTokens.init({ } } } - // highlight-end }) ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -502,7 +481,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init(), thirdparty.init(), @@ -518,8 +497,8 @@ init( ) ``` - - + + In the above snippet, you configure email password and social login as the first factor, followed by TOTP as the second factor. @@ -531,13 +510,11 @@ In the above example, `"totp"` returns as a required factor for all users. Howev The output of this function can be more complex than a `string[]`. You can also return an object which tells SuperTokens that any one of the factors must satisfy: + + + -## Require one of multiple factors - - - - -```ts +```ts {25,26,27,28,29,30} import supertokens from "supertokens-node"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth" @@ -562,14 +539,12 @@ supertokens.init({ return { ...originalImplementation, getMFARequirementsForAuth: async function (input) { - // highlight-start return [{ oneOf: [ MultiFactorAuth.FactorIds.TOTP, MultiFactorAuth.FactorIds.OTP_EMAIL ] }] - // highlight-end } } } @@ -579,17 +554,16 @@ supertokens.init({ }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + -```python +```python {21} from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import multifactorauth from supertokens_python.recipe.multifactorauth.types import FactorIds, OverrideConfig @@ -610,7 +584,6 @@ def override_functions(original_implementation: RecipeInterface): required_secondary_factors_for_tenant: Callable[[], Awaitable[List[str]]], user_context: Dict[str, Any], ) -> MFARequirementList: - # highlight-next-line return [FactorIds.TOTP, FactorIds.OTP_EMAIL] original_implementation.get_mfa_requirements_for_auth = ( @@ -628,7 +601,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ multifactorauth.init( first_factors=[FactorIds.EMAILPASSWORD, FactorIds.THIRDPARTY], @@ -638,15 +611,14 @@ init( ) ``` - - + + + + + + -## Require multiple factors in any order - - - - -```ts +```ts {25,26,27,28,29,30} import supertokens from "supertokens-node"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth" @@ -671,14 +643,12 @@ supertokens.init({ return { ...originalImplementation, getMFARequirementsForAuth: async function (input) { - // highlight-start return [{ allOfInAnyOrder: [ MultiFactorAuth.FactorIds.TOTP, MultiFactorAuth.FactorIds.OTP_EMAIL ] }] - // highlight-end } } } @@ -688,17 +658,16 @@ supertokens.init({ }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + -```python +```python {21} from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import multifactorauth from supertokens_python.recipe.multifactorauth.types import FactorIds, OverrideConfig @@ -719,7 +688,6 @@ def override_functions(original_implementation: RecipeInterface): required_secondary_factors_for_tenant: Callable[[], Awaitable[List[str]]], user_context: Dict[str, Any], ) -> MFARequirementList: - # highlight-next-line return [{"allOfInAnyOrder": [FactorIds.TOTP, FactorIds.OTP_EMAIL]}] original_implementation.get_mfa_requirements_for_auth = ( @@ -737,7 +705,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ multifactorauth.init( first_factors=[FactorIds.EMAILPASSWORD, FactorIds.THIRDPARTY], @@ -747,15 +715,14 @@ init( ) ``` - - - -## Require multiple factors in a specific order + + + + + + - - - -```ts +```ts {25,26,27,28,29,30,31,32,33} import supertokens from "supertokens-node"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth" @@ -780,7 +747,6 @@ supertokens.init({ return { ...originalImplementation, getMFARequirementsForAuth: async function (input) { - // highlight-start let currentCompletedFactors = MultiFactorAuth.MultiFactorAuthClaim.getValueFromPayload(input.accessTokenPayload) if (MultiFactorAuth.FactorIds.TOTP in currentCompletedFactors.c) { // this means the totp factor is completed @@ -790,7 +756,6 @@ supertokens.init({ // to do that right after first factor login return [MultiFactorAuth.FactorIds.TOTP] } - // highlight-end } } } @@ -800,17 +765,16 @@ supertokens.init({ }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + -```python +```python {24,25,26,27,28,29,30,31,32,33} from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import multifactorauth from supertokens_python.recipe.multifactorauth.types import FactorIds, OverrideConfig @@ -834,7 +798,6 @@ def override_functions(original_implementation: RecipeInterface): required_secondary_factors_for_tenant: Callable[[], Awaitable[List[str]]], user_context: Dict[str, Any], ) -> MFARequirementList: - # highlight-start current_completed_factors = MultiFactorAuthClaim.get_value_from_payload( access_token_payload ) @@ -845,7 +808,6 @@ def override_functions(original_implementation: RecipeInterface): # this means we have not finished totp yet, and we want # to do that right after first factor login return [FactorIds.TOTP] - # highlight-end original_implementation.get_mfa_requirements_for_auth = ( get_mfa_requirements_for_auth @@ -862,7 +824,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ multifactorauth.init( first_factors=[FactorIds.EMAILPASSWORD, FactorIds.THIRDPARTY], @@ -872,26 +834,25 @@ init( ) ``` - - - + + +
-:::note no-title -You can return an empty array from `getMFARequirementsForAuth` if you don't want any further MFA done for the current user. +:::note[You can return an empty array from `getMFARequirementsForAuth` if you don't want any further MFA done for the current user.] ::: -
+ - + For a multi tenant setup, you can configure a list of secondary factors when creating / modifying a tenant as shown below: - + - + ```tsx import Multitenancy from "supertokens-node/recipe/multitenancy"; @@ -917,18 +878,17 @@ To remove the `requiredSecondaryFactors` configuration for a tenant, you can pas If you add more than one item in this array, it means that the user must complete any one of factors mentioned in the array. If you want to have a different behavior for the tenant, you can achieve that by overriding the `getMFARequirementsForAuth` function as shown below: - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant @@ -952,8 +912,8 @@ async def create_new_tenant(): pass ``` - - + + ```python from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant @@ -977,12 +937,12 @@ def create_new_tenant(): pass ``` - - + + - + - + ```bash curl --location --request PUT 'http://localhost:3567/recipe/multitenancy/tenant/v2' \ @@ -1001,11 +961,11 @@ To remove the `requiredSecondaryFactors` configuration for a tenant, you can tur If you add more than one item in this array, it means that the user must complete any one of factors mentioned in the array. If you want to have a different behavior for the tenant, you can achieve that by overriding the `getMFARequirementsForAuth` function as shown below: - + - + -OTP - Email enabled +OTP - Email enabled As shown above, you turn on `OTP - Email` in the **Secondary Factors** section which means that all users who log into that tenant must complete `otp-email` as a second factor. @@ -1014,14 +974,14 @@ You can also turn off all factors to have no secondary factors required for the If you turn on more than one factor, it means that the user must complete any one of factors that are active. If you want to have a different behavior for the tenant, you can achieve that by overriding the `getMFARequirementsForAuth` function as shown below: - + - + - - + + -```ts +```ts {25,26,27} import supertokens from "supertokens-node"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth" @@ -1046,11 +1006,9 @@ supertokens.init({ return { ...originalImplementation, getMFARequirementsForAuth: async function (input) { - // highlight-start return [{ allOfInAnyOrder: await input.requiredSecondaryFactorsForTenant }] - // highlight-end } } } @@ -1060,17 +1018,16 @@ supertokens.init({ }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + -```python +```python {21} from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import multifactorauth from supertokens_python.recipe.multifactorauth.types import FactorIds, OverrideConfig @@ -1091,9 +1048,7 @@ def override_functions(original_implementation: RecipeInterface): required_secondary_factors_for_tenant: Callable[[], Awaitable[List[str]]], user_context: Dict[str, Any], ) -> MFARequirementList: - # highlight-start return [{"allOfInAnyOrder": await required_secondary_factors_for_tenant()}] - # highlight-end original_implementation.get_mfa_requirements_for_auth = ( get_mfa_requirements_for_auth @@ -1110,7 +1065,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ multifactorauth.init( first_factors=[FactorIds.EMAILPASSWORD, FactorIds.THIRDPARTY], @@ -1120,23 +1075,23 @@ init( ) ``` - - + + Notice that the input to the function contains the `requiredSecondaryFactorsForTenant` array. This would be the same list that you passed to the tenant configuration when creating / modifying the tenant as shown in the previous steps. - + -#### 1.4 Remove the second factor requirement {{optional}} +#### 1.4 Remove the second factor requirement (optional) Instead of configuring a factor for all users in your app, or for all users within a tenant, you may want to implement a flow in which users do MFA only if they have enabled it for themselves. Here, users may also want to choose what factors they would like to enable for themselves. This flow allows users to configure their MFA preferences in the settings page in your app's frontend. A pre-built UI for this is not yet provided, but in this section, we explain the setup on the backend. -You want to start by creating an API that does [session verification](/docs/additional-verification/session-verification/protect-api-routes), and then enable the desired factor for the user. For example, if the user wants to enable TOTP, then you would call the following function in your API: +You want to start by creating an API that does [session verification](/additional-verification/session-verification/protect-api-routes), and then enable the desired factor for the user. For example, if the user wants to enable TOTP, then you would call the following function in your API: - - + + ```ts import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; @@ -1146,18 +1101,17 @@ async function enableMFAForUser(userId: string) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multifactorauth.asyncio import add_to_required_secondary_factors_for_user @@ -1169,8 +1123,8 @@ async def enable_mfa_for_user(user_id: str): ) ``` - - + + ```python from supertokens_python.recipe.multifactorauth.syncio import add_to_required_secondary_factors_for_user @@ -1182,20 +1136,20 @@ def enable_mfa_for_user(user_id: str): ) ``` - - + + - - + + The effect of the above function call is that in the default implementation of `getMFARequirementsForAuth`, the factors specifically enabled for the input user are considered. By default, if you add multiple factors for a user ID, then it would require them to complete any one of those secondary factors during login. If you want to change the default behavior from "any one of" to something else (like "all of"), you can do this by overriding the `getMFARequirementsForAuth` function: - - + + -```ts +```ts {24,25,26,27,28} import supertokens from "supertokens-node"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth" @@ -1219,13 +1173,11 @@ supertokens.init({ functions: (originalImplementation) => { return { ...originalImplementation, - // highlight-start getMFARequirementsForAuth: async function (input) { return [{ allOfInAnyOrder: await input.requiredSecondaryFactorsForUser }] } - // highlight-end } } } @@ -1234,17 +1186,16 @@ supertokens.init({ }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + -```python +```python {21} from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import multifactorauth from supertokens_python.recipe.multifactorauth.types import FactorIds, OverrideConfig @@ -1265,9 +1216,7 @@ def override_functions(original_implementation: RecipeInterface): required_secondary_factors_for_tenant: Callable[[], Awaitable[List[str]]], user_context: Dict[str, Any], ) -> MFARequirementList: - # highlight-start return [{"allOfInAnyOrder": await required_secondary_factors_for_user()}] - # highlight-end original_implementation.get_mfa_requirements_for_auth = ( get_mfa_requirements_for_auth @@ -1284,7 +1233,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ multifactorauth.init( first_factors=[FactorIds.EMAILPASSWORD, FactorIds.THIRDPARTY], @@ -1294,8 +1243,8 @@ init( ) ``` - - + + Once you call the `addToRequiredSecondaryFactorsForUser` function for a user, SuperTokens stores this preference in the user metadata JSON of the user. For example, if you add `"totp"` as a required secondary factor for a user, this preference is stored in the metadata JSON as: @@ -1307,12 +1256,12 @@ Once you call the `addToRequiredSecondaryFactorsForUser` function for a user, Su } ``` -You can view this JSON on the [user details page of the user management dashboard](/docs/post-authentication/dashboard/user-management) and modify it manually if you like. +You can view this JSON on the [user details page of the user management dashboard](/post-authentication/dashboard/user-management) and modify it manually if you like. To know the factors that a user has enabled, you can use the following function: - - + + ```ts import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; @@ -1323,18 +1272,17 @@ async function isTotpEnabledForUser(userId: string) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multifactorauth.asyncio import get_required_secondary_factors_for_user @@ -1347,8 +1295,8 @@ async def is_totp_enabled_for_user(user_id: str): return FactorIds.TOTP in factors ``` - - + + ```python from supertokens_python.recipe.multifactorauth.syncio import get_required_secondary_factors_for_user @@ -1361,18 +1309,18 @@ def is_totp_enabled_for_user(user_id: str): return FactorIds.TOTP in factors ``` - - + + - - + + Using the above function, you can build your settings page on the frontend which displays the existing enabled factors for the user. Allow users to enable or disable factors as they like. Once you have enabled a factor for a user, you take them to that factor setup screen if they have not previously already setup the factor. To know if a factor is setup, you can call the following function (on the backend): - - + + ```ts import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; @@ -1383,18 +1331,17 @@ async function isTotpSetupForUser(userId: string) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multifactorauth.asyncio import get_factors_setup_for_user @@ -1407,8 +1354,8 @@ async def is_totp_enabled_for_user(user_id: str): return FactorIds.TOTP in factors ``` - - + + ```python from supertokens_python.recipe.multifactorauth.syncio import get_factors_setup_for_user @@ -1421,20 +1368,19 @@ def is_totp_enabled_for_user(user_id: str): return FactorIds.TOTP in factors ``` - - + + - - + + -Or you can call the [`MFAInfo` endpoint](/docs/additional-verification/mfa/initial-setup#the-mfa-info-endpoint) from the frontend which returns information indicating which factors have already been setup for the user and which not. +Or you can call the [`MFAInfo` endpoint](/additional-verification/mfa/initial-setup#the-mfa-info-endpoint) from the frontend which returns information indicating which factors have already been setup for the user and which not. A factor is considered setup if the user has gone through that factor's flow at least once. For example, if the user has created and verified a TOTP device, only then does the `getFactorsSetupForUser` function return `totp` as part of the array. Likewise, if the user has completed `otp-email` or `link-email` once, only then do these factors become a part of the returned array. Let's take two examples: - The first time the user enables TOTP, then the result of `getFactorsSetupForUser` does not contain `"totp"`. You should redirect the user to the TOTP setup screen. Once they add and verify a device, then `getFactorsSetupForUser` returns `["totp"]` even if they later disable TOTP from the settings page and re-enable it. - Let's say that the first factor for a user is `emailpassword`, and the second factor is `otp-email`. Once they sign up, SuperTokens already knows the email for the user, when they are doing the `otp-email` step, then they are not asked to enter their email again (that is, an OTP is directly sent to them). However, until they actually complete the OTP flow, `getFactorsSetupForUser` does not return `["otp-email"]` as part of the output. -:::caution -In the edge case that a factor is active for a user, but they sign out before setting it up, then when they login next, SuperTokens still asks them to complete the factor at that time. If SuperTokens doesn't have the required information (like no TOTP device for TOTP auth), then users need to set up a device at that point in time. +:::warning[In the edge case that a factor is active for a user, but they sign out before setting it up, then when they login next, SuperTokens still asks them to complete the factor at that time. If SuperTokens doesn't have the required information (like no TOTP device for TOTP auth), then users need to set up a device at that point in time.] If you would like to change how this works and only want users to set up their factor via the settings page, and not during sign in, you can do this by overriding the `getMFARequirementsForAuth` function, which takes as an input the list of factors that are setup for the current user. ::: @@ -1444,11 +1390,11 @@ The subsequent sections in this doc walk through frontend setup, and also specif ### 2. Set up the frontend - + - + - + The pre-built UI provides support for the following MFA methods: - TOTP @@ -1458,11 +1404,11 @@ If you want other types of MFA (like magic links, or password), please consider We start by initialising the MFA recipe on the frontend and providing the list of first factors as shown below: - + - + -```tsx +```tsx {17,18,19,20,21,22} import supertokens from "supertokens-auth-react" import EmailPassword from "supertokens-auth-react/recipe/emailpassword" import Passwordless from "supertokens-auth-react/recipe/passwordless" @@ -1479,32 +1425,26 @@ supertokens.init({ Passwordless.init({ contactMethod: "EMAIL_OR_PHONE", }), - // highlight-start MultiFactorAuth.init({ firstFactors: [ MultiFactorAuth.FactorIds.EMAILPASSWORD, MultiFactorAuth.FactorIds.THIRDPARTY ] }) - // highlight-end ] }) ``` - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: This change is in your auth route configuration. -```tsx +```tsx {14,15,16,17,18,19} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword" -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless" -import supertokensUIMultiFactorAuth from "supertokens-auth-react-script/recipe/multifactorauth" supertokensUIInit({ appInfo: { @@ -1517,14 +1457,12 @@ supertokensUIInit({ supertokensUIPasswordless.init({ contactMethod: "EMAIL_OR_PHONE", }), - // highlight-start supertokensUIMultiFactorAuth.init({ firstFactors: [ supertokensUIMultiFactorAuth.FactorIds.EMAILPASSWORD, supertokensUIMultiFactorAuth.FactorIds.THIRDPARTY ] }) - // highlight-end ] }) ``` @@ -1549,11 +1487,11 @@ SuperTokens.init({ }); ``` - + - + -In the above snippet, `thirdparty` and email password are configured as first factors. The second factor is determined [on the backend](/docs/additional-verification/mfa/initial-setup#1-set-up-the-backend), based on the boolean value of [`v` in the MFA claim in the session](/docs/additional-verification/mfa/important-concepts#factors). If the `v` is `false` in the session, it means that there are still factors pending before the user has completed login. In this case, the frontend SDK calls the `MFAInfo` endpoint (see more about this later) on the backend which returns the list of factors (`string[]`) that the user must complete next. For example: +In the above snippet, `thirdparty` and email password are configured as first factors. The second factor is determined [on the backend](/additional-verification/mfa/initial-setup#1-set-up-the-backend), based on the boolean value of [`v` in the MFA claim in the session](/additional-verification/mfa/important-concepts#factors). If the `v` is `false` in the session, it means that there are still factors pending before the user has completed login. In this case, the frontend SDK calls the `MFAInfo` endpoint (see more about this later) on the backend which returns the list of factors (`string[]`) that the user must complete next. For example: - If the next array is `["otp-email"]`, then the user sees the enter OTP screen for the email associated with the first factor login. - If the `n` array has multiple items, the user sees a [factor chooser screen](https://master--6571be2867f75556541fde98.chromatic.com/?path=/story/mfa-chooser--multiple-factors) using which they can decide which factor they want to continue with. - If the `next` is empty, it means that: @@ -1562,11 +1500,11 @@ In the above snippet, `thirdparty` and email password are configured as first fa If you notice, in the above code snippet, `Passwordless.init` is also included, and this handles cases where the second factor is `otp-email` or `otp-sms`. For TOTP, a different recipe is used as shown later in this guide. - + - + -For a multi-factor setup, the first factors are selected based on [the configuration of the tenant](./backend-setup#multi-tenant-setup). Each tenant has a `firstFactors` array configuration which determines the login options shown for that tenant. For MFA, the login options are determined by the [`requiredSecondaryFactors` configuration on the tenant](./backend-setup#multi-tenant-setup-1), or based on the customisations for `getMFARequirementsForAuth` on the backend. +For a multi-factor setup, the first factors are selected based on [the configuration of the tenant](/additional-verification/mfa/initial-setup#12-configure-the-first-factors). Each tenant has a `firstFactors` array configuration which determines the login options shown for that tenant. For MFA, the login options are determined by the [`requiredSecondaryFactors` configuration on the tenant](/additional-verification/mfa/initial-setup#13-configure-the-second-factor), or based on the customisations for `getMFARequirementsForAuth` on the backend. To tell the frontend to dynamically load the factors based on the tenant, four things need to supply: - The current `tenantId` @@ -1574,11 +1512,11 @@ To tell the frontend to dynamically load the factors based on the tenant, four t - Add `MultiFactorAuth.init` to the recipe list without any configured `firstFactors` - Init all the recipes that can be possibly used by any tenant as the first or second factor. - + - + -```tsx +```tsx {13,20,21,22,23,24,33} import supertokens from "supertokens-auth-react" import EmailPassword from "supertokens-auth-react/recipe/emailpassword" import Passwordless from "supertokens-auth-react/recipe/passwordless" @@ -1591,7 +1529,6 @@ supertokens.init({ apiDomain: "...", websiteDomain: "...", }, - // highlight-next-line usesDynamicLoginMethods: true, recipeList: [ Multitenancy.init({ @@ -1599,13 +1536,11 @@ supertokens.init({ functions: (oI) => { return { ...oI, - // highlight-start getTenantId: (input) => { // Implement the following based on the UX flow you want for // tenant discovery return "TODO.." } - // highlight-end } } } @@ -1614,28 +1549,21 @@ supertokens.init({ Passwordless.init({ contactMethod: "EMAIL_OR_PHONE", }), - // highlight-start MultiFactorAuth.init() - // highlight-end ] }) ``` - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: This change is in your auth route configuration. -```tsx +```tsx {9,16,17,18,19,20,29} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword" -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless" -import supertokensUIMultiFactorAuth from "supertokens-auth-react-script/recipe/multifactorauth" -import supertokensUIMultitenancy from "supertokens-auth-react-script/recipe/multitenancy" supertokensUIInit({ appInfo: { @@ -1643,7 +1571,6 @@ supertokensUIInit({ apiDomain: "...", websiteDomain: "...", }, - // highlight-next-line usesDynamicLoginMethods: true, recipeList: [ supertokensUIMultitenancy.init({ @@ -1651,13 +1578,11 @@ supertokensUIInit({ functions: (oI) => { return { ...oI, - // highlight-start getTenantId: (input) => { // Implement the following based on the UX flow you want for // tenant discovery return "TODO.." } - // highlight-end } } } @@ -1666,9 +1591,7 @@ supertokensUIInit({ supertokensUIPasswordless.init({ contactMethod: "EMAIL_OR_PHONE", }), - // highlight-start supertokensUIMultiFactorAuth.init() - // highlight-end ] }) ``` @@ -1693,9 +1616,9 @@ SuperTokens.init({ }); ``` - + - + - In the above code snippet, `ThirdPartyEmailPassword` and `Passwordless` are included as the auth methods. This works for a variety of use cases like: - The first factor for any tenant can be third party or email password login, and the second factor can be passwordless login (`otp-email` or `otp-sms`). @@ -1704,14 +1627,13 @@ SuperTokens.init({ - The first factor for any tenant can be passwordless login (with magic link), with or without a second factor (like `otp-email`). - You can even change `passwordles.init` to using `thirdpartypasswordless.init` if you want to have the first factor for any tenant to be `thirdparty` or passwordless login, with or without a second factor (like `otp-email`). - The `MultiFactorAuth` is configured without any configured `firstFactors` because the frontend is set to dynamically load the first factors based on the tenant. Therefore, `usesDynamicLoginMethods: true` is included in the `SuperTokens.init` call. -- The `Multitenancy` is configured as well, and a skeleton for `getTenantId` is provided. You need to implement this function based on the UX flow desired for tenant discovery. For example, [here is a common UX flow in which the tenant ID is determined based on the current sub domain](/docs/authentication/enterprise/subdomain-login). +- The `Multitenancy` is configured as well, and a skeleton for `getTenantId` is provided. You need to implement this function based on the UX flow desired for tenant discovery. For example, [here is a common UX flow in which the tenant ID is determined based on the current sub domain](/authentication/enterprise/subdomain-login). -:::important -- If you do initialize the `firstFactors` array for `MultiFactorAuth.init()` on the frontend, it is not considered when `usesDynamicLoginMethods: true` is included. -- If the tenant doesn't have the `firstFactors` array set, then the list of first factors that appear is determined by the [login methods that are enabled in that tenant's configuration](/docs/multi-tenancy/new-tenant). +:::note[- If you do initialize the `firstFactors` array for `MultiFactorAuth.init()` on the frontend, it is not considered when `usesDynamicLoginMethods: true` is included.] +- If the tenant doesn't have the `firstFactors` array set, then the list of first factors that appear is determined by the [login methods that are enabled in that tenant's configuration](/authentication/enterprise/manage-tenants#create-a-new-tenant). ::: -The second factor for a tenant is selected based on the [`secondaryFactors` configuration for the tenant](./backend-setup#multi-tenant-setup-1), or based on any custom implementation for the `getMFARequirementsForAuth` function. If the current user has specific MFA methods enabled for them, those are also shown as options as well. Overall, the list of secondary factors is used to build the `next` array returned from the `MFAInfo` endpoint (see more about this later). For example: +The second factor for a tenant is selected based on the [`secondaryFactors` configuration for the tenant](/additional-verification/mfa/initial-setup#13-configure-the-second-factor), or based on any custom implementation for the `getMFARequirementsForAuth` function. If the current user has specific MFA methods enabled for them, those are also shown as options as well. Overall, the list of secondary factors is used to build the `next` array returned from the `MFAInfo` endpoint (see more about this later). For example: - If the next array is `["otp-email"]`, then the user sees the enter OTP screen for the email associated with the first factor login. - If the `n` array has multiple items, the user sees a [factor chooser screen](https://master--6571be2867f75556541fde98.chromatic.com/?path=/story/mfa-chooser--multiple-factors) using which they can decide which factor they want to continue with. - If the `next` is empty, it means that: @@ -1720,7 +1642,7 @@ The second factor for a tenant is selected based on the [`secondaryFactors` conf In the subsequent sections, specific MFA setup examples are given for your reference. - + #### Usage with email verification @@ -1729,11 +1651,11 @@ For example, if the user has email password as the first factor, and then TOTP a To switch the order such that email verification happens after the secondary factors of MFA, follow the next code snippet. - + - + -```tsx +```tsx {21,22,23,24,25} import supertokens from "supertokens-auth-react" import EmailVerification from "supertokens-auth-react/recipe/emailverification"; import Session from "supertokens-auth-react/recipe/session"; @@ -1754,13 +1676,11 @@ supertokens.init({ functions: (originalImplementation) => { return { ...originalImplementation, - // highlight-start getGlobalClaimValidators: (input) => { let emailVerificationClaimValidator = input.claimValidatorsAddedByOtherRecipes.find(v => v.id === EmailVerification.EmailVerificationClaim.id)!; let filteredValidators = input.claimValidatorsAddedByOtherRecipes.filter(v => v.id !== EmailVerification.EmailVerificationClaim.id); return [...filteredValidators, emailVerificationClaimValidator]; } - // highlight-end } } } @@ -1771,15 +1691,12 @@ supertokens.init({ In the snippet above, the `getGlobalClaimValidators` function in the Session recipe is overridden to add the email verification validator at the end of the returned validators array. This ensures that post the first factor sign up, the first validator that fails is the MFA one which redirects the user to complete the MFA factors. - + - + -```tsx +```tsx {19,20,21,22,23} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailVerification from "supertokens-auth-react-script/recipe/emailverification"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -1797,13 +1714,11 @@ supertokensUIInit({ functions: (originalImplementation) => { return { ...originalImplementation, - // highlight-start getGlobalClaimValidators: (input) => { let emailVerificationClaimValidator = input.claimValidatorsAddedByOtherRecipes.find(v => v.id === supertokensUIEmailVerification.EmailVerificationClaim.id)!; let filteredValidators = input.claimValidatorsAddedByOtherRecipes.filter(v => v.id !== supertokensUIEmailVerification.EmailVerificationClaim.id); return [...filteredValidators, emailVerificationClaimValidator]; } - // highlight-end } } } @@ -1814,9 +1729,9 @@ supertokensUIInit({ In the snippet above, the `getGlobalClaimValidators` function in the Session recipe is overridden to add the email verification validator at the end of the returned validators array. This ensures that post the first factor sign up, the first validator that fails is the MFA one which redirects the user to complete the MFA factors. - + - + #### Handle misconfigurations @@ -1834,13 +1749,12 @@ Sometimes, users may end up seeing [an access denied screen](https://master--657 You can override this component in the following way: - + - + - - + + ```tsx import React from "react"; @@ -1869,9 +1783,9 @@ function App() { export default App; ``` - + - + ```tsx import React from "react"; @@ -1906,27 +1820,26 @@ function App() { export default App; ``` - + - + - + - + -:::caution -You cannot override the pre-built UI in non react apps yet. +:::warning[You cannot override the pre-built UI in non react apps yet.] ::: - + - + - + - + After the first factor sign in is over, to know the next auth challenge, the frontend should rely on the session's access token payload MFA claim's `n` array. For example, the access token payload may have the following content: @@ -1945,15 +1858,15 @@ This means that the user has completed the email password login, and that there #### 1.1 Initialize the MFA recipe - + - + - + - + -```tsx +```tsx {12} import SuperTokens from 'supertokens-web-js'; import MultiFactorAuth from 'supertokens-web-js/recipe/multifactorauth'; @@ -1965,19 +1878,16 @@ SuperTokens.init({ }, recipeList: [ // other recipes... - // highlight-next-line MultiFactorAuth.init() ], }); ``` - + - + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensMultiFactorAuth from 'supertokens-web-js-script/recipe/multifactorauth'; +```tsx {9} supertokens.init({ appInfo: { apiDomain: "...", @@ -1986,50 +1896,45 @@ supertokens.init({ }, recipeList: [ // other recipes... - // highlight-next-line supertokensMultiFactorAuth.init() ], }); ``` - + - + - + - + -:::success -This step is not applicable for mobile apps. Please continue reading. +:::success[This step is not applicable for mobile apps. Please continue reading.] ::: - + - + #### 1.2 Add the MFA flow The overall lifecycle of a factor post sign in is as follows: - -## Asking for the first factor - + This is the same as setting up a recipe per the other recipe guides. Please follow those. - -## Checking the `v` boolean value in the MFA claim - + + After the first factor is complete, the frontend needs to check if there are any pending MFA challenges. This can be done by reading the `v` claim from the session as shown below: - + - + - + - + ```tsx import MultiFactorAuth from 'supertokens-web-js/recipe/multifactorauth'; @@ -2053,13 +1958,11 @@ async function isAllMFACompleted() { } ``` - + - + ```tsx -import supertokensMultiFactorAuth from 'supertokens-web-js-script/recipe/multifactorauth'; -import supertokensSession from "supertokens-web-js-script/recipe/session"; async function isAllMFACompleted() { if (await supertokensSession.doesSessionExist()) { let mfaClaim = await supertokensSession.getClaimValue({ @@ -2078,36 +1981,34 @@ async function isAllMFACompleted() { } ``` - + - + - + - + - + - + -```tsx +```tsx {6,7} import SuperTokens from 'supertokens-react-native'; async function isAllMFACompleted() { if (await SuperTokens.doesSessionExist()) { - // highlight-start let isMFACompleted: boolean = (await SuperTokens.getAccessTokenPayloadSecurely())["st-mfa"].v; return isMFACompleted - // highlight-end } } ``` - + - + ```kotlin import android.app.Application @@ -2123,9 +2024,9 @@ class MainApplication: Application() { } ``` - + - + ```swift import UIKit @@ -2148,9 +2049,9 @@ fileprivate class ViewController: UIViewController { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -2171,24 +2072,23 @@ Future isAllMFACompleted() async { } ``` - - - - - + - + + -## Checking the `next` array + + + Once it is verified that MFA is still pending, the list of factors the user must do next needs to be retrieved. This can be done by calling the [MFA Info endpoint](#mfa-info-endpoint) which returns a list of next (`string[]`) factors: - If there are multiple values in this array, then the frontend needs to show these options to the user and ask them to pick one of them. - If there is only one item, then the UI can directly ask the user to complete that factor. - If this array is empty, then: - A misconfiguration exists on the backend. This would show an access denied screen to the user. OR; - Another claim needs to satisfy first (like email verification), before the next MFA challenge can display. This can happen if you configure the `backend`'s `checkAllowedToSetupFactorElseThrowInvalidClaimError` function to not allow a factor setup until the email has been verified. - -## Checking for factor setup + + Once the user has picked a specific factor (or if `next` contains only one item), you need to check if that factor has already been setup for that user. A factor is setup already if: - For `totp`: The user has already added a `totp` device and verified it. - For `otp-email`: The user has a passwordless `loginMethod` that has an email associated with it. @@ -2213,10 +2113,10 @@ In case the user does not have the factor setup, you need to ask them to set it - For `thirdparty`: Ask them to login using the third party provider. Once they login, a third party user is created and associated with their user object. In the later guides of this recipe, the use cases are described. If you want to know the status of any factor, you can get that by calling the [MFA Info endpoint](#mfa-info-endpoint). - + - + ## References @@ -2231,13 +2131,13 @@ This is an important endpoint which can be utilized to: Our pre-built UI uses this API automatically, but you can also always call this API manually if you are building a custom UI: - + - + - + - + ```tsx import MultifactorAuth from "supertokens-web-js/recipe/multifactorauth" @@ -2272,13 +2172,11 @@ async function fetchMFAInfo() { } ``` - + - + ```tsx -import supertokensMultiFactorAuth from "supertokens-web-js-script/recipe/multifactorauth" -import supertokensSession from "supertokens-web-js-script/recipe/session" async function fetchMFAInfo() { if (await supertokensSession.doesSessionExist()) { try { @@ -2308,9 +2206,9 @@ async function fetchMFAInfo() { } ``` - + - + - In the above code snippet, the list of factors which the user must complete next (in the `next` array) is retrieved along with all the relevant information to know what state each factor is in to decide if the user should be prompted to setup the factor (for example create a new TOTP device), or solve the auth challenge instead (for example, showing the enter TOTP screen). - The function is called `resyncSessionAndFetchMFAInfo` because it does two things: @@ -2318,22 +2216,21 @@ async function fetchMFAInfo() { - resynchronizes the value of the `v` and `c` in the session's MFA claim. - + - + - Call the following API when you want to know the status of any factor. Notice that the API call requires the session's access token as an input (this should be included by the frontend SDK automatically): ```bash -curl --location --request PUT '^{appInfo.apiDomain}^{appInfo.apiBasePath}/mfa/info' \ +curl --location --request PUT '/auth/mfa/info' \ --header 'Authorization: Bearer ...' ``` - + - + - The structure of the raw JSON response is as follows: ```json @@ -2373,16 +2270,13 @@ curl --location --request PUT '^{appInfo.apiDomain}^{appInfo.apiBasePath}/mfa/in - Another claim needs to satisfy first (like email verification), before the next MFA challenge can display. This can happen if you configure the `checkAllowedToSetupFactorElseThrowInvalidClaimError` function, on the backend, to not allow a factor setup until the email is verified. - - ### Handle support cases Some situations exist in which users may be locked out of their accounts and would need you to do certain steps to unlock their accounts. These cases are: - - -## `ERR_CODE_009` + + - This can happen when the second factor is `emailpassword`: - API Path is `/signin POST`. - Output JSON: @@ -2393,8 +2287,8 @@ These cases are: } ``` - This can happen if the email password account you are trying to do MFA with is not verified. - -## `ERR_CODE_010` + + - This can happen when the second factor is `emailpassword`: - API Path is `/signin POST`. - Output JSON: @@ -2405,8 +2299,8 @@ These cases are: } ``` - This can happen if the email password account you are trying to do MFA with is already linked to another primary user that is not equal to the session user. - -## `ERR_CODE_011` + + - This can happen when the second factor is `emailpassword`: - API Path is `/signin POST`. - Output JSON: @@ -2417,8 +2311,8 @@ These cases are: } ``` - This can happen if the email password account you are trying to do MFA cannot link to the session user because there already exists another primary user with the same email. - -## `ERR_CODE_012` + + - This can happen when the second factor is `emailpassword`: - API Path is `/signin POST`. - Output JSON: @@ -2429,8 +2323,8 @@ These cases are: } ``` - To link the email password user with the session user, it must be confirmed that the session user is a primary user. However, that can fail if there exists another primary user with the same email as the session user, and in this case, this error is sent to the frontend. - -## `ERR_CODE_013` + + - This can happen when the second factor is `emailpassword`: - API Path is `/signup POST`. - Output JSON: @@ -2444,9 +2338,9 @@ These cases are: - A user signs up with their phone number and OTP - Post sign up, they are prompted to add their email and a password for the account. In this case, since the entered email is not verified, this error will display. -- To resolve this, it is advised to change the flow to first ask the user to go through the email OTP flow post the first factor sign up, and then add a password to the account. This way, the email will be verified. - -## `ERR_CODE_014` +- To resolve this, it is advised to change the flow to first ask the user to go through the email OTP flow post the first factor sign up, and then add a password to the account. This way, the email will be verified. + + - This can happen when the second factor is `emailpassword`: - API Path is `/signup POST`. - Output JSON: @@ -2462,8 +2356,8 @@ These cases are: - The user logs out, and then creates a social login account with email `e1`. Then, they are prompted to add a password to this account. Since an email password account with `e1` already exists, SuperTokens will try and link that to this new account, but fail, since the email password account with `e1` is already a primary user. - To resolve this, it is advised to manually link the `e1` social login account with the `e1` email password account. Or you can enable automatic account linking for first factor and this way, the above scenario will not happen. - -## `ERR_CODE_015` + + - This can happen when the second factor is `emailpassword`: - API Path is `/signup POST`. - Output JSON: @@ -2480,8 +2374,8 @@ These cases are: - This will cause this type of error since the linking of the new social login and email account will fail since there already exists another primary user with the same (`e1`) email. - To resolve this, it is advised not allowing users to specify an email when asking them to add a password for their account. - -## `ERR_CODE_016` + + - This can happen when the second factor is `emailpassword`: - API Path is `/signup POST`. - Output JSON: @@ -2497,8 +2391,8 @@ These cases are: - The user logs out and creates another social login account with email `e1` (say `GitHub`), and then tries and adds a password to this account with email `e1`. Here, SuperTokens will try and make the `GitHub` login a primary user, but fail, since the email `e1` is already a primary user (with Google login). - To resolve this, it is advised to manually link the `e1` `GitHub` social login account with the `e1` Google social login account. Or you can enable automatic account linking for first factor and this way, the above scenario will not happen. - -## `ERR_CODE_017` + + - This can happen when the second factor relies on the passwordless recipe. - API Path is `/signinup/code/consume POST`. - Output JSON: @@ -2509,8 +2403,8 @@ These cases are: } ``` - This can happen when the passwordless account is trying to link to the account of the first factor, but it can't because the passwordless account is already linked with another primary user. - -## `ERR_CODE_018` + + - This can happen when the second factor relies on the passwordless recipe. - API Path is `/signinup/code/consume POST`. - Output JSON: @@ -2521,8 +2415,8 @@ These cases are: } ``` - This can happen when the passwordless account is trying to link to the account of the first factor, but it can't because there exists another primary user with the same email as the passwordless account. - -## `ERR_CODE_019` + + - This can happen when the second factor relies on the passwordless recipe. - API Path is `/signinup/code POST` or `/signinup/code/consume POST`. - Output JSON: @@ -2533,6 +2427,7 @@ These cases are: } ``` - This can happen when the passwordless account is trying to link to the account of the first factor, but, the first factor account cannot become a primary user because there exists another account with the same email as the first factor user account which is already primary. + @@ -2562,11 +2457,10 @@ SuperTokens enforces that a user has completed all the required factors by keepi ## See also - - - - - - - - + + + + + + + diff --git a/docs/additional-verification/mfa/introduction.mdx b/docs/additional-verification/mfa/introduction.mdx index 3a47e4a51b..dcba1f2431 100644 --- a/docs/additional-verification/mfa/introduction.mdx +++ b/docs/additional-verification/mfa/introduction.mdx @@ -1,19 +1,10 @@ --- -sidebar_position: 1 title: Introduction -hide_title: true -skip_llms_txt: true -description: >- - Implement multi-factor authentication with email, SMS, or TOTP, and customize - user authentication preferences. -page_type: overview -recipe: mfa -category: multi-factor-authentication +description: Implement multi-factor authentication with email, SMS, or TOTP, and customize user authentication preferences. +sidebar: + order: 1 --- - -# Multi-factor authentication - ## Overview Multi-factor authentication (MFA) is a security process that requires users to verify their identity through multiple forms of credentials before gaining access to a system. @@ -21,7 +12,9 @@ Multi-factor authentication (MFA) is a security process that requires users to v ## Prerequisites - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: Magic link via email or SMS is only supported as a first factor for pre-built UI. It will not work as a second factor because if the magic link is opened on a different device, there would be no reference to the existing session (which was created before first factor completion). @@ -42,95 +35,43 @@ Besides that, you can check the initial quickstart guide for step-by-step instru Before you explore a guide, read through the **Important Concepts** page first. It explains multiple topics that get used in each tutorial. - - - - Important Concepts - - - Go through a quick explanation of how MFA works and some common terminologies. - - - - - Quickstart Guide - - - Implement an authentication flow that uses MFA. - - - - - Implement Step Up Authentication - - - Require additional authentication challenges on specific routes or actions. - - - - - Implement Recovery Codes - - - Allow users to recover their account if they lose access to one of the factors. - - - + + +Go through a quick explanation of how MFA works and some common terminologies. + + +Implement an authentication flow that uses MFA. + + +Require additional authentication challenges on specific routes or actions. + + +Allow users to recover their account if they lose access to one of the factors. + + ## Customization To adjust the functionality to fit your use case you can explore different sections from the documentation. - - - - Require TOTP for all users - - - Force all users to use TOTP. - - - - - Require TOTP for specific users - - - Enable TOTP only for some of the users. - - - - - Require OTP for all users - - - Force all users to use OTP. - - - - - Require OTP for specific users - - - Enable OTP only for some of the users. - - - - - WebAuthn - - - Use WebAuthn as a secondary factor - - - - - Protect frontend and backend routes - - - Check for the MFA status on specific routes. - - - - - + + +Force all users to use TOTP. + + +Enable TOTP only for some of the users. + + +Force all users to use OTP. + + +Enable OTP only for some of the users. + + +Use WebAuthn as a secondary factor + + +Check for the MFA status on specific routes. + + diff --git a/docs/additional-verification/mfa/legacy-mfa/_category_.json b/docs/additional-verification/mfa/legacy-mfa/_category_.json deleted file mode 100644 index cb389d680e..0000000000 --- a/docs/additional-verification/mfa/legacy-mfa/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Legacy method", - "position": 11 -} diff --git a/docs/additional-verification/mfa/legacy-mfa/backend-setup/_category_.json b/docs/additional-verification/mfa/legacy-mfa/backend-setup/_category_.json deleted file mode 100644 index f540a9b0d8..0000000000 --- a/docs/additional-verification/mfa/legacy-mfa/backend-setup/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Backend Setup", - "position": 3 -} diff --git a/docs/additional-verification/mfa/legacy-mfa/backend-setup/first-factor.mdx b/docs/additional-verification/mfa/legacy-mfa/backend-setup/first-factor.mdx index 6f97e59b81..a597db04a9 100644 --- a/docs/additional-verification/mfa/legacy-mfa/backend-setup/first-factor.mdx +++ b/docs/additional-verification/mfa/legacy-mfa/backend-setup/first-factor.mdx @@ -1,32 +1,22 @@ --- -id: first-factor title: Setting up the first factor -hide_title: true -sidebar_position: 1 -description: >- - Set up the first authentication factor using SuperTokens with various - frameworks. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Set up the first authentication factor using SuperTokens with various frameworks. +sidebar: + order: 1 --- - -# Setting up the 1st factor - ## 1. Initialisation Start by following the recipe guide for the first factor. In this guide, we will take the example of `thirdparty` and `emailpassword` recipes as being the first factor. -After following the [backend quick setup section](/docs/quickstart/backend-setup) (or any of the framework specific integration guides), you should have all the auth APIs exposed to the frontend via the SuperTokens middleware. The `supertokens.init` code on the server would look like this: +After following the [backend quick setup section](/quickstart/backend-setup) (or any of the framework specific integration guides), you should have all the auth APIs exposed to the frontend via the SuperTokens middleware. The `supertokens.init` code on the server would look like this: - - - + + - - + + ```tsx import supertokens from "supertokens-node"; @@ -38,16 +28,16 @@ import EmailPassword from "supertokens-node/recipe/emailpassword" supertokens.init({ framework: "express", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ ThirdParty.init({ @@ -61,9 +51,9 @@ supertokens.init({ ] }); ``` - + - + ```tsx import supertokens from "supertokens-node"; @@ -75,16 +65,16 @@ import EmailPassword from "supertokens-node/recipe/emailpassword" supertokens.init({ framework: "hapi", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ ThirdParty.init({ @@ -98,9 +88,9 @@ supertokens.init({ ] }); ``` - + - + ```tsx import supertokens from "supertokens-node"; @@ -112,16 +102,16 @@ import EmailPassword from "supertokens-node/recipe/emailpassword" supertokens.init({ framework: "fastify", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ ThirdParty.init({ @@ -135,9 +125,9 @@ supertokens.init({ ] }); ``` - + - + ```tsx import supertokens from "supertokens-node"; @@ -149,16 +139,16 @@ import EmailPassword from "supertokens-node/recipe/emailpassword" supertokens.init({ framework: "koa", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ ThirdParty.init({ @@ -172,9 +162,9 @@ supertokens.init({ ] }); ``` - + - + ```tsx import supertokens from "supertokens-node"; @@ -186,16 +176,16 @@ import EmailPassword from "supertokens-node/recipe/emailpassword" supertokens.init({ framework: "loopback", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ ThirdParty.init({ @@ -209,34 +199,34 @@ supertokens.init({ ] }); ``` - -// + +// // -// :::important +// :::note // Please refer the **serverless deployment** section in the ThirdParty + EmailPassword recipe guide // ::: // -// -// +// +// // -// :::important +// :::note // Please refer the **NextJS** section in the ThirdParty + EmailPassword recipe guide // ::: // -// -// +// +// // -// :::important +// :::note // Please refer the **NestJS** section in the ThirdParty + EmailPassword recipe guide // ::: // -// - - +// + + - + -```go showAppTypeSelect +```go import ( "github.com/supertokens/supertokens-golang/recipe/emailpassword" "github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels" @@ -248,17 +238,17 @@ import ( ) func main() { - apiBasePath := "^{appInfo.apiBasePath}" - websiteBasePath := "^{appInfo.websiteBasePath}" + apiBasePath := "/auth" + websiteBasePath := "/auth" err := supertokens.Init(supertokens.TypeInput{ Supertokens: &supertokens.ConnectionInfo{ - ConnectionURI: "^{coreInfo.uri}", - APIKey: "^{coreInfo.key}", + ConnectionURI: "", + APIKey: "", }, AppInfo: supertokens.AppInfo{ - AppName: "^{appInfo.appName}", - APIDomain: "^{appInfo.apiDomain}", - WebsiteDomain: "^{appInfo.websiteDomain}", + AppName: "", + APIDomain: "", + WebsiteDomain: "", APIBasePath: &apiBasePath, WebsiteBasePath: &websiteBasePath, }, @@ -275,11 +265,11 @@ func main() { } } ``` - - + + - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -287,15 +277,15 @@ from supertokens_python.recipe import thirdparty, emailpassword, session, userme init( app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" ), supertokens_config=SupertokensConfig( - connection_uri="^{coreInfo.uri}", - api_key="^{coreInfo.key}" + connection_uri="", + api_key="" ), framework='fastapi', recipe_list=[ @@ -312,8 +302,8 @@ init( ) ``` - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -321,15 +311,15 @@ from supertokens_python.recipe import thirdparty, emailpassword, session, userme init( app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" ), supertokens_config=SupertokensConfig( - connection_uri="^{coreInfo.uri}", - api_key="^{coreInfo.key}" + connection_uri="", + api_key="" ), framework='flask', recipe_list=[ @@ -345,8 +335,8 @@ init( ) ``` - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -354,15 +344,15 @@ from supertokens_python.recipe import thirdparty, emailpassword, session, userme init( app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" ), supertokens_config=SupertokensConfig( - connection_uri="^{coreInfo.uri}", - api_key="^{coreInfo.key}" + connection_uri="", + api_key="" ), framework='django', recipe_list=[ @@ -379,23 +369,22 @@ init( ) ``` - - - - + + + + -:::important -You should have also added the SuperTokens `middleware` and `errorHandler` (depending on your framework) to your application. We are not showing it in the above code snippet for brevity, but it is explained in the ThirdParty + EmailPassword recipe guide. +:::note[You should have also added the SuperTokens `middleware` and `errorHandler` (depending on your framework) to your application. We are not showing it in the above code snippet for brevity, but it is explained in the ThirdParty + EmailPassword recipe guide.] ::: ## 2. Adding second factor claim After sign up or sign in of the first factor, the existence of the session signifies the completion of the first factor, but we want to explicitly mark the second factor as incomplete. This can be done by overriding the `createNewSession` function in the `Session.init` config: - - + + -```tsx +```tsx {8,9,10,11,24} import Session from "supertokens-node/recipe/session"; import { BooleanClaim } from "supertokens-node/recipe/session/claims"; @@ -403,12 +392,10 @@ import { BooleanClaim } from "supertokens-node/recipe/session/claims"; This will be used to modify the session's access token payload to add {"2fa-completed": false} into it. */ -// highlight-start export const SecondFactorClaim = new BooleanClaim({ fetchValue: () => false, key: "2fa-completed", }); -// highlight-end Session.init({ override: { @@ -421,7 +408,6 @@ Session.init({ ...input, accessTokenPayload: { ...input.accessTokenPayload, - // highlight-next-line ...(await SecondFactorClaim.build(input.userId, input.recipeUserId, input.tenantId, undefined, input.userContext)), }, }); @@ -432,10 +418,10 @@ Session.init({ }) ``` - - + + -```go +```go {9,10,11,19,20,21,22,23,24,25} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/claims" @@ -444,11 +430,9 @@ import ( ) func main() { - // highlight-start SecondFactorClaim, _ := claims.BooleanClaim("2fa-completed", func(userId, tenantId string, userContext supertokens.UserContext) (interface{}, error) { return false, nil }, nil) - // highlight-end session.Init(&sessmodels.TypeInput{ Override: &sessmodels.OverrideStruct{ @@ -456,7 +440,6 @@ func main() { oCreateNewSession := *originalImplementation.CreateNewSession /* This function is called after signing in or signing up via the first factor */ (*originalImplementation.CreateNewSession) = func(userID string, accessTokenPayload, sessionDataInDatabase map[string]interface{}, disableAntiCsrf *bool, tenantId string, userContext supertokens.UserContext) (sessmodels.SessionContainer, error) { - // highlight-start if accessTokenPayload == nil { accessTokenPayload = map[string]interface{}{} } @@ -464,7 +447,6 @@ func main() { if err != nil { return nil, err } - // highlight-end return oCreateNewSession(userID, accessTokenPayload, sessionDataInDatabase, disableAntiCsrf, tenantId, userContext) } return originalImplementation @@ -474,10 +456,10 @@ func main() { } ``` - - + + -```python +```python {9,10,11,31,58} from supertokens_python.recipe import session from supertokens_python.recipe.session.claims import BooleanClaim from supertokens_python.recipe.session.interfaces import RecipeInterface @@ -486,11 +468,9 @@ from supertokens_python.types import RecipeUserId # This will be used to modify the session's access token payload # to add {"2fa-completed": false} into it. -# highlight-start SecondFactorClaim = BooleanClaim( key="2fa-completed", fetch_value=lambda _, __, ___, ____, _____: False ) -# highlight-end def override_session_functions(original_implementation: RecipeInterface): @@ -510,7 +490,6 @@ def override_session_functions(original_implementation: RecipeInterface): if access_token_payload is None: access_token_payload = {} - # highlight-next-line access_token_payload = { **access_token_payload, **( @@ -538,12 +517,11 @@ def override_session_functions(original_implementation: RecipeInterface): session.init( - # highlight-next-line override=session.InputOverrideConfig(functions=override_session_functions) ) ``` - - + + We add `SecondFactorClaim` into the access token payload. This will be set to false on session creation (see `fetchValue` in the claim definition). diff --git a/docs/additional-verification/mfa/legacy-mfa/backend-setup/meta.ts b/docs/additional-verification/mfa/legacy-mfa/backend-setup/meta.ts new file mode 100644 index 0000000000..1fa5d710ae --- /dev/null +++ b/docs/additional-verification/mfa/legacy-mfa/backend-setup/meta.ts @@ -0,0 +1,6 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Backend Setup", + "order": 3 +}); diff --git a/docs/additional-verification/mfa/legacy-mfa/backend-setup/protecting-api.mdx b/docs/additional-verification/mfa/legacy-mfa/backend-setup/protecting-api.mdx index 8b81838de0..ef6dc7c6bb 100644 --- a/docs/additional-verification/mfa/legacy-mfa/backend-setup/protecting-api.mdx +++ b/docs/additional-verification/mfa/legacy-mfa/backend-setup/protecting-api.mdx @@ -1,32 +1,21 @@ --- -id: protecting-api title: Protecting API routes -hide_title: true -sidebar_position: 3 -description: >- - Protect API routes by enforcing 2FA using session claim validators in various - programming languages. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Protect API routes by enforcing 2FA using session claim validators in various programming languages. +sidebar: + order: 3 --- - -# Protecting API routes - In the previous steps, we saw the a session is created after the first factor, with `SecondFactorClaim` set to false, and then after the second factor is completed, we update that value to true. ## 1. Protecting all APIs We want to protect all the application APIs such that they are accessible only when `SecondFactorClaim` is `true` - indicating that the user has completed 2FA. We can do this by by overriding the `getGlobalClaimValidators` function in the Session recipe. - - + + ```tsx import Session from "supertokens-node/recipe/session"; -import { BooleanClaim } from "supertokens-node/recipe/session/claims"; // REMOVE_FROM_OUTPUT -declare const SecondFactorClaim: BooleanClaim; // REMOVE_FROM_OUTPUT Session.init({ override: { @@ -44,10 +33,10 @@ Session.init({ ``` - - + + -```go +```go {10,11,12,18,19,20,21,22} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/claims" @@ -57,23 +46,19 @@ import ( func main() { - // highlight-start _, SecondFactorClaimValidator := claims.BooleanClaim("2fa-completed", func(userId, tenantId string, userContext supertokens.UserContext) (interface{}, error) { return false, nil }, nil) - // highlight-end session.Init(&sessmodels.TypeInput{ Override: &sessmodels.OverrideStruct{ Functions: func(originalImplementation sessmodels.RecipeInterface) sessmodels.RecipeInterface { - // highlight-start (*originalImplementation.GetGlobalClaimValidators) = func(userId string, claimValidatorsAddedByOtherRecipes []claims.SessionClaimValidator, tenantId string, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { claimValidatorsAddedByOtherRecipes = append(claimValidatorsAddedByOtherRecipes, SecondFactorClaimValidator.HasValue(true, nil, nil)) return claimValidatorsAddedByOtherRecipes, nil } - // highlight-end return originalImplementation }, @@ -82,10 +67,10 @@ func main() { } ``` - - + + -```python +```python {17,18,19,20,21,22,23,24,25,26,27} from typing import List, Dict, Any from supertokens_python.recipe.session.claims import BooleanClaim from supertokens_python.recipe import session @@ -102,7 +87,6 @@ SecondFactorClaim = BooleanClaim( def override_session_functions(original_implementation: RecipeInterface): - # highlight-start async def get_global_claim_validators( tenant_id: str, user_id: str, @@ -114,7 +98,6 @@ def override_session_functions(original_implementation: RecipeInterface): SecondFactorClaim.validators.has_value(True) ] - # highlight-end original_implementation.get_global_claim_validators = get_global_claim_validators return original_implementation @@ -123,41 +106,37 @@ def override_session_functions(original_implementation: RecipeInterface): session.init(override=session.InputOverrideConfig(override_session_functions)) ``` - - + + ## 2. Protecting specific API routes If instead, you want to enforce 2FA on certain API routes, you can add the validator only when calling the `verifySession` function: - - + + -```tsx +```tsx {8,9,10,11} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; -import { BooleanClaim } from "supertokens-node/recipe/session/claims"; // REMOVE_FROM_OUTPUT -declare const SecondFactorClaim: BooleanClaim; // REMOVE_FROM_OUTPUT let app = express(); app.post("/like-comment", verifySession({ - // highlight-start overrideGlobalClaimValidators: (globalValidators) => [ ...globalValidators, SecondFactorClaim.validators.hasValue(true), ] - // highlight-end }), (req: SessionRequest, res) => { //.... }); ``` - - + + -```go +```go {11,12,13,21,22,23,24,25} import ( "net/http" @@ -168,11 +147,9 @@ import ( ) func main() { - // highlight-start _, SecondFactorClaimValidator := claims.BooleanClaim("2fa-completed", func(userId, tenantId string, userContext supertokens.UserContext) (interface{}, error) { return false, nil }, nil) - // highlight-end http.ListenAndServe("SERVER ADDRESS", corsMiddleware( supertokens.Middleware(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { @@ -180,13 +157,11 @@ func main() { if r.URL.Path == "/like-comment" { session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, SecondFactorClaimValidator.HasValue(true, nil, nil)) return globalClaimValidators, nil }, - // highlight-end }, likeCommentAPI).ServeHTTP(rw, r) return } @@ -203,10 +178,10 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { // If it comes here, the user has completed 2fa. } ``` - - + + -```python +```python {15,16,17} from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.session import SessionContainer from fastapi import Depends @@ -217,15 +192,13 @@ SecondFactorClaim = BooleanClaim( ) -@app.post("/like_comment") # type: ignore +@app.post("/like_comment") async def like_comment( session: SessionContainer = Depends( verify_session( - # highlight-start # We add the SecondFactorClaim's has_value(True) validator override_global_claim_validators=lambda global_validators, session, user_context: global_validators + [SecondFactorClaim.validators.has_value(True)] - # highlight-end ) ) ): @@ -234,9 +207,9 @@ async def like_comment( ``` - - + + -:::info Important +:::info[Important] If the `SecondFactorClaim` claim validator fails, then the SDK will send a `403` response. ::: diff --git a/docs/additional-verification/mfa/legacy-mfa/backend-setup/second-factor.mdx b/docs/additional-verification/mfa/legacy-mfa/backend-setup/second-factor.mdx index 25975f66a8..f40e5b5911 100644 --- a/docs/additional-verification/mfa/legacy-mfa/backend-setup/second-factor.mdx +++ b/docs/additional-verification/mfa/legacy-mfa/backend-setup/second-factor.mdx @@ -1,34 +1,24 @@ --- -id: second-factor title: Setting up the second factor -hide_title: true -sidebar_position: 2 -description: >- - Configure SMS OTP as a second authentication factor using the Passwordless - recipe. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Configure SMS OTP as a second authentication factor using the Passwordless recipe. +sidebar: + order: 2 --- - -# Setting up the 2nd factor - ## 1. Initialisation We use the [Passwordless recipe](https://supertokens.com/docs/passwordless/introduction) with SMS OTP as the second factor. You can follow the recipe's [backend quick setup guide](https://supertokens.com/docs/passwordless/quick-setup/backend) to configure a different method as well (for example with email magic links). The `Passwordless.init` function should look something like this: - - - + + - - + + -```tsx +```tsx {22,23,24,25} import supertokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -38,24 +28,22 @@ import Passwordless from "supertokens-node/recipe/passwordless" supertokens.init({ framework: "express", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ - // highlight-start Passwordless.init({ flowType: "USER_INPUT_CODE", contactMethod: "PHONE" }), - // highlight-end ThirdParty.init({ //... }), @@ -66,11 +54,11 @@ supertokens.init({ ] }); ``` - + - + -```tsx +```tsx {22,23,24,25} import supertokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -80,24 +68,22 @@ import Passwordless from "supertokens-node/recipe/passwordless" supertokens.init({ framework: "hapi", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ - // highlight-start Passwordless.init({ flowType: "USER_INPUT_CODE", contactMethod: "PHONE" }), - // highlight-end ThirdParty.init({ //... }), @@ -108,11 +94,11 @@ supertokens.init({ ] }); ``` - + - + -```tsx +```tsx {22,23,24,25} import supertokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -122,24 +108,22 @@ import Passwordless from "supertokens-node/recipe/passwordless" supertokens.init({ framework: "fastify", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ - // highlight-start Passwordless.init({ flowType: "USER_INPUT_CODE", contactMethod: "PHONE" }), - // highlight-end ThirdParty.init({ //... }), @@ -150,11 +134,11 @@ supertokens.init({ ] }); ``` - + - + -```tsx +```tsx {22,23,24,25} import supertokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -164,24 +148,22 @@ import Passwordless from "supertokens-node/recipe/passwordless" supertokens.init({ framework: "koa", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ - // highlight-start Passwordless.init({ flowType: "USER_INPUT_CODE", contactMethod: "PHONE" }), - // highlight-end ThirdParty.init({ //... }), @@ -192,11 +174,11 @@ supertokens.init({ ] }); ``` - + - + -```tsx +```tsx {22,23,24,25} import supertokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -206,24 +188,22 @@ import Passwordless from "supertokens-node/recipe/passwordless" supertokens.init({ framework: "loopback", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ - // highlight-start Passwordless.init({ flowType: "USER_INPUT_CODE", contactMethod: "PHONE" }), - // highlight-end ThirdParty.init({ //... }), @@ -234,33 +214,30 @@ supertokens.init({ ] }); ``` - - + + -:::important -Please refer the **serverless deployment** section in the Passwordless recipe guide +:::note[Please refer the **serverless deployment** section in the Passwordless recipe guide] ::: - - + + -:::important -Please refer the **NextJS** section in the Passwordless recipe guide +:::note[Please refer the **NextJS** section in the Passwordless recipe guide] ::: - - + + -:::important -Please refer the **NestJS** section in the Passwordless recipe guide +:::note[Please refer the **NestJS** section in the Passwordless recipe guide] ::: - - - - + + + + -```go showAppTypeSelect +```go {29,30,31,32,33,34} import ( "github.com/supertokens/supertokens-golang/recipe/emailpassword" "github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels" @@ -274,29 +251,27 @@ import ( ) func main() { - apiBasePath := "^{appInfo.apiBasePath}" - websiteBasePath := "^{appInfo.websiteBasePath}" + apiBasePath := "/auth" + websiteBasePath := "/auth" err := supertokens.Init(supertokens.TypeInput{ Supertokens: &supertokens.ConnectionInfo{ - ConnectionURI: "^{coreInfo.uri}", - APIKey: "^{coreInfo.key}", + ConnectionURI: "", + APIKey: "", }, AppInfo: supertokens.AppInfo{ - AppName: "^{appInfo.appName}", - APIDomain: "^{appInfo.apiDomain}", - WebsiteDomain: "^{appInfo.websiteDomain}", + AppName: "", + APIDomain: "", + WebsiteDomain: "", APIBasePath: &apiBasePath, WebsiteBasePath: &websiteBasePath, }, RecipeList: []supertokens.Recipe{ - // highlight-start passwordless.Init(plessmodels.TypeInput{ FlowType: "USER_INPUT_CODE", ContactMethodPhone: plessmodels.ContactMethodPhoneConfig{ Enabled: true, }, }), - // highlight-end thirdparty.Init(&tpmodels.TypeInput{ /*...*/ }), emailpassword.Init(&epmodels.TypeInput{ /*...*/ }), session.Init(&sessmodels.TypeInput{ @@ -310,27 +285,27 @@ func main() { } } ``` - - - - + + + + -```python +```python {26,27,28,29} from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import thirdparty, emailpassword, session, passwordless from supertokens_python.recipe.passwordless import ContactPhoneOnlyConfig init( app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" ), supertokens_config=SupertokensConfig( - connection_uri="^{coreInfo.uri}", - api_key="^{coreInfo.key}" + connection_uri="", + api_key="" ), framework='fastapi', recipe_list=[ @@ -341,36 +316,34 @@ init( emailpassword.init( # ... ), - # highlight-start passwordless.init( flow_type="USER_INPUT_CODE", contact_config=ContactPhoneOnlyConfig() ) - # highlight-end ], mode='asgi' # use wsgi if you are running using gunicorn ) ``` - - + + -```python +```python {26,27,28,29} from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import thirdparty, emailpassword, session, passwordless from supertokens_python.recipe.passwordless import ContactPhoneOnlyConfig init( app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" ), supertokens_config=SupertokensConfig( - connection_uri="^{coreInfo.uri}", - api_key="^{coreInfo.key}" + connection_uri="", + api_key="" ), framework='flask', recipe_list=[ @@ -381,35 +354,33 @@ init( emailpassword.init( # ... ), - # highlight-start passwordless.init( flow_type="USER_INPUT_CODE", contact_config=ContactPhoneOnlyConfig() ) - # highlight-end ] ) ``` - - + + -```python +```python {26,27,28,29} from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import thirdparty, emailpassword, session, passwordless from supertokens_python.recipe.passwordless import ContactPhoneOnlyConfig init( app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" ), supertokens_config=SupertokensConfig( - connection_uri="^{coreInfo.uri}", - api_key="^{coreInfo.key}" + connection_uri="", + api_key="" ), framework='django', recipe_list=[ @@ -420,21 +391,19 @@ init( emailpassword.init( # ... ), - # highlight-start passwordless.init( flow_type="USER_INPUT_CODE", contact_config=ContactPhoneOnlyConfig() ) - # highlight-end ], mode='asgi' # use wsgi if you are running django server in sync mode ) ``` - - - - + + + + The above exposes all the APIs to the frontend that can be used to create and verify the OTP. @@ -442,14 +411,13 @@ The above exposes all the APIs to the frontend that can be used to create and ve During sign up, once the user has completed the second factor, we want to save their phone number against their profile. For this, we use the `UserMetadata` recipe. -:::important -Make sure to add the User Metadata in the recipe list. +:::note[Make sure to add the User Metadata in the recipe list.] ::: The passwordless recipe creates a new `userId` for the user against which it saves the phone number. We can associate the passwordless `userId` with the `userId` of the first factor, and this way, we associate a phone number to the user: - - + + ```tsx import Session from "supertokens-node/recipe/session"; @@ -494,8 +462,8 @@ Passwordless.init({ }) ``` - - + + ```go import ( @@ -558,8 +526,8 @@ func main() { } ``` - - + + ```python from supertokens_python.recipe.passwordless.interfaces import APIInterface, APIOptions, ConsumeCodePostOkResult @@ -625,8 +593,8 @@ passwordless.init( ) ``` - - + + ## 3. Updating the session post second factor auth @@ -634,15 +602,13 @@ We also want to change the session's payload to indicate that the user has compl We also have to be careful about not creating a new session after the second factor auth is completed. By default, the passwordless recipe creates a new session on successful verification, overwriting the older one. We can prevent this, by using the `userContext` feature: - - + + -```tsx +```tsx {21,22,23,28,29,30,31,58,59,60,61,62,63,64} import Session from "supertokens-node/recipe/session"; import UserMetadata from "supertokens-node/recipe/usermetadata"; import Passwordless from "supertokens-node/recipe/passwordless"; -import { BooleanClaim } from "supertokens-node/recipe/session/claims"; // REMOVE_FROM_OUTPUT -declare const SecondFactorClaim: BooleanClaim; // REMOVE_FROM_OUTPUT Passwordless.init({ flowType: "USER_INPUT_CODE", @@ -660,21 +626,17 @@ Passwordless.init({ overrideGlobalClaimValidators: () => [], }); - // highlight-start // we add the existing session to the user context so that the createNewSession // function doesn't create a new session input.userContext.session = session; - // highlight-end let resp = await oI.consumeCodePOST!(input); if (resp.status === "OK") { - // highlight-start // OTP verification was successful. // We can now set the SecondFactorClaim in the session to true. // the user has access to API routes and the frontend UI await resp.session.setClaimValue(SecondFactorClaim, true); - // highlight-end // We can now associate // the passwordless user ID with the thirdpartyemailpassword @@ -701,7 +663,6 @@ Session.init({ ...originalImplementation, /* This function is called after signing in or signing up via the first factor */ createNewSession: async function (input) { - // highlight-start if (input.userContext.session !== undefined) { /** * This is true for the second factor login. @@ -709,7 +670,6 @@ Session.init({ */ return input.userContext.session; } - // highlight-end return originalImplementation.createNewSession({ ...input, accessTokenPayload: { @@ -724,10 +684,10 @@ Session.init({ }) ``` - - + + -```go +```go {12,13,14,39,40,41,49,50,51,52,78,79,80,81,82,83,84} import ( "github.com/supertokens/supertokens-golang/recipe/passwordless" "github.com/supertokens/supertokens-golang/recipe/passwordless/plessmodels" @@ -739,11 +699,9 @@ import ( ) func main() { - // highlight-start SecondFactorClaim, _ := claims.BooleanClaim("2fa-completed", func(userId, tenantId string, userContext supertokens.UserContext) (interface{}, error) { return false, nil }, nil) - // highlight-end passwordless.Init(plessmodels.TypeInput{ FlowType: "USER_INPUT_CODE", @@ -768,11 +726,9 @@ func main() { return plessmodels.ConsumeCodePOSTResponse{}, err } - // highlight-start // we add the existing session to the user context so that the createNewSession // function doesn't create a new session (*userContext)["session"] = session - // highlight-end resp, err := oConsumeCodePOST(userInput, linkCode, preAuthSessionID, tenantId, options, userContext) if err != nil { @@ -780,12 +736,10 @@ func main() { } if resp.OK != nil { - // highlight-start // OTP verification was successful. We can now mark the // session's payload as is2faComplete: true so that // the user has access to API routes and the frontend UI resp.OK.Session.SetClaimValue(SecondFactorClaim, true) - // highlight-end // We can now associate // the passwordless user ID with the thirdpartyemailpassword @@ -811,7 +765,6 @@ func main() { oCreateNewSession := *originalImplementation.CreateNewSession /* This function is called after signing in or signing up via the first factor */ (*originalImplementation.CreateNewSession) = func(userID string, accessTokenPayload, sessionDataInDatabase map[string]interface{}, disableAntiCsrf *bool, tenantId string, userContext supertokens.UserContext) (sessmodels.SessionContainer, error) { - // highlight-start if session, ok := (*userContext)["session"].(sessmodels.SessionContainer); ok { /** * This will be true for the second factor login. @@ -819,7 +772,6 @@ func main() { */ return session, nil } - // highlight-end if accessTokenPayload == nil { accessTokenPayload = map[string]interface{}{} @@ -837,10 +789,10 @@ func main() { } ``` - - + + -```python +```python {48,63,64,65,66,97,98,99,100,101} from supertokens_python.recipe.passwordless.interfaces import ( APIInterface, APIOptions, @@ -888,7 +840,6 @@ def override_passwordless_apis(original_implementation: APIInterface): # we should add the existing session to the user_context # so that the create_new_session function # doesn't create a new session - # highlight-next-line user_context["session"] = _session res = await original_consume_code_post( @@ -904,12 +855,10 @@ def override_passwordless_apis(original_implementation: APIInterface): ) if isinstance(res, ConsumeCodePostOkResult): - # highlight-start # OTP verification was successful. We can now mark the # session's payload as {"is2faComplete": True} so that # the user has access to API routes and the frontend UI await _session.set_claim_value(SecondFactorClaim, True) - # highlight-end # We can now associate # the passwordless user ID with the thirdpartyemailpassword @@ -940,13 +889,11 @@ def override_session_functions(original_implementation: RecipeInterface): # This function is called after signing in or # signing up via the first factor - # highlight-start _session = user_context.get("session") if _session and isinstance(_session, SessionContainer): # This is true for the second factor login. # So instead of creating a new session, we return the already existing one. return _session - # highlight-end if access_token_payload is None: access_token_payload = {} @@ -977,8 +924,8 @@ def override_session_functions(original_implementation: RecipeInterface): return original_implementation ``` - - + + ## 4. Validating the phone number @@ -990,8 +937,8 @@ By default, the Passwordless API for sending an OTP (`createCodePOST`) sends the To make it secure, we override the `createCodePOST` API and check that the input phone number is the same as the phone number associated with the user. If it's not the same, we throw an error, and if it is the same, we continue: - - + + ```tsx import Session from "supertokens-node/recipe/session"; @@ -1057,10 +1004,10 @@ Passwordless.init({ }) ``` - - + + -```go +```go {23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67} import ( "errors" @@ -1083,7 +1030,6 @@ func main() { APIs: func(originalImplementation plessmodels.APIInterface) plessmodels.APIInterface { /*This API is called to send an OTP*/ oCreateCodePOST := *originalImplementation.CreateCodePOST - // highlight-start nCreateCodePOST := func(email *string, phoneNumber *string, tenantId string, options plessmodels.APIOptions, userContext supertokens.UserContext) (plessmodels.CreateCodePOSTResponse, error) { /** * We want to make sure that the OTP being generated is for the @@ -1129,7 +1075,6 @@ func main() { return oCreateCodePOST(email, phoneNumber, tenantId, options, userContext) } - // highlight-end *originalImplementation.CreateCodePOST = nCreateCodePOST oConsumeCodePOST := *originalImplementation.ConsumeCodePOST @@ -1148,10 +1093,10 @@ func main() { } ``` - - + + -```python +```python {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66} from supertokens_python.recipe.passwordless.interfaces import APIInterface, APIOptions from typing import Union, Dict, Any, Optional from supertokens_python.recipe.session.asyncio import get_session @@ -1164,7 +1109,6 @@ def override_passwordless_apis(original_implementation: APIInterface): original_consume_code_post = original_implementation.consume_code_post original_create_code_post = original_implementation.create_code_post - # highlight-start async def create_code_post( email: Union[str, None], phone_number: Union[str, None], @@ -1219,7 +1163,6 @@ def override_passwordless_apis(original_implementation: APIInterface): user_context, ) - # highlight-end async def consume_code_post( pre_auth_session_id: str, @@ -1252,8 +1195,8 @@ def override_passwordless_apis(original_implementation: APIInterface): return original_implementation ``` - - + + ## 5. Storing the user's phone number in the session @@ -1261,15 +1204,13 @@ When the session is first created (after the first factor is completed), we stor We do this by modifying the `createNewSession` function in the `Session.init` call: - - + + -```tsx +```tsx {20,21,22,23,24,25,26,27,28,29,30,31,38} import Session from "supertokens-node/recipe/session"; import UserMetadata from "supertokens-node/recipe/usermetadata"; import SuperTokens from "supertokens-node"; -import { BooleanClaim } from "supertokens-node/recipe/session/claims"; // REMOVE_FROM_OUTPUT -declare const SecondFactorClaim: BooleanClaim; // REMOVE_FROM_OUTPUT Session.init({ override: { @@ -1286,7 +1227,6 @@ Session.init({ return input.userContext.session; } - // highlight-start // we first get the passwordless userId associated with this user // using the UserMetadata recipe let userMetadata = await UserMetadata.getUserMetadata(input.userId); @@ -1299,14 +1239,12 @@ Session.init({ ); phoneNumber = passwordlessUserInfo?.phoneNumbers[0]; } - // highlight-end return originalImplementation.createNewSession({ ...input, accessTokenPayload: { ...input.accessTokenPayload, ...(await SecondFactorClaim.build(input.userId, input.recipeUserId, input.tenantId, undefined, input.userContext)), - // highlight-next-line phoneNumber, }, }); @@ -1317,10 +1255,10 @@ Session.init({ }) ``` - - + + -```go +```go {29,30,31,32,33,34,35,36,37,38,39,40,41,42,51,52,53} import ( "github.com/supertokens/supertokens-golang/recipe/passwordless" "github.com/supertokens/supertokens-golang/recipe/session" @@ -1349,7 +1287,6 @@ func main() { return session, nil } - // highlight-start // we first get the passwordless userId associated with this user // using the UserMetadata recipe userMetadata, err := usermetadata.GetUserMetadata(userID, userContext) @@ -1364,7 +1301,6 @@ func main() { } userPhoneNumber = passwordlessUserInfo.PhoneNumber } - // highlight-end if accessTokenPayload == nil { accessTokenPayload = map[string]interface{}{} @@ -1373,11 +1309,9 @@ func main() { if err != nil { return nil, err } - // highlight-start if userPhoneNumber != nil { accessTokenPayload["phoneNumber"] = *userPhoneNumber } - // highlight-end return oCreateNewSession(userID, accessTokenPayload, sessionDataInDatabase, disableAntiCsrf, tenantId, userContext) } return originalImplementation @@ -1387,10 +1321,10 @@ func main() { } ``` - - + + -```python +```python {40,41,42,43,44,45,46,47,48,49,50,64} from typing import Dict, Any, Optional from supertokens_python.recipe.usermetadata.asyncio import get_user_metadata from supertokens_python.asyncio import get_user @@ -1430,7 +1364,6 @@ def override_session_functions(original_implementation: RecipeInterface): if access_token_payload is None: access_token_payload = {} - # highlight-start # we first get the passwordless user id associated with this user # using the user_metadata recipe user_metadata = await get_user_metadata(user_id) @@ -1442,7 +1375,6 @@ def override_session_functions(original_implementation: RecipeInterface): ) if passwordless_user_info is not None: phone_number = passwordless_user_info.phone_numbers[0] - # highlight-end # Insert "is2faComplete" and "phoneNumber" in the access token payload access_token_payload = { @@ -1456,7 +1388,6 @@ def override_session_functions(original_implementation: RecipeInterface): user_context, ) ), - # highlight-next-line "phoneNumber": phone_number, } return await original_create_new_session( @@ -1473,15 +1404,15 @@ def override_session_functions(original_implementation: RecipeInterface): return original_implementation ``` - - + + We can then further modify the customisation in step (4) to simply read from the session's payload making it more efficient: - - + + -```tsx +```tsx {25} import Session from "supertokens-node/recipe/session"; import UserMetadata from "supertokens-node/recipe/usermetadata"; import Passwordless from "supertokens-node/recipe/passwordless"; @@ -1506,7 +1437,6 @@ Passwordless.init({ overrideGlobalClaimValidators: () => [], }); - // highlight-next-line let phoneNumber: string = session!.getAccessTokenPayload().phoneNumber; if (phoneNumber !== undefined) { @@ -1531,10 +1461,10 @@ Passwordless.init({ }) ``` - - + + -```go +```go {40,41,42,43} import ( "errors" @@ -1574,12 +1504,10 @@ func main() { return plessmodels.CreateCodePOSTResponse{}, err } - // highlight-start var userPhoneNumber *string if phoneNumber, ok := session.GetAccessTokenPayloadWithContext(userContext)["phoneNumber"].(string); ok { userPhoneNumber = &phoneNumber } - // highlight-end if userPhoneNumber != nil { // this means we found a phone number associated to this user. @@ -1609,10 +1537,10 @@ func main() { } ``` - - + + -```python +```python {32} from supertokens_python.recipe.passwordless.interfaces import APIInterface, APIOptions from typing import Union, Dict, Any, Optional from supertokens_python.recipe.session.asyncio import get_session @@ -1644,7 +1572,6 @@ def override_passwordless_apis(original_implementation: APIInterface): ) assert _session is not None - # highlight-next-line payload_phone_number = _session.get_access_token_payload().get("phoneNumber") if payload_phone_number is not None: @@ -1668,5 +1595,5 @@ def override_passwordless_apis(original_implementation: APIInterface): original_implementation.create_code_post = create_code_post ``` - - + + diff --git a/docs/additional-verification/mfa/legacy-mfa/frontend-custom.mdx b/docs/additional-verification/mfa/legacy-mfa/frontend-custom.mdx index c8ab048221..e499307a84 100644 --- a/docs/additional-verification/mfa/legacy-mfa/frontend-custom.mdx +++ b/docs/additional-verification/mfa/legacy-mfa/frontend-custom.mdx @@ -1,29 +1,19 @@ --- -id: frontend-custom title: Using a custom UI -hide_title: true -sidebar_position: 4 -description: >- - Implement custom UI for multi-factor authentication using SuperTokens recipes - and session management. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Implement custom UI for multi-factor authentication using SuperTokens recipes and session management. +sidebar: + order: 4 --- - -# Using a custom UI - ## 1. First factor recipe init Start by following the recipe guide for first factor login. To continue building our example app, we will use the `thirdparty` and the `emailpassword` recipes as the first factor. -After following the [frontend quick setup section](/docs/quickstart/introduction) and the [social login guide](/docs/authentication/social/initial-setup), you should have the following `supertokens.init`: +After following the [frontend quick setup section](/quickstart/introduction) and the [social login guide](/authentication/social/initial-setup), you should have the following `supertokens.init`: - - + + - ```tsx import SuperTokens from 'supertokens-web-js'; @@ -33,8 +23,8 @@ import ThirdParty from 'supertokens-web-js/recipe/thirdparty'; SuperTokens.init({ appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", appName: "...", }, recipeList: [ @@ -45,20 +35,15 @@ SuperTokens.init({ }); ``` - - + + - ```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensEmailPassword from "supertokens-web-js-script/recipe/emailpassword"; -import supertokensThirdParty from "supertokens-web-js-script/recipe/thirdparty"; supertokens.init({ appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", appName: "...", }, recipeList: [ @@ -69,8 +54,8 @@ supertokens.init({ }); ``` - - + + From here on, you can continue to build out the first factor's login form using the functions exposed from the `supertokens-web-js` SDK. @@ -78,64 +63,54 @@ From here on, you can continue to build out the first factor's login form using For the second factor, we will be using the [passwordless recipe](https://supertokens.com/docs/passwordless/introduction). After following the [frontend quick setup section](https://supertokens.com/docs/passwordless/quick-setup/frontend), you should have the following `supertokens.init`: - - + + - -```tsx +```tsx {5,17} import SuperTokens from 'supertokens-web-js'; import Session from 'supertokens-web-js/recipe/session'; import EmailPassword from 'supertokens-web-js/recipe/emailpassword'; import ThirdParty from 'supertokens-web-js/recipe/thirdparty'; -// highlight-next-line import Passwordless from 'supertokens-web-js/recipe/passwordless'; SuperTokens.init({ appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", appName: "...", }, recipeList: [ Session.init(), EmailPassword.init(), ThirdParty.init(), - // highlight-next-line Passwordless.init(), ], }); ``` - - + + - -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensEmailPassword from "supertokens-web-js-script/recipe/emailpassword"; -import supertokensThirdParty from "supertokens-web-js-script/recipe/thirdparty"; -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; +```tsx {11} supertokens.init({ appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", appName: "...", }, recipeList: [ supertokensSession.init(), supertokensEmailPassword.init(), supertokensThirdParty.init(), - // highlight-next-line supertokensPasswordless.init() ], }); ``` - - + + You can use the passwordless recipe function to build the second factor UI. @@ -145,8 +120,8 @@ You will want to handle the routing of `webapp` to make sure that the correct lo ### Checking if the first factor login should be shown - - + + ```tsx import Session from 'supertokens-web-js/recipe/session'; @@ -156,30 +131,28 @@ async function shouldShowFirstFactor() { } ``` - - + + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; async function shouldShowFirstFactor() { return !(await supertokensSession.doesSessionExist()); } ``` - - + + If a session does not exist, this means that the user has not completed the first factor. In this case, you want to route them to the `thirdparty` + `emailpassword` login screen. ### Checking if the second factor login should be shown - - + + -```tsx +```tsx {3,4,5,6,7,8,9,10,11,12,13,14,15,16} import Session, { BooleanClaim } from 'supertokens-web-js/recipe/session'; -// highlight-start export const SecondFactorClaim = new BooleanClaim({ id: "2fa-completed", refresh: async () => { @@ -194,19 +167,16 @@ async function shouldShowSecondFactor() { return !(await Session.getClaimValue({ claim: SecondFactorClaim })); } -// highlight-end async function shouldShowFirstFactor() { return !(await Session.doesSessionExist()); } ``` - - + + -```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -// highlight-start +```tsx {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17} // This could be moved into a separate file... export const SecondFactorClaim = new supertokensSession.BooleanClaim({ id: "2fa-completed", @@ -224,15 +194,14 @@ async function shouldShowSecondFactor() { } return true; } -// highlight-end async function shouldShowFirstFactor() { return !(await supertokensSession.doesSessionExist()); } ``` - - + + - If a session does not exist, it means that the user has not finished the first factor yet. - If a session exists, but the `SecondFactorClaim` value is `true`, it means that the user has finished both the factors. @@ -243,7 +212,6 @@ You can check if a user has finished both the login factors using the two functi ```tsx async function areBothLoginFactorsCompleted(): Promise { - // @ts-ignore return !(await shouldShowFirstFactor()) && !(await shouldShowSecondFactor()) } @@ -251,7 +219,6 @@ areBothLoginFactorsCompleted().then(async (bothFactorsCompleted) => { if (bothFactorsCompleted) { // update state to show UI } else { - // @ts-ignore if (await shouldShowFirstFactor()) { // redirect user to first factor } else { @@ -265,8 +232,8 @@ areBothLoginFactorsCompleted().then(async (bothFactorsCompleted) => { Once the user has finished the sign up process, we save their phone number in the session (as seen in the backend setup steps). This can be accessed on the frontend to send the OTP to the user without asking them to re-enter their phone after sign in: - - + + ```tsx import Session from 'supertokens-web-js/recipe/session'; @@ -292,11 +259,10 @@ async function getUsersPhoneNumber(): Promise { } ``` - - + + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; async function getUsersPhoneNumber(): Promise { if (!(await supertokensSession.doesSessionExist())) { // the user has not finished the first factor. @@ -318,15 +284,15 @@ async function getUsersPhoneNumber(): Promise { } ``` - - + + ## 5. Implementing logout If the user has completed both the factors, implementing the sign out feature can be done by: - - + + ```tsx import Session from 'supertokens-web-js/recipe/session'; @@ -337,31 +303,29 @@ async function signOut() { } ``` - - + + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; async function signOut() { await supertokensSession.signOut(); // redirect the user to the first factor login screen } ``` - - + + You should also implement a sign out button on the second factor screen, otherwise the user would be in a stuck state if they are unable to complete the second factor. To do this, you will need to call the `signOut` function as well as a function to clear the passwordless login state: - - + + ```tsx import Session from 'supertokens-web-js/recipe/session'; import Passwordless from 'supertokens-web-js/recipe/passwordless'; async function signOut() { - // @ts-ignore if (await shouldShowSecondFactor()) { // this means we are on the second factor screen now. // calling the function below clears the login attempt info that is @@ -374,14 +338,11 @@ async function signOut() { } ``` - - + + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; async function signOut() { - // @ts-ignore if (await shouldShowSecondFactor()) { // this means we are on the second factor screen now. // calling the function below clears the login attempt info that is @@ -394,5 +355,5 @@ async function signOut() { } ``` - - + + diff --git a/docs/additional-verification/mfa/legacy-mfa/how-it-works.mdx b/docs/additional-verification/mfa/legacy-mfa/how-it-works.mdx index b6cabf9085..c6c543b278 100644 --- a/docs/additional-verification/mfa/legacy-mfa/how-it-works.mdx +++ b/docs/additional-verification/mfa/legacy-mfa/how-it-works.mdx @@ -1,21 +1,16 @@ --- -id: how-it-works title: How it works -hide_title: true -sidebar_position: 2 description: >- - Implement multi-factor authentication using customizable auth recipes, - including session management and second factor validation. -page_type: guide -recipe: mfa -category: multi-factor-authentication + Implement multi-factor authentication using customizable auth recipes, including session management and second factor + validation. +sidebar: + order: 2 --- -:::info Caution +:::info[Caution] This is the legacy method of implementing MFA. It has multiple [disadvantages](./legacy-vs-new) compared to using our MFA recipe. ::: -# How it works You need to start by choosing your first factor auth. This can be any of the [auth recipes](https://supertokens.com/docs/guides) we support. A common choice is to combine the `thirdparty` and `emailpassword` recipes, which allows users to sign in with social or email / password login. @@ -30,7 +25,7 @@ As a high level flow, we will customise these recipes in the following way: - Similarly, to protect frontend routes, we will add the `SecondFactorClaim` validator to the global validators ensuring that all components wrapped with the `SessionAuth` component will check that 2FA is completed. If not, we can then reroute the user to the second factor screen. - We also need to use the `UserMetadata` recipe to store information about the second factor authentication's identification. In the example app, we use phone number SMS OTP as the second factor, therefore we store the user's phone number using the `UserMetadata` recipe, and only send OTPs to that number during sign in. The phone number itself is obtained during the sign up flow. -:::info Important +:::info[Important] In the subsequent sections, we will see how to implement 2fa with the first factor being social and email / password login, and the second factor being phone SMS OTP. If you require a different set of factors or behaviour, you can take inspiration from this guide. diff --git a/docs/additional-verification/mfa/legacy-mfa/legacy-vs-new.mdx b/docs/additional-verification/mfa/legacy-mfa/legacy-vs-new.mdx index 3ea09580c9..551bf4b8fc 100644 --- a/docs/additional-verification/mfa/legacy-mfa/legacy-vs-new.mdx +++ b/docs/additional-verification/mfa/legacy-mfa/legacy-vs-new.mdx @@ -1,18 +1,10 @@ --- -id: legacy-vs-new title: Legacy vs New method -hide_title: true -sidebar_position: 1 -description: >- - Compare legacy and new MFA methods, highlighting limitations and scenarios for - using the legacy approach. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Compare legacy and new MFA methods, highlighting limitations and scenarios for using the legacy approach. +sidebar: + order: 1 --- -# Legacy vs New method - The legacy method for MFA requires you to customise the auth recipes we have to add MFA on top of it. Since it does not use the MFA recipe we have, it's free. The limitations of using the legacy method are: diff --git a/docs/additional-verification/mfa/legacy-mfa/meta.ts b/docs/additional-verification/mfa/legacy-mfa/meta.ts new file mode 100644 index 0000000000..5c1acf97bf --- /dev/null +++ b/docs/additional-verification/mfa/legacy-mfa/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Legacy method", + "icon": "history", + "order": 11 +}); diff --git a/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/_category_.json b/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/_category_.json deleted file mode 100644 index b2f67741f7..0000000000 --- a/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Using prebuilt UI", - "position": 5 -} diff --git a/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/init.mdx b/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/init.mdx index f349e545bd..097fc06483 100644 --- a/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/init.mdx +++ b/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/init.mdx @@ -1,26 +1,17 @@ --- -id: init title: 1. Recipe init -hide_title: true -sidebar_position: 1 -description: >- - Initialize authentication with ThirdParty, EmailPassword, Passwordless, and - MultiFactorAuth using SuperTokens. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Initialize authentication with ThirdParty, EmailPassword, Passwordless, and MultiFactorAuth using SuperTokens. +sidebar: + order: 1 --- - -:::info Caution +:::info[Caution] This is the legacy method of implementing MFA. It has multiple [disadvantages](../legacy-vs-new) compared to using our MFA recipe. ::: -# 1. Recipe init To start, we want to initialise the [ThirdParty + EmailPassword](https://supertokens.com/docs/thirdpartyemailpassword/quick-setup/frontend), the [Passwordless](https://supertokens.com/docs/passwordless/quick-setup/frontend) and the MFA recipes: - ```tsx import React from 'react'; @@ -34,11 +25,11 @@ import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth"; SuperTokens.init({ appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ // first factor method @@ -65,6 +56,6 @@ In the subsequent sections, we will be seeing how to modify theses `init` calls - Auto skipping the screen which asks the user to input their phone number if we already have it - post sign in. - Implementing a logout button on the second factor pre-built UI screen. -:::info Important +:::info[Important] In the guide, we will assume that the first factor path is `/auth`, and the second factor path is `/second-factor`. ::: diff --git a/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/meta.ts b/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/meta.ts new file mode 100644 index 0000000000..a1a8e01e88 --- /dev/null +++ b/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Using prebuilt UI", + "icon": "palette", + "order": 5 +}); diff --git a/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/protecting-routes.mdx b/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/protecting-routes.mdx index 294e80697a..b00f20b0ed 100644 --- a/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/protecting-routes.mdx +++ b/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/protecting-routes.mdx @@ -1,25 +1,18 @@ --- -id: protecting-routes title: 3. Protecting routes -hide_title: true -sidebar_position: 3 -description: >- - Wrap application routes with `SessionAuth` to ensure multi-factor - authentication completion. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Wrap application routes with `SessionAuth` to ensure multi-factor authentication completion. +sidebar: + order: 3 --- -:::info Caution +:::info[Caution] This is the legacy method of implementing MFA. It has multiple [disadvantages](../legacy-vs-new) compared to using our MFA recipe. ::: -# 3. Protecting routes Now we can wrap your application routes with the `SessionAuth` component, which should check for MFA completion by default: -```tsx +```tsx {24,25,26,27,28,29,30,31} import React from "react"; import { Routes, @@ -33,9 +26,7 @@ import { MultiFactorAuthPreBuiltUI } from "supertokens-auth-react/recipe/multifa import { PasswordlessPreBuiltUI } from "supertokens-auth-react/recipe/passwordless/prebuiltui"; import { ThirdPartyPreBuiltUI } from "supertokens-auth-react/recipe/thirdparty/prebuiltui"; import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui"; -// @ts-ignore import SecondFactor from "./SecondFactor"; -// @ts-ignore import Home from "./Home" function App() { @@ -45,7 +36,6 @@ function App() {
{getSuperTokensRoutesForReactRouterDom(reactRouterDom, [ThirdPartyPreBuiltUI, EmailPasswordPreBuiltUI, PasswordlessPreBuiltUI, MultiFactorAuthPreBuiltUI])} - // highlight-start } /> - // highlight-end ## First factor UI -You should see the third party + email password login UI when you visit `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}`. +You should see the third party + email password login UI when you visit `/auth`. No further step is required for the first factor. @@ -45,12 +37,11 @@ export default SecondFactorClaim Then in the main `session.init` in the `supertokens.init` block, add this claim's validator to run the check on each route. -```tsx +```tsx {22,23,24,25,26,27,28,29} import React from 'react'; import SuperTokens from "supertokens-auth-react"; import Session from "supertokens-auth-react/recipe/session"; -// @ts-ignore import SecondFactorClaim from "./SecondFactorClaim"; import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth"; @@ -68,7 +59,6 @@ SuperTokens.init({ override: { functions: (oI) => ({ ...oI, - // highlight-start getGlobalClaimValidators: ({ claimValidatorsAddedByOtherRecipes }) => { return [ SecondFactorClaim.validators.isTrue(), @@ -77,7 +67,6 @@ SuperTokens.init({ ), ]; }, - // highlight-end }), }, }) @@ -159,7 +148,7 @@ export default App; Finally, we add the custom component we copy / pasted before to our router: -```tsx +```tsx {23,24,25,26,27,28,29,30} import { Routes, Route, @@ -173,7 +162,6 @@ import { PasswordlessPreBuiltUI } from "supertokens-auth-react/recipe/passwordle import { ThirdPartyPreBuiltUI } from "supertokens-auth-react/recipe/thirdparty/prebuiltui" import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui" -// @ts-ignore import SecondFactor from "./SecondFactor"; function App() { @@ -183,7 +171,6 @@ function App() {
{getSuperTokensRoutesForReactRouterDom(reactRouterDom, [ThirdPartyPreBuiltUI, EmailPasswordPreBuiltUI, PasswordlessPreBuiltUI, MultiFactorAuthPreBuiltUI])} - // highlight-start } /> - // highlight-end
diff --git a/docs/additional-verification/mfa/meta.ts b/docs/additional-verification/mfa/meta.ts new file mode 100644 index 0000000000..170dd53cda --- /dev/null +++ b/docs/additional-verification/mfa/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Multi Factor Authentication", + "icon": "monitor-smartphone", + "order": 1.2 +}); diff --git a/docs/additional-verification/mfa/migration/_category_.json b/docs/additional-verification/mfa/migration/_category_.json deleted file mode 100644 index 6481579300..0000000000 --- a/docs/additional-verification/mfa/migration/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Migration", - "position": 9 -} diff --git a/docs/additional-verification/mfa/migration/legacy-to-new.mdx b/docs/additional-verification/mfa/migration/legacy-to-new.mdx index 3209584161..9aa194b9d2 100644 --- a/docs/additional-verification/mfa/migration/legacy-to-new.mdx +++ b/docs/additional-verification/mfa/migration/legacy-to-new.mdx @@ -1,21 +1,11 @@ --- -id: legacy-to-new title: Migration from legacy MFA to new MFA method -hide_title: true -sidebar_position: 2 -description: >- - Migrate from legacy to new MFA method, integrating backend and frontend - changes for enhanced security. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Migrate from legacy to new MFA method, integrating backend and frontend changes for enhanced security. +sidebar: + order: 2 --- - - -# Migration from legacy MFA to new MFA method - -This page only applies if you have used our [legacy MFA method](/docs/additional-verification/mfa/legacy-mfa/how-it-works) and want to migrate to the new MFA method. +This page only applies if you have used our [legacy MFA method](/additional-verification/mfa/legacy-mfa/how-it-works) and want to migrate to the new MFA method. From a code point of view, [here is the diff](https://github.com/supertokens/supertokens-auth-react/commit/f96e11a527ccd9df71c25798c316dd3de770dde1) of all changes required: - We no longer need the custom `secondFactoeClaim` since the MFA recipe adds its own MFA claim. diff --git a/docs/additional-verification/mfa/migration/meta.ts b/docs/additional-verification/mfa/migration/meta.ts new file mode 100644 index 0000000000..87b7103a58 --- /dev/null +++ b/docs/additional-verification/mfa/migration/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Migration", + "icon": "arrow-right", + "order": 9 +}); diff --git a/docs/additional-verification/mfa/migration/old-sdk-to-new.mdx b/docs/additional-verification/mfa/migration/old-sdk-to-new.mdx index 31d4d2a55e..767d883152 100644 --- a/docs/additional-verification/mfa/migration/old-sdk-to-new.mdx +++ b/docs/additional-verification/mfa/migration/old-sdk-to-new.mdx @@ -1,21 +1,12 @@ --- -id: old-sdk-to-new title: Migration from an older SuperTokens SDK to a newer one -hide_title: true -sidebar_position: 3 -description: >- - Upgrade your SuperTokens SDK to enable MFA, ensuring compatibility and smooth - transition for existing users. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Upgrade your SuperTokens SDK to enable MFA, ensuring compatibility and smooth transition for existing users. +sidebar: + order: 3 --- - -# Migration from an older SuperTokens SDK to a newer one - This section is applicable to those who want to enable MFA for the first time and are already using SuperTokens in production. The following are the steps you need to take: -- Make sure that you have updated your SuperTokens core, backend SDK and frontend SDK that supports MFA (you can find these versions in the CHANGELOG.md files in their respective GitHub repository). Make sure to read the migration guide for each of the breaking version upgrades. You should aim to get your existing feature set working with the new version of SuperTokens before you enable MFA. +- Make sure that you have updated your SuperTokens core, backend SDK and frontend SDK that supports MFA (you can find these versions in the CHANGELOG files in their respective GitHub repository). Make sure to read the migration guide for each of the breaking version upgrades. You should aim to get your existing feature set working with the new version of SuperTokens before you enable MFA. - Follow the backend and frontend setup we have in this guide along with the factor specific setup (TOTP or email / SMS OTP). ## If enabling MFA for all users at once @@ -24,10 +15,10 @@ If you have enabled MFA for all users, then existing logged in users will asked If you have clients like mobile apps, which take time to upgrade across your entire user base, then you may want to remove the global MFA validator on the backend and make it run only when you know that the request is coming from an updated client: - - + + -```tsx +```tsx {20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56} import Session from "supertokens-node/recipe/session"; import { ClaimValidationResult } from "supertokens-node/recipe/session/types"; import SuperTokens, { getRequestFromUserContext } from "supertokens-node"; @@ -47,7 +38,6 @@ SuperTokens.init({ functions: (originalImplementation) => { return { ...originalImplementation, - // highlight-start getGlobalClaimValidators: (input) => { // We remove the existing default MFA validator which checks that // the client has finished MFA. @@ -85,7 +75,6 @@ SuperTokens.init({ return [customValidator, ...newValidatorsArray]; } - // highlight-end } } } @@ -94,15 +83,14 @@ SuperTokens.init({ }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -178,18 +166,17 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ session.init(override=InputOverrideConfig(functions=override_functions)) ], ) ``` - - + + The code above will still result in the MFA claim being added to all sessions, with the `v` boolean in it being `false`, however, for older clients, we will not run the validator that checks if the `v` value is true on the backend since those clients have no way to show the MFA UI without updating the app. -:::caution -You want to add the above exception only for a certain amount of time until you force all users to update their mobile app. This is because the exception method can be used as a way for malicious users to bypass MFA by spoofing that they are using an older client. +:::warning[You want to add the above exception only for a certain amount of time until you force all users to update their mobile app. This is because the exception method can be used as a way for malicious users to bypass MFA by spoofing that they are using an older client.] ::: diff --git a/docs/additional-verification/mfa/protect-routes.mdx b/docs/additional-verification/mfa/protect-routes.mdx index d1775acf75..a572af9750 100644 --- a/docs/additional-verification/mfa/protect-routes.mdx +++ b/docs/additional-verification/mfa/protect-routes.mdx @@ -1,20 +1,10 @@ --- title: Protect frontend and backend routes -hide_title: true -sidebar_position: 8 -description: >- - Protect frontend and backend routes using SuperTokens Session Tokens and - Multi-Factor Authentication (MFA). -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Protect frontend and backend routes using SuperTokens Session Tokens and Multi-Factor Authentication (MFA). +sidebar: + order: 8 --- - -import { TokensCallout, ContextCondition } from "/src/components"; - -# Protect frontend and backend routes - ## Overview This page shows you how to protect your frontend and backend routes to make them accessible only when the user has finished all the MFA challenges configured for them. @@ -22,7 +12,9 @@ In both the backend and the frontend, routes are protected based on value of the ## Before you start - +:::info +This guide only applies to scenarios involving **SuperTokens Session Access Tokens**. +::: One thing to note here is that, with **OAuth2 Access Tokens**, you don't need to check the MFA claims. You will get the token once the MFA flow is done. @@ -34,8 +26,7 @@ When you call `MultiFactorAuth.init` in the `supertokens.init` on the backend, S This validator checks that the value of `v` in the [MFA claim](./important-concepts#factors) is `true` before allowing the request to proceed. If the value of `v` is `false`, the validator will send a 403 error to the frontend. -:::important -This validator is added globally, which means that every time you use `Verify Session` or `Get Session` from the backend SDKs, this check will happen. +:::note[This validator is added globally, which means that every time you use `Verify Session` or `Get Session` from the backend SDKs, this check will happen.] This means that you don't need to add any extra code on a per API level to enforce MFA. ::: @@ -44,10 +35,10 @@ This means that you don't need to add any extra code on a per API level to enfor To exclude the default validator check in a certain backend route, you have to update `Verify Session` call. - - - - + + + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/express"; @@ -70,8 +61,8 @@ app.post( } ); ``` - - + + ```tsx import Hapi from "@hapi/hapi"; @@ -101,8 +92,8 @@ server.route({ } }) ``` - - + + ```tsx import Fastify from "fastify"; @@ -124,8 +115,8 @@ fastify.post("/update-blog", { }); ``` - - + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; @@ -144,8 +135,8 @@ exports.handler = verifySession(updateBlog, { }); ``` - - + + ```tsx import KoaRouter from "koa-router"; @@ -165,8 +156,8 @@ router.post("/update-blog", verifySession({ }); ``` - - + + ```tsx import { inject, intercept } from "@loopback/core"; @@ -191,22 +182,21 @@ class Example { } ``` - - + + + - - + -```tsx +```tsx {6,7,8,9,10,11,12,13,14,15,16,17,18,19,20} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; -// highlight-start export default async function example(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { @@ -227,12 +217,11 @@ export default async function example(req: SessionRequest, res: any) { -```tsx +```tsx {19,20,21} import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -247,24 +236,21 @@ export function POST(request: NextRequest) { return NextResponse.json({}) }, { - // highlight-start overrideGlobalClaimValidators: async (globalValidators) => { return globalValidators.filter(validator => validator.id !== MultiFactorAuth.MultiFactorAuthClaim.key); }, - // highlight-end }); } ``` - - + + ```tsx import { Controller, Post, UseGuards, Request, Response, Session } from "@nestjs/common"; import { SessionContainer, SessionClaimValidator } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; @@ -283,87 +269,80 @@ export class ExampleController { } } ``` - + - - - + + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + -```python +```python {9,10,11} from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import MultiFactorAuthClaim from supertokens_python.recipe.session import SessionContainer from fastapi import Depends -@app.post('/like_comment') # type: ignore +@app.post('/like_comment') async def like_comment(session: SessionContainer = Depends( verify_session( - # highlight-start # We keep all validators except for the EmailVerification ones override_global_claim_validators=lambda global_validators, session, user_context: [ validators for validators in global_validators if validators.id != MultiFactorAuthClaim.key] - # highlight-end ) )): # All validator checks have passed and the user has a verified email address pass ``` - - + + -```python +```python {6,7,8} from supertokens_python.recipe.session.framework.flask import verify_session from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import MultiFactorAuthClaim -@app.route('/update-jwt', methods=['POST']) # type: ignore +@app.route('/update-jwt', methods=['POST']) @verify_session( - # highlight-start # We keep all validators except for the EmailVerification ones override_global_claim_validators=lambda global_validators, session, user_context: [ validators for validators in global_validators if validators.id != MultiFactorAuthClaim.key] - # highlight-end ) def like_comment(): # All validator checks have passed and the user has a verified email address pass ``` - - + + -```python +```python {6,7,8} from supertokens_python.recipe.session.framework.django.asyncio import verify_session from django.http import HttpRequest from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import MultiFactorAuthClaim @verify_session( - # highlight-start # We keep all validators except for the EmailVerification ones override_global_claim_validators=lambda global_validators, session, user_context: [ validators for validators in global_validators if validators.id != MultiFactorAuthClaim.key] - # highlight-end ) async def like_comment(request: HttpRequest): # All validator checks have passed and the user has a verified email address pass ``` - - + + - - + + The same modification can be done for `getSession` as well. @@ -371,10 +350,10 @@ The same modification can be done for `getSession` as well. To account for a more complex logic when you check the MFA claim (other than checking if `v` is `true`), look over the next code snippet. - - - - + + + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/express"; @@ -423,8 +402,8 @@ app.post( } ); ``` - - + + ```tsx import Hapi from "@hapi/hapi"; @@ -480,8 +459,8 @@ server.route({ } }) ``` - - + + ```tsx import Fastify from "fastify"; @@ -529,8 +508,8 @@ fastify.post("/update-blog", { }); ``` - - + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; @@ -575,8 +554,8 @@ exports.handler = verifySession(updateBlog, { }); ``` - - + + ```tsx import KoaRouter from "koa-router"; @@ -622,8 +601,8 @@ router.post("/update-blog", verifySession({ }); ``` - - + + ```tsx import { inject, intercept } from "@loopback/core"; @@ -674,23 +653,22 @@ class Example { } ``` - - + + + - - + -```tsx +```tsx {7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; import { Error as STError } from "supertokens-node/recipe/session" -// highlight-start export default async function example(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { @@ -742,12 +720,11 @@ export default async function example(req: SessionRequest, res: any) { -```tsx +```tsx {46,47,48} import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; import { Error as STError } from "supertokens-node/recipe/session" @@ -789,24 +766,21 @@ export function POST(request: NextRequest) { return NextResponse.json({}) }, { - // highlight-start overrideGlobalClaimValidators: async (globalValidators) => { return globalValidators.filter(validator => validator.id !== MultiFactorAuth.MultiFactorAuthClaim.key); }, - // highlight-end }); } ``` - - + + ```tsx import { Controller, Post, UseGuards, Request, Response, Session } from "@nestjs/common"; import { SessionContainer, SessionClaimValidator } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; import { Error as STError } from "supertokens-node/recipe/session" @@ -851,23 +825,22 @@ export class ExampleController { } } ``` - + - - - + + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + -```python +```python {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39} from fastapi import Depends from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import ( @@ -881,9 +854,8 @@ from supertokens_python.recipe.session.exceptions import ( from supertokens_python.recipe.session.framework.fastapi import verify_session -@app.post("/update-blog") # type: ignore +@app.post("/update-blog") async def update_blog_api(session: SessionContainer = Depends(verify_session())): - # highlight-start mfa_claim_value = await session.get_claim_value(MultiFactorAuthClaim) if mfa_claim_value is None: # This means that there is no MFA claim information in the session. @@ -908,13 +880,12 @@ async def update_blog_api(session: SessionContainer = Depends(verify_session())) ], ) # If we reach here, it means the user has completed TOTP - # highlight-end ``` - - + + -```python +```python {19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36} from flask import Flask, g from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import ( @@ -929,11 +900,10 @@ from supertokens_python.recipe.session.framework.flask import verify_session app = Flask(__name__) -@app.route('/update-blog', methods=['POST']) # type: ignore +@app.route('/update-blog', methods=['POST']) @verify_session() def check_mfa_api(): - session: SessionContainer = g.supertokens # type: ignore - # highlight-start + session: SessionContainer = g.supertokens mfa_claim_value = session.sync_get_claim_value(MultiFactorAuthClaim) if mfa_claim_value is None: # This means that there is no MFA claim information in the session. @@ -952,13 +922,12 @@ def check_mfa_api(): }) ]) # If we reach here, it means the user has completed TOTP - # highlight-end ``` - - + + -```python +```python {19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42} from typing import cast from django.http import HttpRequest @@ -976,8 +945,7 @@ from supertokens_python.recipe.session.framework.django.asyncio import verify_se @verify_session() async def get_user_info_api(request: HttpRequest): - session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore - # highlight-start + session: SessionContainer = cast(SessionContainer, request.supertokens) mfa_claim_value = await session.get_claim_value(MultiFactorAuthClaim) if mfa_claim_value is None: # This means that there is no MFA claim information in the session. @@ -1002,21 +970,20 @@ async def get_user_info_api(request: HttpRequest): ], ) # If we reach here, it means the user has completed TOTP - # highlight-end ``` - - + + - - + + - In the code snippet above, we remove the default validator that was added to the global validators (which checks if the `v` value in the claim is true or not). You don't need to do this, but in the code snippet above, we show it anyway. - Then in the API logic, we manually fetch the claim value, and then check if TOTP has been completed or not. If it hasn't, we send back a 403 error to the frontend. You can use a similar approach as shown above to do any kind of check. -:::info important +:::info[important] If you are doing JWT verification manually, then post verification, you should check the payload of the JWT and make sure that the `v` value in the [MFA claim](./important-concepts#how-are-auth-factors-marked-as-completed) is `true`. This would be equivalent to doing a check as our default claim validator mentioned above. @@ -1027,13 +994,13 @@ Make sure to also do other checks on the JWT payload. For example, if you requir ## Protect frontend routes - + - + - + - + When you call `MultiFactorAuth.init` in the `supertokens.init` on the frontend, SuperTokens will add a default validator check that runs whenever you use the `SessionAuth` component. This validator checks if the `v` value in the [MFA claim](./important-concepts#how-are-auth-factors-marked-as-completed) is `true` or not. If it is not, then the user will be redirected to the MFA auth screen. @@ -1079,9 +1046,9 @@ function InvalidClaimHandler(props: React.PropsWithChildren) { - In the snippet above, we remove the default claim validator that is added to `SessionAuth`, and add out own logic that reads from the session's payload. - Finally, we check if the user has completed TOTP or not. If not, we show a message to the user, and ask them to complete TOTP. Of course, if this is all you want to do, then the default validator already does that. But the above has the boilerplate for how you can do more complex checks. - + - + By default, when you do `MultiFactorAuth.init` in `supertokens.init` on the frontend, SuperTokens will add a default validator check that runs whenever you call the `Session.validateClaims` function. This validator checks if the `v` value in the [MFA claim](./important-concepts#how-are-auth-factors-marked-as-completed) is `true` or not. @@ -1120,23 +1087,23 @@ In your protected routes, you need to first check if a session exists, and then In case the claim fails, you can get the claim value and check which factor is not completed. In the above code, we check that if it's the TOTP factor that is missing when the claim fails and return `false` from this function. However, it's really up to you for what you want to do next. For example, you could redirect the user to the TOTP factor screen. - + - + - + - + - + - + By default, when you do `MultiFactorAuth.init` in `supertokens.init` on the frontend, SuperTokens will add a default validator check that runs whenever you call the `Session.validateClaims` function. This validator checks if the `v` value in the [MFA claim](./important-concepts#how-are-auth-factors-marked-as-completed) is `true` or not. - - + + ```tsx import Session from "supertokens-web-js/recipe/session"; @@ -1169,12 +1136,10 @@ async function shouldLoadRoute(): Promise { } ``` - - + + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensMultiFactorAuth from "supertokens-web-js-script/recipe/multifactorauth"; async function shouldLoadRoute(): Promise { if (await supertokensSession.doesSessionExist()) { let validationErrors = await supertokensSession.validateClaims(); @@ -1202,32 +1167,30 @@ async function shouldLoadRoute(): Promise { } ``` - - + + In your protected routes, you need to first check if a session exists, and then call the Session.validateClaims function as shown above. This function inspects the session's contents and runs claim validators on them. If a claim validator fails, it will be reflected in the `validationErrors` variable. The `MultiFactorAuthClaim` validator will be automatically checked by this function since you have initialized the MFA recipe. In case the claim fails, you can get the claim value and check which factor is not completed. In the above code, we check that if it's the TOTP factor that is missing when the claim fails and return `false` from this function. However, it's really up to you for what you want to do next. For example, you could redirect the user to the TOTP factor screen. - + - + In your app, you can check the [MFA claim](./important-concepts#how-are-auth-factors-marked-as-completed) values to know which factors have been completed by the user and take action based on that. - - + - + -```tsx +```tsx {6,7,8,9,10,11,12} import SuperTokens from 'supertokens-react-native'; async function checkIfMFAIsCompleted() { if (await SuperTokens.doesSessionExist()) { - // highlight-start let isMFACompleted: boolean = (await SuperTokens.getAccessTokenPayloadSecurely())["st-mfa"].v; if (isMFACompleted) { @@ -1235,14 +1198,13 @@ async function checkIfMFAIsCompleted() { } else { // You can check the `c` object from ["st-mfa"] prop to see which factors have been completed by the user } - // highlight-end } } ``` - + - + ```kotlin import android.app.Application @@ -1262,9 +1224,9 @@ class MainApplication: Application() { } ``` - + - + ```swift import UIKit @@ -1290,9 +1252,9 @@ fileprivate class ViewController: UIViewController { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -1316,26 +1278,25 @@ Future checkIfMFAIsCompleted() async { } ``` - + - + -If the MFA claim value is missing in the access token payload, then it means that the session was created before you enabled MFA on the backend. In this case, you can call the [MFA Info](./frontend-setup#mfa-info-endpoint) endpoint which will add the MFA claim to the session and check again. +If the MFA claim value is missing in the access token payload, then it means that the session was created before you enabled MFA on the backend. In this case, you can call the [MFA Info](/additional-verification/mfa/initial-setup#the-mfa-info-endpoint) endpoint which will add the MFA claim to the session and check again. - - + + - + --- ## See also - - - - - - - + + + + + + diff --git a/docs/additional-verification/mfa/step-up-auth.mdx b/docs/additional-verification/mfa/step-up-auth.mdx index 917162b568..24dfe68c3d 100644 --- a/docs/additional-verification/mfa/step-up-auth.mdx +++ b/docs/additional-verification/mfa/step-up-auth.mdx @@ -1,17 +1,10 @@ --- title: Implement step-up authentication -hide_title: true -toc_max_heading_level: 4 -sidebar_position: 7 description: Implement step-up authentication using SuperTokens MFA recipe. -page_type: guide -recipe: mfa -category: multi-factor-authentication +sidebar: + order: 7 --- - -# Implement step-up authentication - ## Overview Step-up authentication enforces the user to complete an authentication challenge before navigating to a page, or before doing a specific action. @@ -19,10 +12,12 @@ You can implement it with **SuperTokens** as full page navigation, or as popups ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: These instructions assume that you already have some knowledge of MFA. -If you are not familiar with terms like authentication factors and challenges, please go through the [MFA concepts page](/docs/additional-verification/mfa/important-concepts). +If you are not familiar with terms like authentication factors and challenges, please go through the [MFA concepts page](/additional-verification/mfa/important-concepts). ### Prerequisites @@ -43,10 +38,10 @@ To protect sensitive APIs with step up auth, you need to check that the user has If they haven't, you should return a `403` to the frontend which highlights which factor is necessary. The frontend can then consume this and show the auth challenge to the user. - - - - + + + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/express"; @@ -82,8 +77,8 @@ app.post( } ); ``` - - + + ```tsx import Hapi from "@hapi/hapi"; @@ -127,8 +122,8 @@ server.route({ } }) ``` - - + + ```tsx import Fastify from "fastify"; @@ -163,8 +158,8 @@ fastify.post("/update-blog", { }); ``` - - + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; @@ -196,8 +191,8 @@ async function updateBlog(awsEvent: SessionEvent) { exports.handler = verifySession(updateBlog); ``` - - + + ```tsx import KoaRouter from "koa-router"; @@ -230,8 +225,8 @@ router.post("/update-blog", verifySession(), async (ctx: SessionContext, next) = }); ``` - - + + ```tsx import { inject, intercept } from "@loopback/core"; @@ -269,23 +264,22 @@ class Example { } ``` - - + + + - - + -```tsx +```tsx {7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; import { Error as STError } from "supertokens-node/recipe/session" -// highlight-start export default async function example(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { @@ -329,7 +323,6 @@ import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; import { Error as STError } from "supertokens-node/recipe/session" @@ -366,13 +359,12 @@ export function POST(request: NextRequest) { - - + + ```tsx import { Controller, Post, UseGuards, Request, Response, Session } from "@nestjs/common"; import { SessionContainer, SessionClaimValidator } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; import { Error as STError } from "supertokens-node/recipe/session" @@ -404,23 +396,22 @@ export class ExampleController { } } ``` - + - - - + + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + -```python +```python {18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36} import time from fastapi import Depends @@ -436,9 +427,8 @@ from supertokens_python.recipe.session.exceptions import ( from supertokens_python.recipe.session.framework.fastapi import verify_session -@app.post("/update-blog") # type: ignore +@app.post("/update-blog") async def update_blog_api(session: SessionContainer = Depends(verify_session())): - # highlight-start mfa_claim_value = await session.get_claim_value(MultiFactorAuthClaim) assert mfa_claim_value is not None totp_completed_time = mfa_claim_value.c.get("totp") @@ -458,13 +448,12 @@ async def update_blog_api(session: SessionContainer = Depends(verify_session())) ], ) # If we reach here, it means the user has completed TOTP - # highlight-end ``` - - + + -```python +```python {21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39} import time from flask import Flask, g @@ -481,11 +470,10 @@ from supertokens_python.recipe.session.framework.flask import verify_session app = Flask(__name__) -@app.route('/update-blog', methods=['POST']) # type: ignore +@app.route('/update-blog', methods=['POST']) @verify_session() def check_mfa_api(): - session: SessionContainer = g.supertokens # type: ignore - # highlight-start + session: SessionContainer = g.supertokens mfa_claim_value = session.sync_get_claim_value(MultiFactorAuthClaim) assert mfa_claim_value is not None totp_completed_time = mfa_claim_value.c.get("totp") @@ -505,13 +493,12 @@ def check_mfa_api(): ], ) # If we reach here, it means the user has completed TOTP - # highlight-end ``` - - + + -```python +```python {20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38} import time from typing import cast @@ -530,8 +517,7 @@ from supertokens_python.recipe.session.framework.django.asyncio import verify_se @verify_session() async def get_user_info_api(request: HttpRequest): - session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore - # highlight-start + session: SessionContainer = cast(SessionContainer, request.supertokens) mfa_claim_value = await session.get_claim_value(MultiFactorAuthClaim) assert mfa_claim_value is not None totp_completed_time = mfa_claim_value.c.get("totp") @@ -551,14 +537,13 @@ async def get_user_info_api(request: HttpRequest): ], ) # If we reach here, it means the user has completed TOTP - # highlight-end ``` - - + + - - + + - When calling the `verifySession`, SuperTokens makes sure that the session is valid and that the user has completed all the required auth factors at some point in time. This enforces the basic check that the user has finished MFA during login. - Further check if the user has finished the TOTP login method within the last 5 minutes. If they haven't, send back a 403 to the frontend for the frontend to handle. @@ -576,10 +561,10 @@ This opens up a security issue when it comes to completing step up auth. Conside This allows someone malicious to bypass step up auth. To prevent this, override one of the MFA recipe functions on the backend. This enforces that the factor setup can only happen if the user is not in a step-up auth state. - - + + -```ts +```ts {22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51} import supertokens from "supertokens-node"; import MultiFactorAuth from "supertokens-node/recipe/multifactorauth" import { Error as STError } from "supertokens-node/recipe/session" @@ -601,7 +586,6 @@ supertokens.init({ functions: (originalImplementation) => { return { ...originalImplementation, - // highlight-start assertAllowedToSetupFactorElseThrowInvalidClaimError: async (input) => { await originalImplementation.assertAllowedToSetupFactorElseThrowInvalidClaimError(input); @@ -632,7 +616,6 @@ supertokens.init({ } } } - // highlight-end } } } @@ -641,15 +624,14 @@ supertokens.init({ }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python import time @@ -735,7 +717,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ multifactorauth.init( first_factors=[FactorIds.EMAILPASSWORD, FactorIds.THIRDPARTY], @@ -745,8 +727,8 @@ init( ) ``` - - + + - SuperTokens calls the function `assertAllowedToSetupFactorElseThrowInvalidClaimError` whenever the client calls an API to setup a new factor (for example, create a new TOTP device). Perform checks in this function and throw an error if necessary to prevent factor setup. - In the override logic, first call the original implementation and check that the `v` value in the MFA session claim is `true`. This throws / exits the function early if the user has not logged in yet (for example, they have finished the first factor, but not the required second factor). @@ -773,9 +755,9 @@ The JSON body of the step-up auth claim failure looks like this: } ``` - + - + You can check for this structure and the `factorId` to decide what factor to show on the frontend. You have two options to show the UI to the user: @@ -783,8 +765,8 @@ You can check for this structure and the `factorId` to decide what factor to sho To redirect the user to as factor challenge page and then navigate them back to the current page, you can use the following function: - - + + ```tsx import MultiFactorAuth from 'supertokens-auth-react/recipe/multifactorauth'; @@ -802,27 +784,27 @@ async function redirectToTotpSetupScreen() { - You can also redirect the user to `/{websiteBasePath}/mfa/totp?setup=true&redirectToPath={currentPath}` if you don't want to use the above function. - + - + To add a new device, you can redirect the user to `/{websiteBasePath}/mfa/totp?setup=true&redirectToPath={currentPath}` from your settings page. This shows the [TOTP factor setup screen](https://master--6571be2867f75556541fde98.chromatic.com/?path=/story/totp-mfa--device-setup) to the user. The `redirectToPath` query parameter also tells the SDK to redirect the user back to the current page after they have finished creating the device. - + - + #### Show the factor in a popup -Checkout [the documentation](/docs/additional-verification/mfa/embed-the-prebuilt-ui) for embedding the pre-built UI factor components in a page or a popup. +Checkout [the documentation](/additional-verification/mfa/embed-the-prebuilt-ui) for embedding the pre-built UI factor components in a page or a popup. - + - + You can check for this structure and the `factorId` to decide what factor to show on the frontend. - + ### 4. Check for step-up authentication on page navigation @@ -834,11 +816,11 @@ To do this, read the access token payload on the frontend and check the complete If the completed time is older than 5 minutes (as an example), redirect the user to the factor challenge page. - + - + - + ```tsx import React from "react"; @@ -874,9 +856,9 @@ function InvalidClaimHandler(props: React.PropsWithChildren) { - Check if the user has completed TOTP within the last 5 minutes or not. If not, show a message to the user, and ask them to complete TOTP. - Notice that the `DateProviderReference` class exported by SuperTokens replaces `Date.now()`. This accounts for any clock skew that may exist between the frontend and the backend server. - + - + ```tsx import Session from "supertokens-web-js/recipe/session"; @@ -910,20 +892,20 @@ async function shouldLoadRoute(): Promise { - For checking for step-up auth, get the MFA claim value from the session and then check if TOTP completed within the last 5 minutes. Only if it did, return true, else return false. - Notice that the `DateProviderReference` class exported by SuperTokens replaces `Date.now()`. This accounts for any clock skew that may exist between the frontend and the backend server. - + - + - + - + - + - + - - + + ```tsx import Session from "supertokens-web-js/recipe/session"; @@ -953,13 +935,10 @@ async function shouldLoadRoute(): Promise { } ``` - - + + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensMultiFactorAuth from "supertokens-web-js-script/recipe/multifactorauth"; -import supertokensDateProviderReference from "supertokens-web-js-script/utils/dateProvider"; async function shouldLoadRoute(): Promise { if (await supertokensSession.doesSessionExist()) { let validationErrors = await supertokensSession.validateClaims(); @@ -983,28 +962,27 @@ async function shouldLoadRoute(): Promise { } ``` - - + + - In your protected routes, you need to first check if a session exists, and then call the Session.validateClaims function as shown above. If that passes, it means all the default claim validators have passed (checks applied to all routes in general), and then perform the step-up auth check. - For checking for step-up auth, get the MFA claim value from the session and then check if TOTP completed within the last 5 minutes. Only if it did, return true, else return false. - Notice that the `DateProviderReference` class exported by SuperTokens replaces `Date.now()`. This accounts for any clock skew that may exist between the frontend and the backend server. - + - + - + - + -```tsx +```tsx {6,7,8,9,10,11,12,13,14} import SuperTokens from 'supertokens-react-native'; async function checkIfMFAIsCompleted() { if (await SuperTokens.doesSessionExist()) { - // highlight-start let isMFACompleted: boolean = (await SuperTokens.getAccessTokenPayloadSecurely())["st-mfa"].v; if (isMFACompleted) { let completedFactors = (await SuperTokens.getAccessTokenPayloadSecurely())["st-mfa"].c; @@ -1014,14 +992,13 @@ async function checkIfMFAIsCompleted() { } else { // You can check the `c` object from ["st-mfa"] prop to see which factors have been completed by the user } - // highlight-end } } ``` - + - + ```kotlin import android.app.Application @@ -1054,9 +1031,9 @@ class MainApplication: Application() { } ``` - + - + ```swift import UIKit @@ -1082,9 +1059,9 @@ fileprivate class ViewController: UIViewController { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -1114,27 +1091,26 @@ Future checkIfMFAIsCompleted() async { } ``` - + - + - In your protected routes, you need to first check if a session exists, and then check that the user has finished all the basic MFA factors for logging in (by checking the value of the `v` boolean in the MFA claim session). If that passes, then perform the step-up auth check. - For checking for step-up auth, get the MFA claim value from the session, and then check if TOTP completed within the last 5 minutes. Only if it did, return true, else return false. - - + + - + --- ## See also - - - - - - - + + + + + + diff --git a/docs/additional-verification/mfa/totp/_category_.json b/docs/additional-verification/mfa/totp/_category_.json deleted file mode 100644 index a4a93e6285..0000000000 --- a/docs/additional-verification/mfa/totp/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "TOTP", - "position": 5 -} diff --git a/docs/additional-verification/mfa/totp/meta.ts b/docs/additional-verification/mfa/totp/meta.ts new file mode 100644 index 0000000000..fe7bd63f9a --- /dev/null +++ b/docs/additional-verification/mfa/totp/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "TOTP", + "icon": "hash", + "order": 5 +}); diff --git a/docs/additional-verification/mfa/totp/totp-for-all-users.mdx b/docs/additional-verification/mfa/totp/totp-for-all-users.mdx index 24803dd02e..d6436c0f6d 100644 --- a/docs/additional-verification/mfa/totp/totp-for-all-users.mdx +++ b/docs/additional-verification/mfa/totp/totp-for-all-users.mdx @@ -1,18 +1,10 @@ --- title: Require TOTP for all users -hide_title: true -sidebar_position: 1 -description: >- - Implement a TOTP-based MFA policy for all users to enhance application - security. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Implement a TOTP-based MFA policy for all users to enhance application security. +sidebar: + order: 1 --- - -# TOTP required for all users - ## Overview This guide shows you how to implement an MFA policy that requires all users to use TOTP before they get access to your application. @@ -21,22 +13,24 @@ This guide shows you how to implement an MFA policy that requires all users to u The tutorial assumes that the first factor is email password or social login, but the same set of steps are applicable for other first factor types. - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: ## Steps - + - + ### 1. Configure the backend To start with, we configure the backend in the following way: - - + + -```ts +```ts {25,31,32,33,34,35,36,37,38,39,40} import supertokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty" import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -61,14 +55,12 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-next-line totp.init(), MultiFactorAuth.init({ firstFactors: [ MultiFactorAuth.FactorIds.EMAILPASSWORD, MultiFactorAuth.FactorIds.THIRDPARTY ], - // highlight-start override: { functions: (originalImplementation) => { return { @@ -79,21 +71,19 @@ supertokens.init({ } } } - // highlight-end }) ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -137,7 +127,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ totp.init(), multifactorauth.init( @@ -148,8 +138,8 @@ init( ) ``` - - + + - Notice that we have initialised the TOTP recipe in the `recipeList`. By default, no configs are required for it, but you can provide: - `issuer`: This is the name that will show up in the TOTP app for the user. By default, this is equal to the `appName` config, however, you can change it to something else using this property. @@ -187,17 +177,17 @@ Indicating that the user has finished all required factors, and should be allowe ### 2. Configure the frontend - + - + We start by modifying the `init` function call on the frontend like so: - + - + -```tsx +```tsx {14,15,16,17,18,19,20} import supertokens from "supertokens-auth-react" import Passwordless from "supertokens-auth-react/recipe/passwordless" import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth" @@ -211,7 +201,6 @@ supertokens.init({ }, recipeList: [ // other recipes.. - // highlight-start totp.init(), MultiFactorAuth.init({ firstFactors: [ @@ -219,25 +208,20 @@ supertokens.init({ MultiFactorAuth.FactorIds.THIRDPARTY ] }) - // highlight-end ] }) ``` - + - + You will have to make changes to the auth route config, as well as to the `supertokens-web-js` SDK config at the root of your application: This change is in your auth route config. -```tsx +```tsx {10,11,12,13,14,15,16} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless" -import supertokensUIMultiFactorAuth from "supertokens-auth-react-script/recipe/multifactorauth" -import supertokensUITOTP from "supertokens-auth-react-script/recipe/totp" supertokensUIInit({ appInfo: { appName: "...", @@ -246,7 +230,6 @@ supertokensUIInit({ }, recipeList: [ // other recipes.. - // highlight-start supertokensUITOTP.init(), supertokensUIMultiFactorAuth.init({ firstFactors: [ @@ -254,14 +237,13 @@ supertokensUIInit({ supertokensUIMultiFactorAuth.FactorIds.THIRDPARTY ] }) - // highlight-end ] }) ``` This change goes in the `supertokens-web-js` SDK config at the root of your application: -```tsx +```tsx {13,14} import SuperTokens from 'supertokens-web-js'; import MultiFactorAuth from 'supertokens-web-js/recipe/multifactorauth'; import Totp from "supertokens-web-js/recipe/totp"; @@ -274,32 +256,29 @@ SuperTokens.init({ }, recipeList: [ // other recipes... - // highlight-start MultiFactorAuth.init(), Totp.init() - // highlight-end ], }); ``` - + - + - Just like on the backend, we init the `totp` recipe in the `recipeList`. - We also init the `MultiFactorAuth` recipe, and pass in the first factors that we want to use. In this case, that would be `emailpassword` and `thirdparty` - same as the backend. Next, we need to add the TOTP pre-built UI when rendering the SuperTokens component: - + - + - - + + -```tsx +```tsx {14} import { SuperTokensWrapper } from "supertokens-auth-react"; import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; import { TOTPPreBuiltUI } from "supertokens-auth-react/recipe/totp/prebuiltui"; @@ -313,9 +292,7 @@ function App() {
- // highlight-start {getSuperTokensRoutesForReactRouterDom(reactRouterDOM, [/* ... */ TOTPPreBuiltUI, MultiFactorAuthPreBuiltUI])} - // highlight-end // ... other routes
@@ -326,63 +303,60 @@ function App() { } ``` -
+
- + -```tsx +```tsx {7,8,9} import { SuperTokensWrapper } from "supertokens-auth-react"; import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; import { TOTPPreBuiltUI } from "supertokens-auth-react/recipe/totp/prebuiltui"; import { MultiFactorAuthPreBuiltUI } from "supertokens-auth-react/recipe/multifactorauth/prebuiltui"; function App() { - // highlight-start if (canHandleRoute([/* ... */ TOTPPreBuiltUI, MultiFactorAuthPreBuiltUI])) { return getRoutingComponent([/* ... */ TOTPPreBuiltUI, MultiFactorAuthPreBuiltUI]) } - // highlight-end return ( {/*Your app*/} ); } ``` - + - +
- + - + -:::success -This step is not required for non React apps, since all the pre-built UI components are already added into the bundle. +:::success[This step is not required for non React apps, since all the pre-built UI components are already added into the bundle.] ::: - + -
+ With the above configuration, users will see `emailpassword` or social login UI when they visit the auth page. After completing that, users will be redirected to `/auth/mfa/totp` (assuming that the `websiteBasePath` is `/auth`) where they will be asked to setup the factor, or complete the TOTP challenge if they have already setup the factor before. The UI for this screen looks like: - [Factor Setup UI](https://6571be2867f75556541fde98-xieqfaxuuo.chromatic.com/?path=/story/totp-mfa--device-setup-with-single-next-option) - [Verification UI](https://6571be2867f75556541fde98-xieqfaxuuo.chromatic.com/?path=/story/totp-mfa--verification-with-single-next-option) (In case the factor is already setup before). -
+
- + We start by initialising the MFA and TOTP recipe on the frontend like so: - + - + - + - + -```tsx +```tsx {13,14} import SuperTokens from 'supertokens-web-js'; import MultiFactorAuth from 'supertokens-web-js/recipe/multifactorauth'; import Totp from "supertokens-web-js/recipe/totp"; @@ -395,22 +369,17 @@ SuperTokens.init({ }, recipeList: [ // other recipes... - // highlight-start MultiFactorAuth.init(), Totp.init() - // highlight-end ], }); ``` - + - + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensMultiFactorAuth from 'supertokens-web-js-script/recipe/multifactorauth'; -import supertokensTotp from "supertokens-web-js-script/recipe/totp"; +```tsx {9,10} supertokens.init({ appInfo: { apiDomain: "...", @@ -419,34 +388,31 @@ supertokens.init({ }, recipeList: [ // other recipes... - // highlight-start supertokensMultiFactorAuth.init(), supertokensTotp.init() - // highlight-end ], }); ``` - + - + - + - + -:::success -This step is not applicable for mobile apps. Please continue reading. +:::success[This step is not applicable for mobile apps. Please continue reading.] ::: - + - + -After the first factor login, you should start by [checking the access token payload and see if the MFA claim's `v` boolean is `false`](../frontend-setup#step-2-checking-the---custv-boolean-value-in-the-mfa-claim--cust). If it's not, then we can redirect the user to the application page. +After the first factor login, you should start by [checking the access token payload and see if the MFA claim's `v` boolean is `false`](/additional-verification/mfa/initial-setup#12-add-the-mfa-flow). If it's not, then we can redirect the user to the application page. -If it's `false`, the frontend then needs to [call the MFA endpoint](../frontend-setup#mfa-info-endpoint) to get information about which factor the user should be asked to complete next. Based on the backend config in this page, the `next` array will contain `["totp"]`. +If it's `false`, the frontend then needs to [call the MFA endpoint](/additional-verification/mfa/initial-setup#the-mfa-info-endpoint) to get information about which factor the user should be asked to complete next. Based on the backend config in this page, the `next` array will contain `["totp"]`. Two possibilities exist here: - Case 1: The user needs to setup a TOTP device cause they don't have any. @@ -461,13 +427,13 @@ In this case, we do two things: To create a new device, call the following API: - + - + - + - + ```tsx import Totp from "supertokens-web-js/recipe/totp" @@ -502,13 +468,11 @@ async function createNewTotpDevice() { } ``` - + - + ```tsx -import supertokensTotp from "supertokens-web-js-script/recipe/totp" -import supertokensSession from "supertokens-web-js-script/recipe/session" async function createNewTotpDevice() { if (await supertokensSession.doesSessionExist()) { try { @@ -538,15 +502,14 @@ async function createNewTotpDevice() { } ``` - + - + - + - + - The above API call returns the following response: @@ -563,9 +526,9 @@ The above API call returns the following response: } ``` - + - + - When device registration is successful, the API returns: - The `secret` and `qrCodeString` which are to be displayed to the user. For React apps, we recommend using the [react-qr-code library](https://github.com/rosskhanas/react-qr-code) to display the QR code. @@ -576,13 +539,13 @@ The above API call returns the following response: Once a device has been created, and scanned, you need to ask the user to enter the TOTP and call the API below to verify it: - + - + - + - + ```tsx import Totp from "supertokens-web-js/recipe/totp" @@ -620,13 +583,11 @@ async function verifyTotpDevice(deviceName: string, userInputTotp: string) { } ``` - + - + ```tsx -import supertokensTotp from "supertokens-web-js-script/recipe/totp" -import supertokensSession from "supertokens-web-js-script/recipe/session" async function verifyTotpDevice(deviceName: string, userInputTotp: string) { if (await supertokensSession.doesSessionExist()) { @@ -660,15 +621,14 @@ async function verifyTotpDevice(deviceName: string, userInputTotp: string) { } ``` - + - + - + - + - The above API call returns the following response: @@ -688,9 +648,9 @@ The above API call returns the following response: } ``` - + - + - The `deviceName`, which is an input to the API is one of the props returned from the previous API call to create a device. - When verification is successful (`status: "OK"`), the device is marked as verified in the database and can be used for the TOTP challenge next time around. The boolean `wasAlreadyVerified` indicates if the device was already verified before this call was made. @@ -701,19 +661,19 @@ The above API call returns the following response: - A status of `UNKNOWN_DEVICE_ERROR` is possible due to a race condition in which the device is somehow deleted before the verification call is made. - A status of `GENERAL_ERROR` is possible if you specifically return that from a backend API override. -On successful verification of a device, the `totp` factor is marked as completed and the `v` value is updated in the session based on if there are any more factors that the user needs to complete. The next step would be to check this `v` value in the MFA claim and redirect the user to the application page, or get information about the next factor using the [MFA info endpoint](../frontend-setup#mfa-info-endpoint). +On successful verification of a device, the `totp` factor is marked as completed and the `v` value is updated in the session based on if there are any more factors that the user needs to complete. The next step would be to check this `v` value in the MFA claim and redirect the user to the application page, or get information about the next factor using the [MFA info endpoint](/additional-verification/mfa/initial-setup#the-mfa-info-endpoint). #### Case 2 implementation: User needs to complete the TOTP challenge This case is when the user already has a device setup (`totp` is in `factorsThatAreAlreadySetup`), and needs to complete the TOTP challenge. In this case, you should show the user an input box asking them to enter their TOTP from the authenticator app and then call the following API: - + - + - + - + ```tsx import Totp from "supertokens-web-js/recipe/totp" @@ -747,13 +707,11 @@ async function verifyTotpCode(userInputTotp: string) { } ``` - + - + ```tsx -import supertokensTotp from "supertokens-web-js-script/recipe/totp" -import supertokensSession from "supertokens-web-js-script/recipe/session" async function verifyTotpCode(userInputTotp: string) { if (await supertokensSession.doesSessionExist()) { @@ -783,15 +741,14 @@ async function verifyTotpCode(userInputTotp: string) { } ``` - + - + - + - + - The above API call returns the following response: @@ -810,9 +767,9 @@ The above API call returns the following response: } ``` - + - + - A `status: OK` indicates that verification was successful. SuperTokens tries and verifies the input TOTP against all verified devices that belong to this user. - A status of `INVALID_TOTP_ERROR` means that the user has entered the an incorrect TOTP and needs to retry. The response contains two other props: @@ -822,14 +779,14 @@ The above API call returns the following response: - A status of `UNKNOWN_USER_ID_ERROR` is possible due to a race condition in which all devices that the user had are deleted by the time this API is called. In this case, you can ask users to setup a new device. - A status of `GENERAL_ERROR` is possible if you specifically return that from a backend API override. -On successful verification of the code, the `totp` factor is marked as completed and the `v` value is updated in the session based on if there are any more factors that the user needs to complete. The next step would be to check this `v` value in the MFA claim and redirect the user to the application page, or get information about the next factor using the [MFA info endpoint](../frontend-setup#mfa-info-endpoint). +On successful verification of the code, the `totp` factor is marked as completed and the `v` value is updated in the session based on if there are any more factors that the user needs to complete. The next step would be to check this `v` value in the MFA claim and redirect the user to the application page, or get information about the next factor using the [MFA info endpoint](/additional-verification/mfa/initial-setup#the-mfa-info-endpoint). - + -
+ - + In a multi tenancy setup, you may want to enable TOTP for all users, across all tenants, or for all users within specific tenants. For enabling for all users across all tenants, it's the same steps as in the [single tenant setup](#single-tenant-setup) section above, so in this section, we will focus on enabling TOTP for all users within specific tenants. @@ -837,10 +794,10 @@ In a multi tenancy setup, you may want to enable TOTP for all users, across all To start, we will initialise the TOTP and the MultiFactorAuth recipes in the following way: - - + + -```ts +```ts {25,26} import supertokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty" import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -865,23 +822,20 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-start totp.init(), MultiFactorAuth.init() - // highlight-end ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -897,7 +851,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ totp.init(), multifactorauth.init(), @@ -905,14 +859,14 @@ init( ) ``` - - + + Unlike the single tenant setup, we do not provide any config to the `MultiFactorAuth` recipe cause all the necessary configuration will be done on a tenant level. - + - + To configure TOTP requirement for a tenant, we can call the following API: @@ -941,18 +895,17 @@ async function createNewTenant() { - We set the `requiredSecondaryFactors` to `["totp"]` to indicate that TOTP is required for all users in this tenant. The default implementation of `getMFARequirementsForAuth` in the `MultiFactorAuth` takes this into account. - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant @@ -976,8 +929,8 @@ async def create_new_tenant(): pass ``` - - + + ```python from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant @@ -1001,12 +954,12 @@ def create_new_tenant(): pass ``` - - + + - + - + Once the user finishes the first factor (for example, with `emailpassword`), their session access token payload will look like this: ```json @@ -1040,15 +993,15 @@ Indicating that the user has finished all required factors, and should be allowe ### 2. Configure the frontend - + We start by modifying the `init` function call on the frontend like so: - + - + -```tsx +```tsx {12,15,16,17,18,19,20,21,22,23,24,25,26,27,28} import supertokens from "supertokens-auth-react" import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth" import totp from "supertokens-auth-react/recipe/totp" @@ -1060,11 +1013,9 @@ supertokens.init({ apiDomain: "...", websiteDomain: "...", }, - // highlight-next-line usesDynamicLoginMethods: true, recipeList: [ // other recipes... - // highlight-start totp.init(), MultiFactorAuth.init(), Multitenancy.init({ @@ -1079,25 +1030,20 @@ supertokens.init({ } } }) - // highlight-end ] }) ``` - + - + You will have to make changes to the auth route config, as well as to the `supertokens-web-js` SDK config at the root of your application: This change is in your auth route config. -```tsx +```tsx {9,12,13,14,15,16,17,18,19,20,21,22,23,24,25} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIMultiFactorAuth from "supertokens-auth-react-script/recipe/multifactorauth" -import supertokensUITOTP from "supertokens-auth-react-script/recipe/totp" -import supertokensUIMultitenancy from "supertokens-auth-react-script/recipe/multitenancy" supertokensUIInit({ appInfo: { @@ -1105,11 +1051,9 @@ supertokensUIInit({ apiDomain: "...", websiteDomain: "...", }, - // highlight-next-line usesDynamicLoginMethods: true, recipeList: [ // other recipes... - // highlight-start supertokensUITOTP.init(), supertokensUIMultiFactorAuth.init(), supertokensUIMultitenancy.init({ @@ -1124,17 +1068,13 @@ supertokensUIInit({ } } }) - // highlight-end ] }) ``` This change goes in the `supertokens-web-js` SDK config at the root of your application: -```tsx -import supertokens from "supertokens-web-js-script"; -import MultiFactorAuth from 'supertokens-web-js-script/recipe/multifactorauth'; -import Session from "supertokens-web-js-script/recipe/session"; +```tsx {9,10} supertokens.init({ appInfo: { @@ -1143,17 +1083,15 @@ supertokens.init({ appName: "...", }, recipeList: [ - // highlight-start Session.init(), MultiFactorAuth.init(), - // highlight-end ], }); ``` - + - + - Just like on the backend, we init the `totp` recipe in the `recipeList`. - We also init the `MultiFactorAuth` recipe. Notice that unlike the single tenant setup, we do not specify the `firstFactors` here. That information is fetched based on the tenantId you provide the SDK with. @@ -1162,15 +1100,14 @@ supertokens.init({ Next, we need to add the TOTP pre-built UI when rendering the SuperTokens component: - + - + - - + + -```tsx +```tsx {14} import { SuperTokensWrapper } from "supertokens-auth-react"; import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; import { TOTPPreBuiltUI } from "supertokens-auth-react/recipe/totp/prebuiltui"; @@ -1184,9 +1121,7 @@ function App() {
- // highlight-start {getSuperTokensRoutesForReactRouterDom(reactRouterDOM, [/* ... */ TOTPPreBuiltUI, MultiFactorAuthPreBuiltUI])} - // highlight-end // ... other routes
@@ -1197,56 +1132,51 @@ function App() { } ``` -
+
- + -```tsx +```tsx {7,8,9} import { SuperTokensWrapper } from "supertokens-auth-react"; import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; import { TOTPPreBuiltUI } from "supertokens-auth-react/recipe/totp/prebuiltui"; import { MultiFactorAuthPreBuiltUI } from "supertokens-auth-react/recipe/multifactorauth/prebuiltui"; function App() { - // highlight-start if (canHandleRoute([/* ... */ TOTPPreBuiltUI, MultiFactorAuthPreBuiltUI])) { return getRoutingComponent([/* ... */ TOTPPreBuiltUI, MultiFactorAuthPreBuiltUI]) } - // highlight-end return ( {/*Your app*/} ); } ``` - + - +
- + - + -:::success -This step is not required for non React apps, since all the pre-built UI components are already added into the bundle. +:::success[This step is not required for non React apps, since all the pre-built UI components are already added into the bundle.] ::: - + -
+ With the above configuration, users will see the first and second factor based on the tenant configuration. For the tenant we configured above, users will see email password or social login first. After completing that, users will be redirected to `/auth/mfa/totp` (assuming that the `websiteBasePath` is `/auth`) where they will be asked to setup the factor, or complete the TOTP challenge if they have already setup the factor before. The UI for this screen looks like: - [Factor Setup UI](https://6571be2867f75556541fde98-xieqfaxuuo.chromatic.com/?path=/story/totp-mfa--device-setup-with-single-next-option) - [Verification UI](https://6571be2867f75556541fde98-xieqfaxuuo.chromatic.com/?path=/story/totp-mfa--verification-with-single-next-option) (In case the factor is already setup before). -
+
- + The steps here are the same as in [the single tenant setup above](#frontend-setup). - - -
- + + diff --git a/docs/additional-verification/mfa/totp/totp-for-opt-in-users.mdx b/docs/additional-verification/mfa/totp/totp-for-opt-in-users.mdx index 10200bd907..6e6998e5c8 100644 --- a/docs/additional-verification/mfa/totp/totp-for-opt-in-users.mdx +++ b/docs/additional-verification/mfa/totp/totp-for-opt-in-users.mdx @@ -1,21 +1,10 @@ --- title: Require TOTP for specific users -hide_title: true -toc_max_heading_level: 4 -sidebar_position: 2 -description: >- - Implement a TOTP-based MFA policy for specific users based on customizable - criteria. -page_type: guide -recipe: mfa -category: multi-factor-authentication +description: Implement a TOTP-based MFA policy for specific users based on customizable criteria. +sidebar: + order: 2 --- - - -# Require TOTP for specific users - - ## Overview In this page, we will show you how to implement an MFA policy that requires certain users to do TOTP. You can decide which those users are based on any criteria. For example: @@ -29,13 +18,15 @@ Whatever the criteria is, the steps to implementing this type of a flow is the s The tutorial assumes that the first factor is email password or social login, but the same set of steps are applicable for other first factor types. - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: ## Steps - + - + ### 1. Configure the backend @@ -43,10 +34,10 @@ The tutorial assumes that the first factor is email password or social login, bu To start with, we configure the backend in the following way: - - + + -```ts +```ts {28,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50} import supertokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty" import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -74,14 +65,12 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-next-line totp.init(), MultiFactorAuth.init({ firstFactors: [ MultiFactorAuth.FactorIds.EMAILPASSWORD, MultiFactorAuth.FactorIds.THIRDPARTY ], - // highlight-start override: { functions: (originalImplementation) => { return { @@ -99,21 +88,19 @@ supertokens.init({ } } } - // highlight-end }) ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -165,7 +152,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ totp.init(), multifactorauth.init( @@ -176,8 +163,8 @@ init( ) ``` - - + + We override the `getMFARequirementsForAuth` function to indicate that `totp` must be completed only for users that have the `admin` role. You can also have any other criteria here. @@ -186,10 +173,10 @@ We override the `getMFARequirementsForAuth` function to indicate that `totp` mus To start with, we configure the backend in the following way: - - + + -```ts +```ts {26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50} import supertokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty" import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -215,7 +202,6 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-start totp.init({ override: { apis: (oI) => { @@ -241,20 +227,18 @@ supertokens.init({ MultiFactorAuth.FactorIds.THIRDPARTY ], }) - // highlight-end ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -308,7 +292,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ totp.init(TOTPConfig(override=OverrideConfig(apis=totp_override))), multifactorauth.init( @@ -318,8 +302,8 @@ init( ) ``` - - + + We initialise the multi factor auth recipe here without any override to `getMFARequirementsForAuth`. The default implementation of this function already checks what factors are enabled for a user and returns those. Therefore all we need to do is mark `totp` as enabled for a user as soon as they have setup a device successfully. This happens in the `verifyDevicePOST` API override as shown above. Once a device is verified, we mark the `totp` factor as enabled for the user, and the next time they login, they will be asked to complete the TOTP challenge. @@ -372,8 +356,8 @@ The second part, which is only applicable in case you want to allow users to ena In order to know if the user has enabled TOTP, you can make an API your backend which calls the following function: - - + + ```ts import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; @@ -384,18 +368,17 @@ async function isTotpEnabledForUser(userId: string) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multifactorauth.asyncio import get_required_secondary_factors_for_user @@ -406,8 +389,8 @@ async def is_totp_factor_enabled_for_user(user_id: str) -> bool: return FactorIds.TOTP in factors ``` - - + + ```python from supertokens_python.recipe.multifactorauth.syncio import get_required_secondary_factors_for_user @@ -418,16 +401,16 @@ def is_totp_factor_enabled_for_user(user_id: str) -> bool: return FactorIds.TOTP in factors ``` - - + + - - + + If the user wants to enable or disable TOTP for them, you can make an API on your backend which calls the following function: - - + + ```ts import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; @@ -441,18 +424,17 @@ async function disableMFAForUser(userId: string) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multifactorauth.asyncio import ( @@ -469,8 +451,8 @@ async def disable_mfa_for_user(user_id: str) -> None: await remove_from_required_secondary_factors_for_user(user_id, FactorIds.TOTP) ``` - - + + ```python from supertokens_python.recipe.multifactorauth.syncio import ( @@ -487,21 +469,21 @@ def disable_mfa_for_user(user_id: str) -> None: remove_from_required_secondary_factors_for_user(user_id, FactorIds.OTP_EMAIL) ``` - - + + - - + + In order to list existing TOTP devices on the frontend, you can call the following API: - + - + - + - + ```tsx import Session from "supertokens-web-js/recipe/session" @@ -530,13 +512,11 @@ async function fetchTOTPDevices() { } ``` - + - + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session" -import supertokensTotp from "supertokens-web-js-script/recipe/totp" async function fetchTOTPDevices() { if (await supertokensSession.doesSessionExist()) { @@ -561,20 +541,19 @@ async function fetchTOTPDevices() { } ``` - + - + - + - + - Notice that the API call requires the session's access token as an input (this should be added by our frontend SDK automatically): ```bash -curl --location --request GET '^{appInfo.apiDomain}^{appInfo.apiBasePath}/totp/device/list' \ +curl --location --request GET '/auth/totp/device/list' \ --header 'Authorization: Bearer ...' ``` @@ -594,22 +573,22 @@ The output from the API call is as follows: } ``` - + - + - A `status: OK` will contain the list of all devices that exist for this user, across all of the user's tenants. We recommend only showing the devices that are `verified` to the user. - A `status: GENERAL_ERROR`: This is possible if you have overridden the backend API to send back a custom error message which should be displayed on the frontend In order to remove a device, you can call the following API from the frontend: - + - + - + - + ```tsx import Session from "supertokens-web-js/recipe/session" @@ -636,13 +615,11 @@ async function removeTOTPDevices(deviceName: string) { } ``` - + - + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session" -import supertokensTotp from "supertokens-web-js-script/recipe/totp" async function removeTOTPDevices(deviceName: string) { if (await supertokensSession.doesSessionExist()) { @@ -665,20 +642,19 @@ async function removeTOTPDevices(deviceName: string) { } ``` - + - + - + - + - Notice that the API call requires the session's access token as an input (this should be added by our frontend SDK automatically): ```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/totp/device/remove' \ +curl --location --request POST '/auth/totp/device/remove' \ --header 'Authorization: Bearer ...' --header 'Content-Type: application/json' \ --data-raw '{ @@ -697,16 +673,16 @@ The output from the API call is as follows: } ``` - + - + - + - + - - + + In order to add a new device, you can call the following function from the frontend. This function will redirect the user to the TOTP create device pre-built UI. After the user has finished the new device creation and verification, they will be redirected back to the current page: @@ -726,31 +702,31 @@ async function redirectToTotpSetupScreen() { - You can also redirect the user to `/{websiteBasePath}/mfa/totp?setup=true&redirectToPath={currentPath}` if you don't want to use the above function. - + - + In order to add a new device, you can redirect the user to `/{websiteBasePath}/mfa/totp?setup=true&redirectToPath={currentPath}` from your settings page. This will show the [TOTP factor setup screen](https://6571be2867f75556541fde98-xieqfaxuuo.chromatic.com/?path=/story/totp-mfa--device-setup-with-single-next-option) to the user: - We add the query param of `setup=true` because we want to create a new device. - The `redirectToPath` query param will also tell our SDK to redirect the user back to the current page after they have finished creating the device. - + - + After the user has finished creating a device, our backend override for `verifyDevicePOST` (see "Example 2" in [Backend setup section](#backend-setup) above) will add TOTP as a required factor for this user, ensuring that next time they login, they will be asked to complete the TOTP challenge. - + - + In order to create a new device, you should redirect the user to a page which creates a new TOTP device on the backend, asks the user to scan the QR code and then to enter the TOTP in order to verify the new device. This can be achieved by calling the functions mentioned in [this section](./totp-for-all-users#case-1-implementation-user-needs-to-setup-a-new-totp-device--cust). - + - + - + ### 1. Configure the backend @@ -761,10 +737,10 @@ However, if you want TOTP to be enabled for a specific user, for a specific tena #### Only enable TOTP for users that have an `admin` role - - + + -```ts +```ts {28,40} import supertokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty" import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -792,7 +768,6 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-next-line totp.init(), MultiFactorAuth.init({ firstFactors: [ @@ -805,7 +780,6 @@ supertokens.init({ ...originalImplementation, getMFARequirementsForAuth: async function (input) { let roles = await UserRoles.getRolesForUser(input.tenantId, (await input.user).id) - // highlight-next-line if (roles.roles.includes("admin") && (await input.requiredSecondaryFactorsForTenant).includes(MultiFactorAuth.FactorIds.TOTP)) { // we only want totp for admins return [MultiFactorAuth.FactorIds.TOTP] @@ -822,15 +796,14 @@ supertokens.init({ }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -885,7 +858,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ multifactorauth.init( first_factors=[FactorIds.EMAILPASSWORD, FactorIds.THIRDPARTY], @@ -896,19 +869,18 @@ init( ) ``` - - + + - The implementation of `shouldRequireTotpForTenant` is entirely up to you. - #### Ask for TOTP only for users that have enabled TOTP on their account - - + + -```ts +```ts {50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66} import supertokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty" import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -958,7 +930,6 @@ supertokens.init({ MultiFactorAuth.FactorIds.EMAILPASSWORD, MultiFactorAuth.FactorIds.THIRDPARTY ], - // highlight-start override: { functions: (originalImplementation) => { return { @@ -976,21 +947,19 @@ supertokens.init({ } } } - // highlight-end }) ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -1070,7 +1039,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ totp.init(TOTPConfig(override=OverrideConfig(apis=totp_override))), multifactorauth.init( @@ -1081,8 +1050,8 @@ init( ) ``` - - + + - We provide an override for `getMFARequirementsForAuth` which checks if TOTP is enabled for the user, and also take into account the tenantId to decide if we want to have this user go through the TOTP flow whilst logging into this tenant. The implementation of `shouldRequireTotpForTenant` is entirely up to you. @@ -1093,7 +1062,7 @@ Two parts exist to this: - Configuring the frontend to show the TOTP UI when required during login / sign up - Allowing users to enable / disable TOTP on their account via the settings page (If you are following Example 2 from above). -The first part is identical to the steps mentioned in [this section](/docs/additional-verification/mfa/totp/totp-for-all-users#2-configure-the-), so please follow that. +The first part is identical to the steps mentioned in [this section](/additional-verification/mfa/totp/totp-for-all-users#2-configure-the-), so please follow that. The second part, which is only applicable in case you want to allow users to enable / disable TOTP themselves, can be achieved by creating the following flow on your frontend: - When the user navigates to their settings page, you can show them if TOTP is enabled or not. @@ -1102,8 +1071,8 @@ The second part, which is only applicable in case you want to allow users to ena In order to know if the user has enabled TOTP, you can make an API your backend which calls the following function: - - + + ```ts import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; @@ -1114,18 +1083,17 @@ async function isTotpEnabledForUser(userId: string) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multifactorauth.asyncio import get_required_secondary_factors_for_user @@ -1136,8 +1104,8 @@ async def is_totp_factor_enabled_for_user(user_id: str) -> bool: return FactorIds.TOTP in factors ``` - - + + ```python from supertokens_python.recipe.multifactorauth.syncio import get_required_secondary_factors_for_user @@ -1148,16 +1116,16 @@ def is_totp_factor_enabled_for_user(user_id: str) -> bool: return FactorIds.TOTP in factors ``` - - + + - - + + If the user wants to enable or disable TOTP for them, you can make an API on your backend which calls the following function: - - + + ```ts import MultiFactorAuth from "supertokens-node/recipe/multifactorauth"; @@ -1171,18 +1139,17 @@ async function disableMFAForUser(userId: string) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multifactorauth.asyncio import ( @@ -1199,8 +1166,8 @@ async def disable_mfa_for_user(user_id: str) -> None: await remove_from_required_secondary_factors_for_user(user_id, FactorIds.TOTP) ``` - - + + ```python from supertokens_python.recipe.multifactorauth.syncio import ( @@ -1217,21 +1184,21 @@ def disable_mfa_for_user(user_id: str) -> None: remove_from_required_secondary_factors_for_user(user_id, FactorIds.OTP_EMAIL) ``` - - + + - - + + In order to list existing TOTP devices on the frontend, you can call the following API: - + - + - + - + ```tsx import Session from "supertokens-web-js/recipe/session" @@ -1260,13 +1227,11 @@ async function fetchTOTPDevices() { } ``` - + - + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session" -import supertokensTotp from "supertokens-web-js-script/recipe/totp" async function fetchTOTPDevices() { if (await supertokensSession.doesSessionExist()) { @@ -1291,20 +1256,19 @@ async function fetchTOTPDevices() { } ``` - + - + - + - + - Notice that the API call requires the session's access token as an input (this should be added by our frontend SDK automatically): ```bash -curl --location --request GET '^{appInfo.apiDomain}^{appInfo.apiBasePath}/totp/device/list' \ +curl --location --request GET '/auth/totp/device/list' \ --header 'Authorization: Bearer ...' ``` @@ -1324,22 +1288,22 @@ The output from the API call is as follows: } ``` - + - + - A `status: OK` will contain the list of all devices that exist for this user, across all of the user's tenants. We recommend only showing the devices that are `verified` to the user. - A `status: GENERAL_ERROR`: This is possible if you have overridden the backend API to send back a custom error message which should be displayed on the frontend In order to remove a device, you can call the following API from the frontend: - + - + - + - + ```tsx import Session from "supertokens-web-js/recipe/session" @@ -1366,13 +1330,11 @@ async function removeTOTPDevices(deviceName: string) { } ``` - + - + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session" -import supertokensTotp from "supertokens-web-js-script/recipe/totp" async function removeTOTPDevices(deviceName: string) { if (await supertokensSession.doesSessionExist()) { @@ -1395,20 +1357,19 @@ async function removeTOTPDevices(deviceName: string) { } ``` - + - + - + - + - Notice that the API call requires the session's access token as an input (this should be added by our frontend SDK automatically): ```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/totp/device/remove' \ +curl --location --request POST '/auth/totp/device/remove' \ --header 'Authorization: Bearer ...' --header 'Content-Type: application/json' \ --data-raw '{ @@ -1427,16 +1388,16 @@ The output from the API call is as follows: } ``` - + - + - + - + - - + + In order to add a new device, you can call the following function from the frontend. This function will redirect the user to the TOTP create device pre-built UI. After the user has finished the new device creation and verification, they will be redirected back to the current page: @@ -1456,27 +1417,26 @@ async function redirectToTotpSetupScreen() { - You can also redirect the user to `/{websiteBasePath}/mfa/totp?setup=true&redirectToPath={currentPath}` if you don't want to use the above function. - + - + In order to add a new device, you can redirect the user to `/{websiteBasePath}/mfa/totp?setup=true&redirectToPath={currentPath}` from your settings page. This will show the [TOTP factor setup screen](https://6571be2867f75556541fde98-xieqfaxuuo.chromatic.com/?path=/story/totp-mfa--device-setup-with-single-next-option) to the user: - We add the query param of `setup=true` because we want to create a new device. - The `redirectToPath` query param will also tell our SDK to redirect the user back to the current page after they have finished creating the device. - + - + After the user has finished creating a device, our backend override for `verifyDevicePOST` (see "Example 2" in [Backend setup section](#1-configure-the-backend) above) will add TOTP as a required factor for this user, so that next time they login, they will be asked to complete the TOTP challenge. - + - + In order to create a new device, you should redirect the user to a page which creates a new TOTP device on the backend, asks the user to scan the QR code and then to enter the TOTP in order to verify the new device. This can be achieved by calling the functions mentioned in [this section](./totp-for-all-users#case-1-implementation-user-needs-to-setup-a-new-totp-device--cust). - - - + + diff --git a/docs/additional-verification/mfa/webauthn-secondary-factor-setup.mdx b/docs/additional-verification/mfa/webauthn-setup.mdx similarity index 73% rename from docs/additional-verification/mfa/webauthn-secondary-factor-setup.mdx rename to docs/additional-verification/mfa/webauthn-setup.mdx index 425f037735..1edb57616d 100644 --- a/docs/additional-verification/mfa/webauthn-secondary-factor-setup.mdx +++ b/docs/additional-verification/mfa/webauthn-setup.mdx @@ -1,18 +1,12 @@ --- -id: webauthn-setup -title: Passkeys/WebAuthn -hide_title: true -sidebar_position: 6.2 +title: Passkeys/WebAuthn description: >- - Implement WebAuthn/Passkey multi-factor authentication that requires all users to complete passkey authentication before accessing the application. -page_type: guide -recipe: mfa -category: multi-factor-authentication + Implement WebAuthn/Passkey multi-factor authentication that requires all users to complete passkey authentication + before accessing the application. +sidebar: + order: 6.2 --- -# Implement WebAuthn as a secondary factor - - ## Overview This guide shows how to implement an MFA policy that requires all users to use WebAuthn before they get access to your application. @@ -21,22 +15,24 @@ This guide shows how to implement an MFA policy that requires all users to use W The tutorial assumes that the first factor is email password or social login, but the same set of steps are applicable for other first factor types. - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: ## Steps - + ### 1. Configure the backend - + To start with, we configure the backend in the following way: - - + + -```ts +```ts {25,31,32,33,34,35,36,37,38,39,40,41} import supertokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty" import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -61,14 +57,12 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-next-line webauthn.init(), MultiFactorAuth.init({ firstFactors: [ MultiFactorAuth.FactorIds.EMAILPASSWORD, MultiFactorAuth.FactorIds.THIRDPARTY ], - // highlight-start override: { functions: (originalImplementation) => { return { @@ -80,21 +74,19 @@ supertokens.init({ } } } - // highlight-end }) ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -138,7 +130,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ webauthn.init(), multifactorauth.init( @@ -149,8 +141,8 @@ init( ) ``` - - + + The MFA recipe override is required to indicate that `webauthn` must be completed before the user can access the app. @@ -182,19 +174,19 @@ The `v` being `false` indicates that there are still factors that are pending. A Indicating that the user has finished all required factors, and should be allowed to access the app. - + - + In a multi tenancy setup, you may want to enable WebAuthn for all users, across all tenants, or for all users within specific tenants. For enabling for all users across all tenants, it's the same steps as in the [single tenant setup](#single-tenant-setup) section above, so in this section, we will focus on enabling WebAuthn for all users within specific tenants. To start, we will initialise the WebAuthn and the MultiFactorAuth recipes in the following way: - - + + -```ts +```ts {25,26} import supertokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty" import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -219,23 +211,20 @@ supertokens.init({ EmailPassword.init({ //... }), - // highlight-start webauthn.init(), MultiFactorAuth.init() - // highlight-end ] }) ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -251,7 +240,7 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework="...", # type: ignore + framework="...", recipe_list=[ webauthn.init(), multifactorauth.init(), @@ -259,14 +248,14 @@ init( ) ``` - - + + Unlike the single tenant setup, we do not provide any config to the `MultiFactorAuth` recipe cause all the necessary configuration will be done on a tenant level. - + - + To configure WebAuthn requirement for a tenant, we can call the following API: @@ -295,18 +284,17 @@ async function createNewTenant() { - We set the `requiredSecondaryFactors` to `["webauthn"]` to indicate that WebAuthn is required for all users in this tenant. The default implementation of `getMFARequirementsForAuth` in the `MultiFactorAuth` takes this into account. - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant @@ -330,8 +318,8 @@ async def create_new_tenant(): pass ``` - - + + ```python from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant @@ -355,12 +343,12 @@ def create_new_tenant(): pass ``` - - + + - + - + Once the user finishes the first factor (for example, with `emailpassword`), their session access token payload will look like this: ```json @@ -390,23 +378,23 @@ The `v` being `false` indicates that there are still factors that are pending. A Indicating that the user has finished all required factors, and should be allowed to access the app. - + ### 2. Configure the frontend - + - + We start by modifying the `init` function call on the frontend like so: - + - + - + -```tsx +```tsx {14,15,16,17,18,19,20,21,22,23,24,25,26,27} import supertokens from "supertokens-auth-react" import Multitenancy from "supertokens-auth-react/recipe/multitenancy" import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth" @@ -420,7 +408,6 @@ supertokens.init({ }, recipeList: [ // other recipes.. - // highlight-start webauthn.init(), MultiFactorAuth.init(), Multitenancy.init({ @@ -435,25 +422,20 @@ supertokens.init({ } } }) - // highlight-end ] }) ``` - + - + You will have to make changes to the auth route config, as well as to the `supertokens-web-js` SDK config at the root of your application: This change is in your auth route config. -```tsx +```tsx {11,12,13,14,15,16,17,18,19,20,21,22,23,24} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIMultiFactorAuth from "supertokens-auth-react-script/recipe/multifactorauth" -import supertokensUIWebAuthn from "supertokens-auth-react-script/recipe/webauthn" -import supertokensUIMultitenancy from "supertokens-auth-react-script/recipe/multitenancy" supertokensUIInit({ appInfo: { @@ -463,7 +445,6 @@ supertokensUIInit({ }, recipeList: [ // other recipes.. - // highlight-start supertokensUIWebAuthn.init(), supertokensUIMultiFactorAuth.init(), supertokensUIMultitenancy.init({ @@ -478,14 +459,13 @@ supertokensUIInit({ } } }) - // highlight-end ] }) ``` This change goes in the `supertokens-web-js` SDK config at the root of your application: -```tsx +```tsx {13,14} import SuperTokens from 'supertokens-web-js'; import MultiFactorAuth from 'supertokens-web-js/recipe/multifactorauth'; import WebAuthn from "supertokens-web-js/recipe/webauthn"; @@ -498,27 +478,25 @@ SuperTokens.init({ }, recipeList: [ // other recipes... - // highlight-start MultiFactorAuth.init(), WebAuthn.init() - // highlight-end ], }); ``` - + - + - + - + - + - + -```tsx +```tsx {13,14,15,16,17,18,19} import supertokens from "supertokens-auth-react" import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth" import webauthn from "supertokens-auth-react/recipe/webauthn" @@ -531,7 +509,6 @@ supertokens.init({ }, recipeList: [ // other recipes.. - // highlight-start webauthn.init(), MultiFactorAuth.init({ firstFactors: [ @@ -539,24 +516,20 @@ supertokens.init({ MultiFactorAuth.FactorIds.THIRDPARTY ] }) - // highlight-end ] }) ``` - + - + You will have to make changes to the auth route config, as well as to the `supertokens-web-js` SDK config at the root of your application: This change is in your auth route config. -```tsx +```tsx {10,11,12,13,14,15,16} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIMultiFactorAuth from "supertokens-auth-react-script/recipe/multifactorauth" -import supertokensUIWebAuthn from "supertokens-auth-react-script/recipe/webauthn" supertokensUIInit({ appInfo: { appName: "...", @@ -565,7 +538,6 @@ supertokensUIInit({ }, recipeList: [ // other recipes.. - // highlight-start supertokensUIWebAuthn.init(), supertokensUIMultiFactorAuth.init({ firstFactors: [ @@ -573,14 +545,13 @@ supertokensUIInit({ supertokensUIMultiFactorAuth.FactorIds.THIRDPARTY ] }) - // highlight-end ] }) ``` This change goes in the `supertokens-web-js` SDK config at the root of your application: -```tsx +```tsx {13,14} import SuperTokens from 'supertokens-web-js'; import MultiFactorAuth from 'supertokens-web-js/recipe/multifactorauth'; import WebAuthn from "supertokens-web-js/recipe/webauthn"; @@ -593,19 +564,17 @@ SuperTokens.init({ }, recipeList: [ // other recipes... - // highlight-start MultiFactorAuth.init(), WebAuthn.init() - // highlight-end ], }); ``` - + - + - + On the frontend, the `MultiFactorAuth` recipe intialization only requires the first factors to be configured. @@ -613,15 +582,14 @@ The secondary factors will be determined based on a requiest to the backend. Add the WebAuthn pre-built UI to render the SuperTokens component: - + - + - - + + -```tsx +```tsx {14} import { SuperTokensWrapper } from "supertokens-auth-react"; import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; import { WebauthnPreBuiltUI } from "supertokens-auth-react/recipe/webauthn/prebuiltui"; @@ -635,9 +603,7 @@ function App() {
- // highlight-start {getSuperTokensRoutesForReactRouterDom(reactRouterDOM, [/* ... */ WebauthnPreBuiltUI, MultiFactorAuthPreBuiltUI])} - // highlight-end // ... other routes
@@ -648,59 +614,56 @@ function App() { } ``` -
+
- + -```tsx +```tsx {7,8,9} import { SuperTokensWrapper } from "supertokens-auth-react"; import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; import { WebauthnPreBuiltUI } from "supertokens-auth-react/recipe/webauthn/prebuiltui"; import { MultiFactorAuthPreBuiltUI } from "supertokens-auth-react/recipe/multifactorauth/prebuiltui"; function App() { - // highlight-start if (canHandleRoute([/* ... */ WebauthnPreBuiltUI, MultiFactorAuthPreBuiltUI])) { return getRoutingComponent([/* ... */ WebauthnPreBuiltUI, MultiFactorAuthPreBuiltUI]) } - // highlight-end return ( {/*Your app*/} ); } ``` - + - +
- + - + -:::success -This step is not required for non React apps, since all the pre-built UI components are already added into the bundle. +:::success[This step is not required for non React apps, since all the pre-built UI components are already added into the bundle.] ::: - + -
+ -
+ - + We start by initialising the MFA and WebAuthn recipe on the frontend like so: - + - + - + - + -```tsx +```tsx {13,14} import SuperTokens from 'supertokens-web-js'; import MultiFactorAuth from 'supertokens-web-js/recipe/multifactorauth'; import WebAuthn from "supertokens-web-js/recipe/webauthn"; @@ -713,22 +676,17 @@ SuperTokens.init({ }, recipeList: [ // other recipes... - // highlight-start MultiFactorAuth.init(), WebAuthn.init() - // highlight-end ], }); ``` - + - + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensMultiFactorAuth from 'supertokens-web-js-script/recipe/multifactorauth'; -import supertokensWebAuthn from "supertokens-web-js-script/recipe/webauthn"; +```tsx {9,10} supertokens.init({ appInfo: { apiDomain: "...", @@ -737,35 +695,32 @@ supertokens.init({ }, recipeList: [ // other recipes... - // highlight-start supertokensMultiFactorAuth.init(), supertokensWebAuthn.init() - // highlight-end ], }); ``` - + - + - + - + -:::success -This step is not applicable for mobile apps. Please continue reading. +:::success[This step is not applicable for mobile apps. Please continue reading.] ::: - + - + After the first factor login, you should start by checking the access token payload and see if the MFA claim's `v` boolean is `false`. 'If it's not, then you can redirect the user to the application page. -If it's `false`, the frontend then needs to [call the MFA endpoint](/docs/references/fdi/mfa/put-mfa-info) to get information about which factor the user should be asked to complete next. +If it's `false`, the frontend then needs to [call the MFA endpoint](/references/fdi/multifactorauth-recipe/getmfainfo) to get information about which factor the user should be asked to complete next. Based on the initial backend configuration, the `next` array will contain `["webauthn"]`. To complete the secondary factor you need to take into account if the users has previously configured a passkey or not. @@ -774,13 +729,13 @@ You can determine this by checking if the `alreadySetup` array contains `"webaut #### Sign up flow - + - + - + - + ```ts import Webauthn from "supertokens-web-js/recipe/webauthn" @@ -797,13 +752,11 @@ async function secondFactorSignUp(email: string, userContext: Record + - + ```ts -import supertokensWebauthn from "supertokens-web-js-script/recipe/webauthn" -import supertokensSession from "supertokens-web-js-script/recipe/session" async function secondFactorSignUp(email: string, userContext: Record) { const response = await recipeImplementation.registerCredentialWithSignUp({ @@ -816,33 +769,33 @@ async function secondFactorSignUp(email: string, userContext: Record + - + - + - + Support for this flow is not available in the mobile SDK. -You will have to call the [backend API](/docs/references/fdi/introduction) directly. +You will have to call the [backend API](/references/fdi/introduction) directly. -First, call the [**Register WebAuthn Credential**](/docs/references/fdi/webauthn/post-webauthn-credential) endpoint to register the passkey. -Afterwards call the [**Sign Up with WebAuthn**](/docs/references/fdi/webauthn/post-webauthn-signup) to complete the second factor sign up process. +First, call the [**Register WebAuthn Credential**](/references/fdi/webauthn-recipe/webauthnregistercredential) endpoint to register the passkey. +Afterwards call the [**Sign Up with WebAuthn**](/references/fdi/webauthn-recipe/webauthnsignup) to complete the second factor sign up process. - + - + #### Sign in flow - + - + - + - + ```ts import Webauthn from "supertokens-web-js/recipe/webauthn" import Session from "supertokens-web-js/recipe/session" @@ -856,12 +809,10 @@ async function secondFactorSignUp(userContext: Record) { return response.status === "OK"; } ``` - + - + ```ts -import supertokensWebauthn from "supertokens-web-js-script/recipe/webauthn" -import supertokensSession from "supertokens-web-js-script/recipe/session" async function secondFactorSignUp(userContext: Record) { const response = await recipeImplementation.authenticateCredentialWithSignIn({ @@ -872,29 +823,27 @@ async function secondFactorSignUp(userContext: Record) { return response.status === "OK"; } ``` - + + - + - - - + Support for this flow is not available in the mobile SDK. -You will have to call the [backend API](/docs/references/fdi/introduction) directly. - -Call the [**Sign in with WebAuthn**](/docs/references/fdi/webauthn/post-webauthn-signin) endpoint to complete the secondary factor flow. +You will have to call the [backend API](/references/fdi/introduction) directly. +Call the [**Sign in with WebAuthn**](/references/fdi/webauthn-recipe/webauthnsignin) endpoint to complete the secondary factor flow. - - + + - + That's it! :tada: diff --git a/docs/additional-verification/session-verification/_blocks/session-object.mdx b/docs/additional-verification/session-verification/_blocks/session-object.mdx deleted file mode 100644 index e40fb02bbd..0000000000 --- a/docs/additional-verification/session-verification/_blocks/session-object.mdx +++ /dev/null @@ -1,458 +0,0 @@ - - - - -```tsx -import { RecipeUserId } from "supertokens-node"; // typecheck-only -import { ReqResInfo } from "supertokens-node/recipe/session/types"; // typecheck-only -import { JSONObject } from "supertokens-node/types"; // typecheck-only -import { SessionClaimValidator, SessionClaim } from "supertokens-website"; // typecheck-only - -interface Session { - /** - * Destroys this session in the database and on the frontend. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves when the session is successfully revoked. - */ - revokeSession(userContext?: Record): Promise; - - /** - * Retrieves the session data stored in the database associated with the session. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves with the session data. - */ - getSessionDataFromDatabase(userContext?: Record): Promise; - - /** - * Sets a new JSON object to the session data stored in the database. - * @param newSessionData The new session data to store. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves when the session data is updated. - */ - updateSessionDataInDatabase(newSessionData: any, userContext?: Record): Promise; - - /** - * Returns the user ID of the logged-in user. - * @param userContext Optional context object for additional data. - * @returns The user ID as a string. - */ - getUserId(userContext?: Record): string; - - /** - * Returns the `RecipeUserId` object for the session. It represents the user ID of the specific login method for this user. - * @param userContext Optional context object for additional data. - * @returns The `RecipeUserId`. - */ - getRecipeUserId(userContext?: Record): RecipeUserId; - - /** - * Returns the tenant ID of the session. The default value is "public" if multi-tenancy is not used. - * @param userContext Optional context object for additional data. - * @returns The tenant ID as a string. - */ - getTenantId(userContext?: Record): string; - - /** - * Returns the access token's payload for this session. This includes user-defined claims, standard claims, and SuperTokens specific ones. - * @param userContext Optional context object for additional data. - * @returns The access token payload. - */ - getAccessTokenPayload(userContext?: Record): any; - - /** - * Returns the `sessionHandle` for this session, a unique string constant for each session. - * @param userContext Optional context object for additional data. - * @returns The session handle as a string. - */ - getHandle(userContext?: Record): string; - - /** - * Returns an object containing the raw string representation of all tokens associated with the session, along with an update status. - * @returns An object with accessToken, refreshToken, antiCsrfToken, frontToken, and accessAndFrontTokenUpdated. - */ - getAllSessionTokensDangerously(): { - accessToken: string; - refreshToken: string | undefined; - antiCsrfToken: string | undefined; - frontToken: string; - accessAndFrontTokenUpdated: boolean; - }; - - /** - * Returns the raw string access token for this session. - * @param userContext Optional context object for additional data. - * @returns The access token as a string. - */ - getAccessToken(userContext?: Record): string; - - /** - * Adds key/value pairs into a JSON object in the access token. Setting a key to null removes it from the payload. - * @param accessTokenPayloadUpdate The updates to apply to the access token payload. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves when the payload is updated. - */ - mergeIntoAccessTokenPayload(accessTokenPayloadUpdate: JSONObject, userContext?: Record): Promise; - - /** - * Returns the time in milliseconds of when this session was created. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves with the creation time in milliseconds. - */ - getTimeCreated(userContext?: Record): Promise; - - /** - * Returns the time in milliseconds of when this session will expire if not refreshed. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves with the expiry time in milliseconds. - */ - getExpiry(userContext?: Record): Promise; - - /** - * Asserts the validity of custom session claims using provided validators. - * @param claimValidators An array of session claim validators. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves when the claim assertions are complete. - */ - assertClaims(claimValidators: SessionClaimValidator[], userContext?: Record): Promise; - - /** - * Fetches and sets a custom claim in the session. - * @param claim The session claim to fetch and set. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves with the fetched claim. - */ - fetchAndSetClaim(claim: SessionClaim, userContext?: Record): Promise; - - /** - * Sets the value of a session claim. - * @param claim The session claim to update. - * @param value The new value for the claim. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves when the claim value is set. - */ - setClaimValue(claim: SessionClaim, value: T, userContext?: Record): Promise; - - /** - * Gets the value of a session claim. - * @param claim The session claim to retrieve the value for. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves with the claim value, or undefined if not found. - */ - getClaimValue(claim: SessionClaim, userContext?: Record): Promise; - - /** - * Removes a session claim. - * @param claim The session claim to remove. - * @param userContext Optional context object for additional data. - * @returns A promise that resolves when the claim is removed. - */ - removeClaim(claim: SessionClaim, userContext?: Record): Promise; - - /** - * Attaches the session to a request-response cycle. - * @param reqResInfo Information about the request-response. - * @param userContext Optional context object for additional data. - * @returns A promise or void once the session is attached. - */ - attachToRequestResponse(reqResInfo: ReqResInfo, userContext?: Record): Promise | void; -} -``` - - - - -### `getSessionDataFromDatabase` vs `getAccessTokenPayload` - - - - -| | `getSessionDataFromDatabase` | `getAccessTokenPayload` | -|--------------------------------------|-----------------------------|-------------------------| -| **Source of Data** | Queries SuperTokens Core database | Reads directly from the access token in the request | -| **Speed** | Slower (requires a network call) | Faster (no network call required) | -| **Data Sensitivity** | Secure—data is not exposed to the frontend | The access token includes data, which is accessible to the frontend | -| **Use Case** | Best for storing sensitive session-related data | Best for frequently accessed data like user roles | -| **Persistence** | Updated via `updateSessionDataInDatabase` | Updated via `mergeIntoAccessTokenPayload` | - - - - -```go - -import ( // typecheck-only - "github.com/supertokens/supertokens-golang/recipe/session/claims" // typecheck-only - "github.com/supertokens/supertokens-golang/supertokens" // typecheck-only -) // typecheck-only - -type TypeSessionContainer struct { - // Destroys this session in the database and on the frontend. - RevokeSession func() error - - // Retrieves the session data stored in the database associated with the session. - GetSessionDataInDatabase func() (map[string]interface{}, error) - - // Sets a new JSON object to the session data stored in the database. - // `newSessionData` is the new session data to store. - UpdateSessionDataInDatabase func(newSessionData map[string]interface{}) error - - // Returns the user ID of the logged-in user. - GetUserID func() string - - // Returns the tenant ID of the session. - // Default value is "public" if multi-tenancy is not used. - GetTenantId func() string - - // Returns the access token's payload for this session. - // Includes user-defined claims, standard claims, and SuperTokens specific ones. - GetAccessTokenPayload func() map[string]interface{} - - // Returns the `sessionHandle` for this session, - // a unique string constant for each session. - GetHandle func() string - - // Returns an object containing the raw string representation - // of all tokens associated with the session, along with an update status. - GetAllSessionTokensDangerously func() SessionTokens - - // Returns the raw string access token for this session. - GetAccessToken func() string - - // Returns the time in milliseconds of when this session was created. - GetTimeCreated func() (uint64, error) - - // Returns the time in milliseconds of when this session will expire if not refreshed. - GetExpiry func() (uint64, error) - - // Context-aware methods that provide the same functionality as their counterparts above while considering user context - - // Destroys this session in the database and on the frontend with user context. - RevokeSessionWithContext func(userContext supertokens.UserContext) error - - // Retrieves the session data stored in the database associated with the session with user context. - GetSessionDataInDatabaseWithContext func(userContext supertokens.UserContext) (map[string]interface{}, error) - - // Sets a new JSON object to the session data stored in the database with user context. - UpdateSessionDataInDatabaseWithContext func(newSessionData map[string]interface{}, userContext supertokens.UserContext) error - - // Returns the user ID of the logged-in user with user context. - GetUserIDWithContext func(userContext supertokens.UserContext) string - - // Returns the tenant ID of the session with user context. - GetTenantIdWithContext func(userContext supertokens.UserContext) string - - // Returns the access token's payload for this session with user context. - GetAccessTokenPayloadWithContext func(userContext supertokens.UserContext) map[string]interface{} - - // Returns the `sessionHandle` for this session with user context. - GetHandleWithContext func(userContext supertokens.UserContext) string - - // Returns the raw string access token for this session with user context. - GetAccessTokenWithContext func(userContext supertokens.UserContext) string - - // Returns the time in milliseconds of when this session was created with user context. - GetTimeCreatedWithContext func(userContext supertokens.UserContext) (uint64, error) - - // Returns the time in milliseconds of when this session will expire if not refreshed with user context. - GetExpiryWithContext func(userContext supertokens.UserContext) (uint64, error) - - // Adds key/value pairs into a JSON object in the access token with user context. - // Setting a key to nil removes it from the payload. - MergeIntoAccessTokenPayloadWithContext func(accessTokenPayloadUpdate map[string]interface{}, userContext supertokens.UserContext) error - - // Asserts the validity of custom session claims using provided validators with user context. - AssertClaimsWithContext func(claimValidators []claims.SessionClaimValidator, userContext supertokens.UserContext) error - - // Fetches and sets a custom claim in the session with user context. - FetchAndSetClaimWithContext func(claim *claims.TypeSessionClaim, userContext supertokens.UserContext) error - - // Sets the value of a session claim with user context. - SetClaimValueWithContext func(claim *claims.TypeSessionClaim, value interface{}, userContext supertokens.UserContext) error - - // Gets the value of a session claim with user context. - // Returns the value or nil if not found. - GetClaimValueWithContext func(claim *claims.TypeSessionClaim, userContext supertokens.UserContext) interface{} - - // Removes a session claim with user context. - RemoveClaimWithContext func(claim *claims.TypeSessionClaim, userContext supertokens.UserContext) error - - // Attaches the session to a request-response cycle with user context. - AttachToRequestResponseWithContext func(info RequestResponseInfo, userContext supertokens.UserContext) error - - // Adds key/value pairs into a JSON object in the access token. - // Setting a key to nil removes it from the payload. - MergeIntoAccessTokenPayload func(accessTokenPayloadUpdate map[string]interface{}) error - - // Asserts the validity of custom session claims using provided validators. - AssertClaims func(claimValidators []claims.SessionClaimValidator) error - - // Fetches and sets a custom claim in the session. - FetchAndSetClaim func(claim *claims.TypeSessionClaim) error - - // Sets the value of a session claim. - SetClaimValue func(claim *claims.TypeSessionClaim, value interface{}) error - - // Gets the value of a session claim. - // Returns the value or nil if not found. - GetClaimValue func(claim *claims.TypeSessionClaim) interface{} - - // Removes a session claim. - RemoveClaim func(claim *claims.TypeSessionClaim) error - - // Attaches the session to a request-response cycle. - AttachToRequestResponse func(info RequestResponseInfo) error -} -``` - - - -### `GetSessionDataFromDatabase` vs `GetAccessTokenPayload` - - - -| | `GetSessionDataFromDatabase` | `GetAccessTokenPayload` | -|--------------------------------------|-----------------------------|-------------------------| -| **Source of Data** | Queries SuperTokens Core database | Reads directly from the access token in the request | -| **Speed** | Slower (requires a network call) | Faster (no network call required) | -| **Data Sensitivity** | Secure—data is not exposed to the frontend | The access token includes data, which is accessible to the frontend | -| **Use Case** | Best for storing sensitive session-related data | Best for frequently accessed data like user roles | -| **Persistence** | Updated via `UpdateSessionDataInDatabase` | Updated via `MergeIntoAccessTokenPayload` | - - - - - -```python -# exclude-from-type-checking - -class Session: - # Destroys this session in the database and on the frontend. - # Optional user_context can be used for additional contextual data. - async def revoke_session(self, user_context: Optional[Dict[str, Any]] = None) -> None: - pass - - # Retrieves the session data stored in the database associated with the session. - # Optional user_context can be used for additional contextual data. - async def get_session_data_from_database(self, user_context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: - pass - - # Sets a new JSON object to the session data stored in the database. - # `new_session_data` is the new session data to store. - # Optional user_context can be used for additional contextual data. - async def update_session_data_in_database(self, new_session_data: Dict[str, Any], user_context: Optional[Dict[str, Any]] = None) -> None: - pass - - # Returns the user ID of the logged-in user. - # Optional user_context can be used for additional contextual data. - def get_user_id(self, user_context: Optional[Dict[str, Any]] = None) -> str: - pass - - # Returns the `RecipeUserId` object for the session. - # This represents the user ID of the specific login method for this user. - # Optional user_context can be used for additional contextual data. - def get_recipe_user_id(self, user_context: Optional[Dict[str, Any]] = None) -> RecipeUserId: - pass - - # Returns the tenant ID of the session. - # Default value is "public" if multi-tenancy is not used. - # Optional user_context can be used for additional contextual data. - def get_tenant_id(self, user_context: Optional[Dict[str, Any]] = None) -> str: - pass - - # Returns the access token's payload for this session. - # Includes user-defined claims, standard claims, and SuperTokens specific ones. - # Optional user_context can be used for additional contextual data. - def get_access_token_payload(self, user_context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: - pass - - # Returns the `sessionHandle` for this session, - # a unique string constant for each session. - # Optional user_context can be used for additional contextual data. - def get_handle(self, user_context: Optional[Dict[str, Any]] = None) -> str: - pass - - # Returns an object containing the raw string representation - # of all tokens associated with the session, along with an update status. - def get_all_session_tokens_dangerously(self) -> GetSessionTokensDangerouslyDict: - pass - - # Returns the raw string access token for this session. - # Optional user_context can be used for additional contextual data. - def get_access_token(self, user_context: Optional[Dict[str, Any]] = None) -> str: - pass - - # Adds key/value pairs into a JSON object in the access token. - # Setting a key to None removes it from the payload. - # `access_token_payload_update` contains the updates to apply. - # Optional user_context can be used for additional contextual data. - async def merge_into_access_token_payload(self, access_token_payload_update: JSONObject, user_context: Optional[Dict[str, Any]] = None) -> None: - pass - - # Returns the time in milliseconds of when this session was created. - # Optional user_context can be used for additional contextual data. - async def get_time_created(self, user_context: Optional[Dict[str, Any]] = None) -> int: - pass - - # Returns the time in milliseconds of when this session will expire if not refreshed. - # Optional user_context can be used for additional contextual data. - async def get_expiry(self, user_context: Optional[Dict[str, Any]] = None) -> int: - pass - - # Asserts the validity of custom session claims using provided validators. - # `claim_validators` is an array of session claim validators. - # Optional user_context can be used for additional contextual data. - async def assert_claims(self, claim_validators: List[SessionClaimValidator], user_context: Optional[Dict[str, Any]] = None) -> None: - pass - - # Fetches and sets a custom claim in the session. - # `claim` is the session claim to fetch and set. - # Optional user_context can be used for additional contextual data. - async def fetch_and_set_claim(self, claim: SessionClaim[Any], user_context: Optional[Dict[str, Any]] = None) -> None: - pass - - # Sets the value of a session claim. - # `claim` is the session claim to update. - # `value` is the new value for the claim. - # Optional user_context can be used for additional contextual data. - async def set_claim_value(self, claim: SessionClaim[_T], value: _T, user_context: Optional[Dict[str, Any]] = None) -> None: - pass - - # Gets the value of a session claim. - # `claim` is the session claim to retrieve the value for. - # Optional user_context can be used for additional contextual data. - # Returns a promise that resolves with the claim value, or None if not found. - async def get_claim_value(self, claim: SessionClaim[_T], user_context: Optional[Dict[str, Any]] = None) -> Union[_T, None]: - pass - - # Removes a session claim. - # `claim` is the session claim to remove. - # Optional user_context can be used for additional contextual data. - async def remove_claim(self, claim: SessionClaim[Any], user_context: Optional[Dict[str, Any]] = None) -> None: - pass - - # Attaches the session to a request-response cycle. - # `req_res_info` contains information about the request-response. - # Optional user_context can be used for additional contextual data. - async def attach_to_request_response(self, request: BaseRequest, transfer_method: TokenTransferMethod, user_context: Optional[Dict[str, Any]] = None) -> None: - pass -``` - - - - -### `get_session_data_from_database` vs `get_access_token_payload` - - - - -| | `get_session_data_from_database` | `get_access_token_payload` | -|--------------------------------------|-----------------------------|-------------------------| -| **Source of Data** | Queries SuperTokens Core database | Reads directly from the access token in the request | -| **Speed** | Slower (requires a network call) | Faster (no network call required) | -| **Data Sensitivity** | Secure—data is not exposed to the frontend | The access token includes data, which is accessible to the frontend | -| **Use Case** | Best for storing sensitive session-related data | Best for frequently accessed data like user roles | -| **Persistence** | Updated via `update_session_data_in_database` | Updated via `merge_into_access_token_payload` | - - - - - diff --git a/docs/additional-verification/session-verification/_category_.json b/docs/additional-verification/session-verification/_category_.json deleted file mode 100644 index 13cc1d829d..0000000000 --- a/docs/additional-verification/session-verification/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Session Verification", - "position": 1 -} diff --git a/docs/additional-verification/session-verification/claim-validation.mdx b/docs/additional-verification/session-verification/claim-validation.mdx index dae4b24bb0..4771949791 100644 --- a/docs/additional-verification/session-verification/claim-validation.mdx +++ b/docs/additional-verification/session-verification/claim-validation.mdx @@ -1,17 +1,10 @@ --- title: Claims validation -hide_title: true -toc_max_heading_level: 5 -sidebar_position: 5 description: Validate your resources based on claims that get attached to the session. -page_type: guide -recipe: session -category: session-verification +sidebar: + order: 5 --- - -# Claim validation - ## Overview **SuperTokens** provides two approaches for managing access control: @@ -36,16 +29,13 @@ This guide shows you how to use each method. ## References - - -## Session Claim - + + ### Session claim interface ```tsx import { RecipeUserId } from "supertokens-node"; -type JSONObject = any; // REMOVE_FROM_OUTPUT interface SessionClaim { // Unique identifier for the claim. // For a `boolean` claim (for example if the email is verified or not), this would be a string like `"st-ev"`. @@ -61,7 +51,6 @@ interface SessionClaim { recipeUserId: RecipeUserId, tenantId: string, currentPayload: JSONObject | undefined, - // @ts-expect-error userContext: UserContext ): Promise | T | undefined; @@ -70,7 +59,6 @@ interface SessionClaim { * * @returns The modified payload object */ - // @ts-expect-error removeFromPayload(payload: JSONObject, userContext: UserContext): JSONObject; /** @@ -78,7 +66,6 @@ interface SessionClaim { * * @returns Claim value */ - // @ts-expect-error getValueFromPayload(payload: JSONObject, userContext: UserContext): T | undefined; } ``` @@ -94,7 +81,6 @@ All the recipe claims are built around these primitives: - [`PermissionClaim`](https://github.com/supertokens/supertokens-node/blob/master/lib/ts/recipe/userroles/permissionClaim.ts): This stores the list of permissions associated with the user. - #### On the frontend Like the backend, the frontend also has the concept of session claim objects which need to conform to the following interface: @@ -119,14 +105,12 @@ Like the backend SDK, the frontend SDK also exposes a few base claims: - [`BooleanClaim`](https://github.com/supertokens/supertokens-website/blob/master/lib/ts/claims/booleanClaim.ts) - [`PrimitiveClaim`](https://github.com/supertokens/supertokens-website/blob/master/lib/ts/claims/primitiveClaim.ts) - [`PrimitiveArrayClaim`](https://github.com/supertokens/supertokens-website/blob/master/lib/ts/claims/primitiveArrayClaim.ts) - -## Claim Validator - + + Once you add a claim to the session, specify the checks that need to run on them during session verification. For example, if an API should allow access only to `admin` roles, there must be a way to tell SuperTokens to do that check. This is where claim validators come into the picture. Here is the shape for a claim validator object: ```tsx -type SessionClaim = any; // REMOVE_FROM_OUTPUT type SessionClaimValidator = { // Identifies the session claim validator // Used to know which validator failed in case multiple of them undergo checking at the same time. @@ -160,7 +144,6 @@ type ClaimValidationResult = { isValid: true } | { isValid: false; reason?: any Using this interface and the claims interface, SuperTokens runs the following session claim validation process during session verification: ```tsx -// @ts-nocheck function validateSessionClaims(accessToken, claimValidators) { payload = accessToken.getPayload(); @@ -211,13 +194,12 @@ interface SessionClaim { getValueFromPayload(payload: any): T | undefined; } ``` - - + ## Before you start - +:::info[Access token guidance] --- @@ -263,7 +245,6 @@ SuperTokens.init({ return { ...originalImplementation, getGlobalClaimValidators: async function (input) { - // @ts-expect-error return [...input.claimValidatorsAddedByOtherRecipes, SecondFactorClaim.validators.isTrue()]; }, }; @@ -326,7 +307,6 @@ const AdminRoute = (props: React.PropsWithChildren) => { import { Error as STError } from "supertokens-node/recipe/session"; import { UserRoleClaim } from "supertokens-node/recipe/userroles"; -// @ts-expect-error if (roles === undefined || !roles.includes("admin")) { throw new STError({ type: "INVALID_CLAIMS", @@ -371,8 +351,7 @@ The access token payload is a simple way to store custom data that needs to be a ### 1. Add Custom Claims to the Access Token Payload -:::important -The access token payload has a set of default claims that can not be overwritten. +:::note[The access token payload has a set of default claims that can not be overwritten.] They reserve these for standard or SuperTokens specific use-cases. Those claims are: `sub`, `iat`, `exp`, `sessionHandle`, `refreshTokenHash1`, `parentRefreshTokenHash1`, `antiCsrfToken` @@ -475,10 +454,10 @@ async function someFunc() { ## See also - - - - - - - + + + + + + + diff --git a/docs/additional-verification/session-verification/meta.ts b/docs/additional-verification/session-verification/meta.ts new file mode 100644 index 0000000000..21ae3c3c39 --- /dev/null +++ b/docs/additional-verification/session-verification/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Session Verification", + "icon": "badge-check", + "order": 1 +}); diff --git a/docs/additional-verification/session-verification/protect-api-routes.mdx b/docs/additional-verification/session-verification/protect-api-routes.mdx index aba9015a1c..474c5ee77e 100644 --- a/docs/additional-verification/session-verification/protect-api-routes.mdx +++ b/docs/additional-verification/session-verification/protect-api-routes.mdx @@ -1,22 +1,10 @@ --- title: Protect backend routes -hide_title: true -sidebar_position: 1 -description: >- - Explore three session verification methods with SuperTokens: middleware, - function, and manual JWT verification. -type: guide -page_type: guide -recipe: session -category: session-verification +description: 'Explore three session verification methods with SuperTokens: middleware, function, and manual JWT verification.' +sidebar: + order: 1 --- - -import SessionObject from "./_blocks/session-object.mdx"; - - -# Protect API routes - ## Overview You can choose between three different methods to check for a session inside an API route handler. @@ -27,7 +15,7 @@ Check each method to see which one works for you. ## Before you start - +:::info[Access token guidance] --- @@ -38,30 +26,28 @@ This function acts as a middleware inside your API endpoints. Hence, it requires that your backend framework supports the concept of middlewares. Besides checking for a session, it also writes responses to the client on its own, based on the session's validity and the provided configuration. - - - - + + + + -```tsx +```tsx {7,8} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; let app = express(); -// highlight-start app.post("/like-comment", verifySession(), (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - // highlight-end //.... }); ``` - - + + -```tsx +```tsx {10,11,12,13,14,15,16,17,18} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import { SessionRequest } from "supertokens-node/framework/hapi"; @@ -71,7 +57,6 @@ let server = Hapi.server({ port: 8000 }); server.route({ path: "/like-comment", method: "post", - //highlight-start options: { pre: [ { @@ -81,35 +66,32 @@ server.route({ }, handler: async (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - //highlight-end //... } }) ``` - - + + -```tsx +```tsx {7,8,9,10} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import { SessionRequest } from "supertokens-node/framework/fastify"; let fastify = Fastify(); -//highlight-start fastify.post("/like-comment", { preHandler: verifySession(), }, (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - //highlight-end //.... }); ``` - - + + -```tsx +```tsx {9} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEventV2 } from "supertokens-node/framework/awsLambda"; @@ -118,66 +100,60 @@ async function likeComment(awsEvent: SessionEventV2) { //.... }; -//highlight-next-line exports.handler = verifySession(likeComment); ``` - - + + -```tsx +```tsx {7,8} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from "supertokens-node/framework/koa"; let router = new KoaRouter(); -//highlight-start router.post("/like-comment", verifySession(), (ctx: SessionContext, next) => { let userId = ctx.session!.getUserId(); - //highlight-end //.... }); ``` - - + + -```tsx +```tsx {7,8,9,10,11,12} import { inject, intercept } from "@loopback/core"; import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; import { SessionContext } from "supertokens-node/framework/loopback"; class LikeComment { - //highlight-start constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { } @post("/like-comment") @intercept(verifySession()) @response(200) handler() { let userId = (this.ctx as SessionContext).session!.getUserId(); - //highlight-end //.... } } ``` - - + + + - - + -```tsx +```tsx {5,6,7,8,9,10,11,12,13,14} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; -// highlight-start export default async function likeComment(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { @@ -188,7 +164,6 @@ export default async function likeComment(req: SessionRequest, res: any) { ) let userId = req.session!.getUserId(); - // highlight-end //.... } ``` @@ -200,7 +175,6 @@ export default async function likeComment(req: SessionRequest, res: any) { import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -219,13 +193,12 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {10,11} import { Controller, Post, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; @Controller() @@ -233,21 +206,19 @@ export class ExampleController { @Post('example') @UseGuards(new AuthGuard()) // For more information about this guard please read our NestJS guide. async postExample(@Session() session: SessionContainer): Promise { - //highlight-start let userId = session.getUserId(); - //highlight-end //.... return true; } } ``` - - - - - - + + + + + + ```go import ( @@ -274,8 +245,8 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + ```go import ( @@ -317,8 +288,8 @@ func likeCommentAPI(c *gin.Context) { } ``` - - + + ```go import ( @@ -346,8 +317,8 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + ```go import ( @@ -375,56 +346,52 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + - - + + -```python +```python {7,8,9} from fastapi import Depends from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.fastapi import verify_session -# highlight-start -@app.post('/like_comment') # type: ignore +@app.post('/like_comment') async def like_comment(session: SessionContainer = Depends(verify_session())): user_id = session.get_user_id() - # highlight-end print(user_id) ``` - - + + -```python +```python {7,8,9,10,11,12} from flask import g from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.flask import verify_session -# highlight-start -@app.route('/update-jwt', methods=['POST']) # type: ignore +@app.route('/update-jwt', methods=['POST']) @verify_session() def like_comment(): - session: SessionContainer = g.supertokens # type: ignore + session: SessionContainer = g.supertokens user_id = session.get_user_id() - # highlight-end print(user_id) ``` - - + + -```python +```python {9,10,11,12,13} from typing import cast from django.http import HttpRequest @@ -433,31 +400,473 @@ from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.django.asyncio import verify_session -# highlight-start @verify_session() async def like_comment(request: HttpRequest): - session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore + session: SessionContainer = cast(SessionContainer, request.supertokens) user_id = session.get_user_id() - # highlight-end print(user_id) ``` - - - - - + + + + + + + + +```tsx + +interface Session { + /** + * Destroys this session in the database and on the frontend. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the session is successfully revoked. + */ + revokeSession(userContext?: Record): Promise; + + /** + * Retrieves the session data stored in the database associated with the session. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves with the session data. + */ + getSessionDataFromDatabase(userContext?: Record): Promise; + + /** + * Sets a new JSON object to the session data stored in the database. + * @param newSessionData The new session data to store. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the session data is updated. + */ + updateSessionDataInDatabase(newSessionData: any, userContext?: Record): Promise; + + /** + * Returns the user ID of the logged-in user. + * @param userContext Optional context object for additional data. + * @returns The user ID as a string. + */ + getUserId(userContext?: Record): string; + + /** + * Returns the `RecipeUserId` object for the session. It represents the user ID of the specific login method for this user. + * @param userContext Optional context object for additional data. + * @returns The `RecipeUserId`. + */ + getRecipeUserId(userContext?: Record): RecipeUserId; + + /** + * Returns the tenant ID of the session. The default value is "public" if multi-tenancy is not used. + * @param userContext Optional context object for additional data. + * @returns The tenant ID as a string. + */ + getTenantId(userContext?: Record): string; + + /** + * Returns the access token's payload for this session. This includes user-defined claims, standard claims, and SuperTokens specific ones. + * @param userContext Optional context object for additional data. + * @returns The access token payload. + */ + getAccessTokenPayload(userContext?: Record): any; + + /** + * Returns the `sessionHandle` for this session, a unique string constant for each session. + * @param userContext Optional context object for additional data. + * @returns The session handle as a string. + */ + getHandle(userContext?: Record): string; + + /** + * Returns an object containing the raw string representation of all tokens associated with the session, along with an update status. + * @returns An object with accessToken, refreshToken, antiCsrfToken, frontToken, and accessAndFrontTokenUpdated. + */ + getAllSessionTokensDangerously(): { + accessToken: string; + refreshToken: string | undefined; + antiCsrfToken: string | undefined; + frontToken: string; + accessAndFrontTokenUpdated: boolean; + }; + + /** + * Returns the raw string access token for this session. + * @param userContext Optional context object for additional data. + * @returns The access token as a string. + */ + getAccessToken(userContext?: Record): string; + + /** + * Adds key/value pairs into a JSON object in the access token. Setting a key to null removes it from the payload. + * @param accessTokenPayloadUpdate The updates to apply to the access token payload. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the payload is updated. + */ + mergeIntoAccessTokenPayload(accessTokenPayloadUpdate: JSONObject, userContext?: Record): Promise; + + /** + * Returns the time in milliseconds of when this session was created. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves with the creation time in milliseconds. + */ + getTimeCreated(userContext?: Record): Promise; + + /** + * Returns the time in milliseconds of when this session will expire if not refreshed. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves with the expiry time in milliseconds. + */ + getExpiry(userContext?: Record): Promise; + + /** + * Asserts the validity of custom session claims using provided validators. + * @param claimValidators An array of session claim validators. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the claim assertions are complete. + */ + assertClaims(claimValidators: SessionClaimValidator[], userContext?: Record): Promise; + + /** + * Fetches and sets a custom claim in the session. + * @param claim The session claim to fetch and set. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves with the fetched claim. + */ + fetchAndSetClaim(claim: SessionClaim, userContext?: Record): Promise; + + /** + * Sets the value of a session claim. + * @param claim The session claim to update. + * @param value The new value for the claim. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the claim value is set. + */ + setClaimValue(claim: SessionClaim, value: T, userContext?: Record): Promise; + + /** + * Gets the value of a session claim. + * @param claim The session claim to retrieve the value for. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves with the claim value, or undefined if not found. + */ + getClaimValue(claim: SessionClaim, userContext?: Record): Promise; + + /** + * Removes a session claim. + * @param claim The session claim to remove. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the claim is removed. + */ + removeClaim(claim: SessionClaim, userContext?: Record): Promise; + + /** + * Attaches the session to a request-response cycle. + * @param reqResInfo Information about the request-response. + * @param userContext Optional context object for additional data. + * @returns A promise or void once the session is attached. + */ + attachToRequestResponse(reqResInfo: ReqResInfo, userContext?: Record): Promise | void; +} +``` + + +
+ +### `getSessionDataFromDatabase` vs `getAccessTokenPayload` + +
+ + +| | `getSessionDataFromDatabase` | `getAccessTokenPayload` | +|--------------------------------------|-----------------------------|-------------------------| +| **Source of Data** | Queries SuperTokens Core database | Reads directly from the access token in the request | +| **Speed** | Slower (requires a network call) | Faster (no network call required) | +| **Data Sensitivity** | Secure—data is not exposed to the frontend | The access token includes data, which is accessible to the frontend | +| **Use Case** | Best for storing sensitive session-related data | Best for frequently accessed data like user roles | +| **Persistence** | Updated via `updateSessionDataInDatabase` | Updated via `mergeIntoAccessTokenPayload` | + +
+ + +```go + + +type TypeSessionContainer struct { + // Destroys this session in the database and on the frontend. + RevokeSession func() error + + // Retrieves the session data stored in the database associated with the session. + GetSessionDataInDatabase func() (map[string]interface{}, error) + + // Sets a new JSON object to the session data stored in the database. + // `newSessionData` is the new session data to store. + UpdateSessionDataInDatabase func(newSessionData map[string]interface{}) error + + // Returns the user ID of the logged-in user. + GetUserID func() string + + // Returns the tenant ID of the session. + // Default value is "public" if multi-tenancy is not used. + GetTenantId func() string + + // Returns the access token's payload for this session. + // Includes user-defined claims, standard claims, and SuperTokens specific ones. + GetAccessTokenPayload func() map[string]interface{} + + // Returns the `sessionHandle` for this session, + // a unique string constant for each session. + GetHandle func() string + + // Returns an object containing the raw string representation + // of all tokens associated with the session, along with an update status. + GetAllSessionTokensDangerously func() SessionTokens + + // Returns the raw string access token for this session. + GetAccessToken func() string + + // Returns the time in milliseconds of when this session was created. + GetTimeCreated func() (uint64, error) + + // Returns the time in milliseconds of when this session will expire if not refreshed. + GetExpiry func() (uint64, error) + + // Context-aware methods that provide the same functionality as their counterparts above while considering user context + + // Destroys this session in the database and on the frontend with user context. + RevokeSessionWithContext func(userContext supertokens.UserContext) error + + // Retrieves the session data stored in the database associated with the session with user context. + GetSessionDataInDatabaseWithContext func(userContext supertokens.UserContext) (map[string]interface{}, error) + + // Sets a new JSON object to the session data stored in the database with user context. + UpdateSessionDataInDatabaseWithContext func(newSessionData map[string]interface{}, userContext supertokens.UserContext) error + + // Returns the user ID of the logged-in user with user context. + GetUserIDWithContext func(userContext supertokens.UserContext) string + + // Returns the tenant ID of the session with user context. + GetTenantIdWithContext func(userContext supertokens.UserContext) string -## The `Session` object + // Returns the access token's payload for this session with user context. + GetAccessTokenPayloadWithContext func(userContext supertokens.UserContext) map[string]interface{} - + // Returns the `sessionHandle` for this session with user context. + GetHandleWithContext func(userContext supertokens.UserContext) string + // Returns the raw string access token for this session with user context. + GetAccessTokenWithContext func(userContext supertokens.UserContext) string + + // Returns the time in milliseconds of when this session was created with user context. + GetTimeCreatedWithContext func(userContext supertokens.UserContext) (uint64, error) + + // Returns the time in milliseconds of when this session will expire if not refreshed with user context. + GetExpiryWithContext func(userContext supertokens.UserContext) (uint64, error) + + // Adds key/value pairs into a JSON object in the access token with user context. + // Setting a key to nil removes it from the payload. + MergeIntoAccessTokenPayloadWithContext func(accessTokenPayloadUpdate map[string]interface{}, userContext supertokens.UserContext) error + + // Asserts the validity of custom session claims using provided validators with user context. + AssertClaimsWithContext func(claimValidators []claims.SessionClaimValidator, userContext supertokens.UserContext) error + + // Fetches and sets a custom claim in the session with user context. + FetchAndSetClaimWithContext func(claim *claims.TypeSessionClaim, userContext supertokens.UserContext) error + + // Sets the value of a session claim with user context. + SetClaimValueWithContext func(claim *claims.TypeSessionClaim, value interface{}, userContext supertokens.UserContext) error + + // Gets the value of a session claim with user context. + // Returns the value or nil if not found. + GetClaimValueWithContext func(claim *claims.TypeSessionClaim, userContext supertokens.UserContext) interface{} + + // Removes a session claim with user context. + RemoveClaimWithContext func(claim *claims.TypeSessionClaim, userContext supertokens.UserContext) error + + // Attaches the session to a request-response cycle with user context. + AttachToRequestResponseWithContext func(info RequestResponseInfo, userContext supertokens.UserContext) error + + // Adds key/value pairs into a JSON object in the access token. + // Setting a key to nil removes it from the payload. + MergeIntoAccessTokenPayload func(accessTokenPayloadUpdate map[string]interface{}) error + + // Asserts the validity of custom session claims using provided validators. + AssertClaims func(claimValidators []claims.SessionClaimValidator) error + + // Fetches and sets a custom claim in the session. + FetchAndSetClaim func(claim *claims.TypeSessionClaim) error + + // Sets the value of a session claim. + SetClaimValue func(claim *claims.TypeSessionClaim, value interface{}) error + + // Gets the value of a session claim. + // Returns the value or nil if not found. + GetClaimValue func(claim *claims.TypeSessionClaim) interface{} + + // Removes a session claim. + RemoveClaim func(claim *claims.TypeSessionClaim) error + + // Attaches the session to a request-response cycle. + AttachToRequestResponse func(info RequestResponseInfo) error +} +``` + +
+ +### `GetSessionDataFromDatabase` vs `GetAccessTokenPayload` + +
+ +| | `GetSessionDataFromDatabase` | `GetAccessTokenPayload` | +|--------------------------------------|-----------------------------|-------------------------| +| **Source of Data** | Queries SuperTokens Core database | Reads directly from the access token in the request | +| **Speed** | Slower (requires a network call) | Faster (no network call required) | +| **Data Sensitivity** | Secure—data is not exposed to the frontend | The access token includes data, which is accessible to the frontend | +| **Use Case** | Best for storing sensitive session-related data | Best for frequently accessed data like user roles | +| **Persistence** | Updated via `UpdateSessionDataInDatabase` | Updated via `MergeIntoAccessTokenPayload` | + +
+ + + +```python +# exclude-from-type-checking + +class Session: + # Destroys this session in the database and on the frontend. + # Optional user_context can be used for additional contextual data. + async def revoke_session(self, user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Retrieves the session data stored in the database associated with the session. + # Optional user_context can be used for additional contextual data. + async def get_session_data_from_database(self, user_context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: + pass + + # Sets a new JSON object to the session data stored in the database. + # `new_session_data` is the new session data to store. + # Optional user_context can be used for additional contextual data. + async def update_session_data_in_database(self, new_session_data: Dict[str, Any], user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Returns the user ID of the logged-in user. + # Optional user_context can be used for additional contextual data. + def get_user_id(self, user_context: Optional[Dict[str, Any]] = None) -> str: + pass + + # Returns the `RecipeUserId` object for the session. + # This represents the user ID of the specific login method for this user. + # Optional user_context can be used for additional contextual data. + def get_recipe_user_id(self, user_context: Optional[Dict[str, Any]] = None) -> RecipeUserId: + pass + + # Returns the tenant ID of the session. + # Default value is "public" if multi-tenancy is not used. + # Optional user_context can be used for additional contextual data. + def get_tenant_id(self, user_context: Optional[Dict[str, Any]] = None) -> str: + pass + + # Returns the access token's payload for this session. + # Includes user-defined claims, standard claims, and SuperTokens specific ones. + # Optional user_context can be used for additional contextual data. + def get_access_token_payload(self, user_context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: + pass + + # Returns the `sessionHandle` for this session, + # a unique string constant for each session. + # Optional user_context can be used for additional contextual data. + def get_handle(self, user_context: Optional[Dict[str, Any]] = None) -> str: + pass + + # Returns an object containing the raw string representation + # of all tokens associated with the session, along with an update status. + def get_all_session_tokens_dangerously(self) -> GetSessionTokensDangerouslyDict: + pass + + # Returns the raw string access token for this session. + # Optional user_context can be used for additional contextual data. + def get_access_token(self, user_context: Optional[Dict[str, Any]] = None) -> str: + pass + + # Adds key/value pairs into a JSON object in the access token. + # Setting a key to None removes it from the payload. + # `access_token_payload_update` contains the updates to apply. + # Optional user_context can be used for additional contextual data. + async def merge_into_access_token_payload(self, access_token_payload_update: JSONObject, user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Returns the time in milliseconds of when this session was created. + # Optional user_context can be used for additional contextual data. + async def get_time_created(self, user_context: Optional[Dict[str, Any]] = None) -> int: + pass + + # Returns the time in milliseconds of when this session will expire if not refreshed. + # Optional user_context can be used for additional contextual data. + async def get_expiry(self, user_context: Optional[Dict[str, Any]] = None) -> int: + pass + + # Asserts the validity of custom session claims using provided validators. + # `claim_validators` is an array of session claim validators. + # Optional user_context can be used for additional contextual data. + async def assert_claims(self, claim_validators: List[SessionClaimValidator], user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Fetches and sets a custom claim in the session. + # `claim` is the session claim to fetch and set. + # Optional user_context can be used for additional contextual data. + async def fetch_and_set_claim(self, claim: SessionClaim[Any], user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Sets the value of a session claim. + # `claim` is the session claim to update. + # `value` is the new value for the claim. + # Optional user_context can be used for additional contextual data. + async def set_claim_value(self, claim: SessionClaim[_T], value: _T, user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Gets the value of a session claim. + # `claim` is the session claim to retrieve the value for. + # Optional user_context can be used for additional contextual data. + # Returns a promise that resolves with the claim value, or None if not found. + async def get_claim_value(self, claim: SessionClaim[_T], user_context: Optional[Dict[str, Any]] = None) -> Union[_T, None]: + pass + + # Removes a session claim. + # `claim` is the session claim to remove. + # Optional user_context can be used for additional contextual data. + async def remove_claim(self, claim: SessionClaim[Any], user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Attaches the session to a request-response cycle. + # `req_res_info` contains information about the request-response. + # Optional user_context can be used for additional contextual data. + async def attach_to_request_response(self, request: BaseRequest, transfer_method: TokenTransferMethod, user_context: Optional[Dict[str, Any]] = None) -> None: + pass +``` + + +
+ +### `get_session_data_from_database` vs `get_access_token_payload` + +
+ + +| | `get_session_data_from_database` | `get_access_token_payload` | +|--------------------------------------|-----------------------------|-------------------------| +| **Source of Data** | Queries SuperTokens Core database | Reads directly from the access token in the request | +| **Speed** | Slower (requires a network call) | Faster (no network call required) | +| **Data Sensitivity** | Secure—data is not exposed to the frontend | The access token includes data, which is accessible to the frontend | +| **Use Case** | Best for storing sensitive session-related data | Best for frequently accessed data like user roles | +| **Persistence** | Updated via `update_session_data_in_database` | Updated via `merge_into_access_token_payload` | + +
+ +
+
@@ -465,12 +874,12 @@ async def like_comment(request: HttpRequest): To make an API endpoint accessible even if there is no session update the middleware call to mark the session as not required. - - - - + + + + -```tsx +```tsx {8} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; @@ -478,7 +887,6 @@ import { SessionRequest } from "supertokens-node/framework/express"; let app = express(); app.post("/like-comment", - // highlight-next-line verifySession({sessionRequired: false}), (req: SessionRequest, res) => { if (req.session !== undefined) { @@ -490,10 +898,10 @@ app.post("/like-comment", ); ``` - - + + -```tsx +```tsx {13} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import { SessionRequest } from "supertokens-node/framework/hapi"; @@ -506,7 +914,6 @@ server.route({ options: { pre: [ { - // highlight-next-line method: verifySession({ sessionRequired: false }) }, ], @@ -520,10 +927,10 @@ server.route({ } }) ``` - - + + -```tsx +```tsx {8} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import { SessionRequest } from "supertokens-node/framework/fastify"; @@ -531,7 +938,6 @@ import { SessionRequest } from "supertokens-node/framework/fastify"; let fastify = Fastify(); fastify.post("/like-comment", { - // highlight-next-line preHandler: verifySession({ sessionRequired: false }), }, (req: SessionRequest, res) => { if (req.session !== undefined) { @@ -542,10 +948,10 @@ fastify.post("/like-comment", { }); ``` - - + + -```tsx +```tsx {12} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEventV2 } from "supertokens-node/framework/awsLambda"; @@ -557,14 +963,13 @@ async function likeComment(awsEvent: SessionEventV2) { } }; -// highlight-next-line exports.handler = verifySession(likeComment, { sessionRequired: false }); ``` - - + + -```tsx +```tsx {8} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from "supertokens-node/framework/koa"; @@ -572,7 +977,6 @@ import { SessionContext } from "supertokens-node/framework/koa"; let router = new KoaRouter(); router.post("/like-comment", - // highlight-next-line verifySession({ sessionRequired: false }), (ctx: SessionContext, next) => { if (ctx.session !== undefined) { @@ -584,10 +988,10 @@ router.post("/like-comment", ); ``` - - + + -```tsx +```tsx {10} import { inject, intercept } from "@loopback/core"; import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; @@ -597,7 +1001,6 @@ import { SessionContext } from "supertokens-node/framework/loopback"; class LikeComment { constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { } @post("/like-comment") - // highlight-next-line @intercept(verifySession({ sessionRequired: false })) @response(200) handler() { @@ -611,21 +1014,20 @@ class LikeComment { } ``` - - + + + - - + -```tsx +```tsx {5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; -// highlight-start export default async function likeComment(req: any, res: any) { await superTokensNextWrapper( async (next) => { @@ -643,7 +1045,6 @@ export default async function likeComment(req: any, res: any) { } else { // session doesn't exist } - // highlight-end //.... } ``` @@ -655,7 +1056,6 @@ export default async function likeComment(req: any, res: any) { import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -681,13 +1081,12 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {10,11,12,13,14,15,16} import { Controller, Post, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; -// @ts-ignore import { OptionalAuthGuard } from './auth/optionalAuth.guard'; @Controller() @@ -695,7 +1094,6 @@ export class ExampleController { @Post('example') @UseGuards(new OptionalAuthGuard()) // For more information about this guard please read our NestJS guide. async postExample(@Session() session: SessionContainer): Promise { - //highlight-start if (session !== undefined) { let userId = session.getUserId(); // session exists @@ -703,20 +1101,19 @@ export class ExampleController { // session doesn't exist } - //highlight-end //.... return true; } } ``` - - - - - - + + + + + + -```go +```go {15} import ( "fmt" "net/http" @@ -731,7 +1128,6 @@ func main() { // Wrap the API handler in session.VerifySession sessionRequired := false session.VerifySession(&sessmodels.VerifySessionOptions{ - //highlight-next-line SessionRequired: &sessionRequired, }, likeCommentAPI).ServeHTTP(rw, r) }) @@ -747,10 +1143,10 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + -```go +```go {16} import ( "fmt" "net/http" @@ -766,7 +1162,6 @@ func main() { // Wrap the API handler in session.VerifySession sessionRequired := false router.POST("/likecomment", verifySession(&sessmodels.VerifySessionOptions{ - //highlight-next-line SessionRequired: &sessionRequired, }), likeCommentAPI) } @@ -794,10 +1189,10 @@ func likeCommentAPI(c *gin.Context) { } ``` - - + + -```go +```go {16} import ( "fmt" "net/http" @@ -813,7 +1208,6 @@ func main() { // Wrap the API handler in session.VerifySession sessionRequired := false r.Post("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{ - //highlight-next-line SessionRequired: &sessionRequired, }, likeCommentAPI)) } @@ -828,10 +1222,10 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + -```go +```go {16} import ( "fmt" "net/http" @@ -847,7 +1241,6 @@ func main() { // Wrap the API handler in session.VerifySession sessionRequired := false router.HandleFunc("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{ - //highlight-next-line SessionRequired: &sessionRequired, }, likeCommentAPI)).Methods(http.MethodPost) } @@ -862,15 +1255,15 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + - - + + -```python +```python {9,10,11,12,13,14,15,16,17,18,19} from typing import Optional from fastapi import Depends @@ -879,8 +1272,7 @@ from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.fastapi import verify_session -# highlight-start -@app.post("/like_comment") # type: ignore +@app.post("/like_comment") async def like_comment( session: Optional[SessionContainer] = Depends( verify_session(session_required=False) @@ -891,13 +1283,12 @@ async def like_comment( print(user_id) # TODO.. else: pass # user is not logged in - # highlight-end ``` - - + + -```python +```python {9,10,11,12,13,14,15,16,17,18} from typing import Union from flask import g @@ -906,24 +1297,22 @@ from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.flask import verify_session -# highlight-start -@app.route('/update-jwt', methods=['POST']) # type: ignore +@app.route('/update-jwt', methods=['POST']) @verify_session(session_required=False) def like_comment(): - session: Union[SessionContainer, None] = g.supertokens # type: ignore + session: Union[SessionContainer, None] = g.supertokens if session is not None: user_id = session.get_user_id() print(user_id) # TODO.. else: pass # user is not logged in - # highlight-end ``` - - + + -```python +```python {9,10,11,12,13,14,15,16,17} from typing import Optional, cast from django.http import HttpRequest @@ -932,24 +1321,22 @@ from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.django.asyncio import verify_session -# highlight-start @verify_session(session_required=False) async def like_comment(request: HttpRequest): - session: Optional[SessionContainer] = cast(Optional[SessionContainer], request.supertokens) # type: ignore + session: Optional[SessionContainer] = cast(Optional[SessionContainer], request.supertokens) if session is not None: user_id = session.get_user_id() print(user_id) # TODO.. else: pass # user is not logged in - # highlight-end ``` - - + + - - + + ### Verify the claims of a session @@ -960,10 +1347,10 @@ The `global validators` represent other validators that apply to all API routes This may include things like a validator that ensures that the user's email is verified. - - - - + + + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/express"; @@ -987,8 +1374,8 @@ app.post( } ); ``` - - + + ```tsx import Hapi from "@hapi/hapi"; @@ -1019,8 +1406,8 @@ server.route({ } }) ``` - - + + ```tsx import Fastify from "fastify"; @@ -1043,8 +1430,8 @@ fastify.post("/update-blog", { }); ``` - - + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; @@ -1064,8 +1451,8 @@ exports.handler = verifySession(updateBlog, { }); ``` - - + + ```tsx import KoaRouter from "koa-router"; @@ -1086,8 +1473,8 @@ router.post("/update-blog", verifySession({ }); ``` - - + + ```tsx import { inject, intercept } from "@loopback/core"; @@ -1113,22 +1500,21 @@ class SetRole { } ``` - - + + + - - + -```tsx +```tsx {6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; import UserRoles from "supertokens-node/recipe/userroles"; -// highlight-start export default async function setRole(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { @@ -1150,12 +1536,11 @@ export default async function setRole(req: SessionRequest, res: any) { -```tsx +```tsx {18,19,20} import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import UserRoles from "supertokens-node/recipe/userroles"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -1169,24 +1554,21 @@ export function POST(request: NextRequest) { return NextResponse.json({}) }, { - // highlight-start overrideGlobalClaimValidators: async function (globalClaimValidators) { return [...globalClaimValidators, UserRoles.UserRoleClaim.validators.includes("admin")] } - // highlight-end }); } ``` - - + + ```tsx import { Controller, Post, UseGuards, Request, Response, Session } from "@nestjs/common"; import { SessionContainer, SessionClaimValidator } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; import UserRoles from "supertokens-node/recipe/userroles"; @@ -1206,15 +1588,15 @@ export class ExampleController { } } ``` - + - - - - - + + + + + -```go +```go {14,15,16,17} import ( "net/http" @@ -1228,12 +1610,10 @@ import ( func main() { _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, userrolesclaims.UserRoleClaimValidators.Includes("admin", nil, nil)) return globalClaimValidators, nil }, - // highlight-end }, exampleAPI).ServeHTTP(rw, r) }) } @@ -1243,10 +1623,10 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + -```go +```go {17,18,19,20} import ( "net/http" @@ -1263,12 +1643,10 @@ func main() { // Wrap the API handler in session.VerifySession router.POST("/likecomment", verifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, userrolesclaims.UserRoleClaimValidators.Includes("admin", nil, nil)) return globalClaimValidators, nil }, - // highlight-end }), exampleAPI) } @@ -1290,10 +1668,10 @@ func exampleAPI(c *gin.Context) { } ``` - - + + -```go +```go {17,18,19,20} import ( "net/http" @@ -1310,12 +1688,10 @@ func main() { // Wrap the API handler in session.VerifySession r.Post("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, userrolesclaims.UserRoleClaimValidators.Includes("admin", nil, nil)) return globalClaimValidators, nil }, - // highlight-end }, exampleAPI)) } @@ -1325,10 +1701,10 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { ``` - - + + -```go +```go {17,18,19,20} import ( "net/http" @@ -1345,12 +1721,10 @@ func main() { // Wrap the API handler in session.VerifySession router.HandleFunc("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, userrolesclaims.UserRoleClaimValidators.Includes("admin", nil, nil)) return globalClaimValidators, nil }, - // highlight-end }, exampleAPI)).Methods(http.MethodPost) } @@ -1359,15 +1733,15 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + - - + + -```python +```python {11,12,13} from fastapi import Depends from supertokens_python.recipe.session import SessionContainer @@ -1375,45 +1749,41 @@ from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.userroles import UserRoleClaim -@app.post('/like_comment') # type: ignore +@app.post('/like_comment') async def like_comment(session: SessionContainer = Depends( verify_session( - # highlight-start # We add the UserRoleClaim's includes validator override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \ [UserRoleClaim.validators.includes("admin")] - # highlight-end ) )): # All validator checks have passed and the user has a verified email address pass ``` - - + + -```python +```python {7,8,9} from supertokens_python.recipe.session.framework.flask import verify_session from supertokens_python.recipe.userroles import UserRoleClaim -@app.route('/update-jwt', methods=['POST']) # type: ignore +@app.route('/update-jwt', methods=['POST']) @verify_session( - # highlight-start # We add the UserRoleClaim's includes validator override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \ [UserRoleClaim.validators.includes("admin")] - # highlight-end ) def like_comment(): # All validator checks have passed and the user has a verified email address pass ``` - - + + -```python +```python {8,9,10} from django.http import HttpRequest from supertokens_python.recipe.session.framework.django.asyncio import verify_session @@ -1421,26 +1791,24 @@ from supertokens_python.recipe.userroles import UserRoleClaim @verify_session( - # highlight-start # We add the UserRoleClaim's includes validator override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \ [UserRoleClaim.validators.includes("admin")] - # highlight-end ) async def like_comment(request: HttpRequest): # All validator checks have passed and the user has a verified email address pass ``` - - + + - - + + -:::tip Feature -You can also [build your own custom claim validators](/docs/additional-verification/session-verification/claim-validation#using-session-claims) based on your app's requirements. +:::tip[Feature] +You can also [build your own custom claim validators](/additional-verification/session-verification/claim-validation#using-session-claims) based on your app's requirements. ::: --- @@ -1453,24 +1821,22 @@ If these errors remain unhandled, the SuperTokens error handler catches these er You should use this function if your framework does not support middlewares or if you want additional control over error management. - - - - + + + + -```tsx +```tsx {6,7,8,9,10} import express from "express"; import Session from "supertokens-node/recipe/session"; let app = express(); -// highlight-start app.post("/like-comment", async (req, res, next) => { try { let session = await Session.getSession(req, res); let userId = session.getUserId(); - // highlight-end //.... } catch (err) { next(err); @@ -1478,10 +1844,10 @@ app.post("/like-comment", async (req, res, next) => { }); ``` - - + + -```tsx +```tsx {9,10,11,12} import Hapi from "@hapi/hapi"; import Session from "supertokens-node/recipe/session"; @@ -1490,85 +1856,75 @@ let server = Hapi.server({ port: 8000 }); server.route({ path: "/like-comment", method: "post", - //highlight-start handler: async (req, res) => { let session = await Session.getSession(req, res); let userId = session.getUserId(); - //highlight-end //... } }) ``` - - + + -```tsx +```tsx {6,7,8,9} import Fastify from "fastify"; import Session from "supertokens-node/recipe/session"; let fastify = Fastify(); -//highlight-start fastify.post("/like-comment", async (req, res) => { let session = await Session.getSession(req, res); let userId = session.getUserId(); - //highlight-end //.... }); ``` - - + + -```tsx +```tsx {5,6,7,8,12} import Session from "supertokens-node/recipe/session"; import { middleware } from "supertokens-node/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; -//highlight-start async function likeComment(awsEvent: SessionEvent) { let session = await Session.getSession(awsEvent, awsEvent); let userId = session.getUserId(); - //highlight-end //.... }; -//highlight-next-line exports.handler = middleware(likeComment); ``` - - + + -```tsx +```tsx {6,7,8,9} import KoaRouter from "koa-router"; import Session from "supertokens-node/recipe/session"; let router = new KoaRouter(); -//highlight-start router.post("/like-comment", async (ctx, next) => { let session = await Session.getSession(ctx, ctx); let userId = session.getUserId(); - //highlight-end //.... }); ``` - - + + -```tsx +```tsx {6,7,8,9,10,11,12} import { inject } from "@loopback/core"; import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest"; import Session from "supertokens-node/recipe/session"; class LikeComment { - //highlight-start constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { } @post("/like-comment") @response(200) @@ -1576,27 +1932,25 @@ class LikeComment { let session = await Session.getSession(this.ctx, this.ctx); let userId = session.getUserId(); - //highlight-end //.... } } ``` - - + + + - - + -```tsx +```tsx {5,6,7,8,9,10,11,12,13,14} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import Session from "supertokens-node/recipe/session"; import { SessionRequest } from "supertokens-node/framework/express"; -// highlight-start export default async function likeComment(req: SessionRequest, res: any) { let session = await superTokensNextWrapper( async (next) => { @@ -1607,7 +1961,6 @@ export default async function likeComment(req: SessionRequest, res: any) { ) let userId = session.getUserId(); - // highlight-end //.... } ``` @@ -1621,7 +1974,6 @@ import SuperTokens from "supertokens-node"; import { withPreParsedRequestResponse } from "supertokens-node/nextjs"; import { CollectingResponse, PreParsedRequest } from "supertokens-node/framework/custom"; import Session from "supertokens-node/recipe/session"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -1637,10 +1989,10 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {9,10,11,12} import { Controller, Post, UseGuards, Req, Res } from "@nestjs/common"; import type { Request, Response } from "express"; import Session from "supertokens-node/recipe/session"; @@ -1649,21 +2001,19 @@ import Session from "supertokens-node/recipe/session"; export class ExampleController { @Post('example') async postExample(@Req() req: Request, @Res({passthrough: true}) res: Response): Promise { - //highlight-start // This should be done inside a parameter decorator, for more information please read our NestJS guide. const session = await Session.getSession(req, res); const userId = session.getUserId(); - //highlight-end //.... return true; } } ``` - - - - + + + + ```go import ( @@ -1692,21 +2042,20 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + - - + + -```python +```python {8} from fastapi.requests import Request from supertokens_python.recipe.session.asyncio import get_session -@app.post('/like-comment') # type: ignore +@app.post('/like-comment') async def like_comment(request: Request): - # highlight-next-line session = await get_session(request) if session is None: @@ -1718,18 +2067,17 @@ async def like_comment(request: Request): # TODO ``` - - + + -```python +```python {8} from flask.wrappers import Request from supertokens_python.recipe.session.syncio import get_session -@app.route('/like-comment', methods=['POST']) # type: ignore +@app.route('/like-comment', methods=['POST']) def like_comment(request: Request): - # highlight-next-line session = get_session(request) if session is None: @@ -1741,17 +2089,16 @@ def like_comment(request: Request): # TODO ``` - - + + -```python +```python {7} from django.http import HttpRequest from supertokens_python.recipe.session.asyncio import get_session async def like_comment(request: HttpRequest): - # highlight-next-line session = await get_session(request) if session is None: raise Exception("Should never come here") @@ -1762,28 +2109,473 @@ async def like_comment(request: HttpRequest): ``` - - + + - - + + + + + + +```tsx + +interface Session { + /** + * Destroys this session in the database and on the frontend. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the session is successfully revoked. + */ + revokeSession(userContext?: Record): Promise; + + /** + * Retrieves the session data stored in the database associated with the session. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves with the session data. + */ + getSessionDataFromDatabase(userContext?: Record): Promise; + + /** + * Sets a new JSON object to the session data stored in the database. + * @param newSessionData The new session data to store. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the session data is updated. + */ + updateSessionDataInDatabase(newSessionData: any, userContext?: Record): Promise; + + /** + * Returns the user ID of the logged-in user. + * @param userContext Optional context object for additional data. + * @returns The user ID as a string. + */ + getUserId(userContext?: Record): string; + + /** + * Returns the `RecipeUserId` object for the session. It represents the user ID of the specific login method for this user. + * @param userContext Optional context object for additional data. + * @returns The `RecipeUserId`. + */ + getRecipeUserId(userContext?: Record): RecipeUserId; + + /** + * Returns the tenant ID of the session. The default value is "public" if multi-tenancy is not used. + * @param userContext Optional context object for additional data. + * @returns The tenant ID as a string. + */ + getTenantId(userContext?: Record): string; + + /** + * Returns the access token's payload for this session. This includes user-defined claims, standard claims, and SuperTokens specific ones. + * @param userContext Optional context object for additional data. + * @returns The access token payload. + */ + getAccessTokenPayload(userContext?: Record): any; + + /** + * Returns the `sessionHandle` for this session, a unique string constant for each session. + * @param userContext Optional context object for additional data. + * @returns The session handle as a string. + */ + getHandle(userContext?: Record): string; + + /** + * Returns an object containing the raw string representation of all tokens associated with the session, along with an update status. + * @returns An object with accessToken, refreshToken, antiCsrfToken, frontToken, and accessAndFrontTokenUpdated. + */ + getAllSessionTokensDangerously(): { + accessToken: string; + refreshToken: string | undefined; + antiCsrfToken: string | undefined; + frontToken: string; + accessAndFrontTokenUpdated: boolean; + }; + + /** + * Returns the raw string access token for this session. + * @param userContext Optional context object for additional data. + * @returns The access token as a string. + */ + getAccessToken(userContext?: Record): string; + + /** + * Adds key/value pairs into a JSON object in the access token. Setting a key to null removes it from the payload. + * @param accessTokenPayloadUpdate The updates to apply to the access token payload. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the payload is updated. + */ + mergeIntoAccessTokenPayload(accessTokenPayloadUpdate: JSONObject, userContext?: Record): Promise; + + /** + * Returns the time in milliseconds of when this session was created. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves with the creation time in milliseconds. + */ + getTimeCreated(userContext?: Record): Promise; + + /** + * Returns the time in milliseconds of when this session will expire if not refreshed. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves with the expiry time in milliseconds. + */ + getExpiry(userContext?: Record): Promise; + + /** + * Asserts the validity of custom session claims using provided validators. + * @param claimValidators An array of session claim validators. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the claim assertions are complete. + */ + assertClaims(claimValidators: SessionClaimValidator[], userContext?: Record): Promise; + + /** + * Fetches and sets a custom claim in the session. + * @param claim The session claim to fetch and set. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves with the fetched claim. + */ + fetchAndSetClaim(claim: SessionClaim, userContext?: Record): Promise; + + /** + * Sets the value of a session claim. + * @param claim The session claim to update. + * @param value The new value for the claim. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the claim value is set. + */ + setClaimValue(claim: SessionClaim, value: T, userContext?: Record): Promise; + + /** + * Gets the value of a session claim. + * @param claim The session claim to retrieve the value for. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves with the claim value, or undefined if not found. + */ + getClaimValue(claim: SessionClaim, userContext?: Record): Promise; + + /** + * Removes a session claim. + * @param claim The session claim to remove. + * @param userContext Optional context object for additional data. + * @returns A promise that resolves when the claim is removed. + */ + removeClaim(claim: SessionClaim, userContext?: Record): Promise; + + /** + * Attaches the session to a request-response cycle. + * @param reqResInfo Information about the request-response. + * @param userContext Optional context object for additional data. + * @returns A promise or void once the session is attached. + */ + attachToRequestResponse(reqResInfo: ReqResInfo, userContext?: Record): Promise | void; +} +``` + + +
+ +### `getSessionDataFromDatabase` vs `getAccessTokenPayload` + +
+ + +| | `getSessionDataFromDatabase` | `getAccessTokenPayload` | +|--------------------------------------|-----------------------------|-------------------------| +| **Source of Data** | Queries SuperTokens Core database | Reads directly from the access token in the request | +| **Speed** | Slower (requires a network call) | Faster (no network call required) | +| **Data Sensitivity** | Secure—data is not exposed to the frontend | The access token includes data, which is accessible to the frontend | +| **Use Case** | Best for storing sensitive session-related data | Best for frequently accessed data like user roles | +| **Persistence** | Updated via `updateSessionDataInDatabase` | Updated via `mergeIntoAccessTokenPayload` | + +
+ + +```go + + +type TypeSessionContainer struct { + // Destroys this session in the database and on the frontend. + RevokeSession func() error + + // Retrieves the session data stored in the database associated with the session. + GetSessionDataInDatabase func() (map[string]interface{}, error) + + // Sets a new JSON object to the session data stored in the database. + // `newSessionData` is the new session data to store. + UpdateSessionDataInDatabase func(newSessionData map[string]interface{}) error + + // Returns the user ID of the logged-in user. + GetUserID func() string + + // Returns the tenant ID of the session. + // Default value is "public" if multi-tenancy is not used. + GetTenantId func() string + + // Returns the access token's payload for this session. + // Includes user-defined claims, standard claims, and SuperTokens specific ones. + GetAccessTokenPayload func() map[string]interface{} + + // Returns the `sessionHandle` for this session, + // a unique string constant for each session. + GetHandle func() string + + // Returns an object containing the raw string representation + // of all tokens associated with the session, along with an update status. + GetAllSessionTokensDangerously func() SessionTokens + + // Returns the raw string access token for this session. + GetAccessToken func() string + + // Returns the time in milliseconds of when this session was created. + GetTimeCreated func() (uint64, error) + + // Returns the time in milliseconds of when this session will expire if not refreshed. + GetExpiry func() (uint64, error) + + // Context-aware methods that provide the same functionality as their counterparts above while considering user context + + // Destroys this session in the database and on the frontend with user context. + RevokeSessionWithContext func(userContext supertokens.UserContext) error + + // Retrieves the session data stored in the database associated with the session with user context. + GetSessionDataInDatabaseWithContext func(userContext supertokens.UserContext) (map[string]interface{}, error) + + // Sets a new JSON object to the session data stored in the database with user context. + UpdateSessionDataInDatabaseWithContext func(newSessionData map[string]interface{}, userContext supertokens.UserContext) error + + // Returns the user ID of the logged-in user with user context. + GetUserIDWithContext func(userContext supertokens.UserContext) string + + // Returns the tenant ID of the session with user context. + GetTenantIdWithContext func(userContext supertokens.UserContext) string + + // Returns the access token's payload for this session with user context. + GetAccessTokenPayloadWithContext func(userContext supertokens.UserContext) map[string]interface{} -## The `Session` object + // Returns the `sessionHandle` for this session with user context. + GetHandleWithContext func(userContext supertokens.UserContext) string - + // Returns the raw string access token for this session with user context. + GetAccessTokenWithContext func(userContext supertokens.UserContext) string + // Returns the time in milliseconds of when this session was created with user context. + GetTimeCreatedWithContext func(userContext supertokens.UserContext) (uint64, error) + + // Returns the time in milliseconds of when this session will expire if not refreshed with user context. + GetExpiryWithContext func(userContext supertokens.UserContext) (uint64, error) + + // Adds key/value pairs into a JSON object in the access token with user context. + // Setting a key to nil removes it from the payload. + MergeIntoAccessTokenPayloadWithContext func(accessTokenPayloadUpdate map[string]interface{}, userContext supertokens.UserContext) error + + // Asserts the validity of custom session claims using provided validators with user context. + AssertClaimsWithContext func(claimValidators []claims.SessionClaimValidator, userContext supertokens.UserContext) error + + // Fetches and sets a custom claim in the session with user context. + FetchAndSetClaimWithContext func(claim *claims.TypeSessionClaim, userContext supertokens.UserContext) error + + // Sets the value of a session claim with user context. + SetClaimValueWithContext func(claim *claims.TypeSessionClaim, value interface{}, userContext supertokens.UserContext) error + + // Gets the value of a session claim with user context. + // Returns the value or nil if not found. + GetClaimValueWithContext func(claim *claims.TypeSessionClaim, userContext supertokens.UserContext) interface{} + + // Removes a session claim with user context. + RemoveClaimWithContext func(claim *claims.TypeSessionClaim, userContext supertokens.UserContext) error + + // Attaches the session to a request-response cycle with user context. + AttachToRequestResponseWithContext func(info RequestResponseInfo, userContext supertokens.UserContext) error + + // Adds key/value pairs into a JSON object in the access token. + // Setting a key to nil removes it from the payload. + MergeIntoAccessTokenPayload func(accessTokenPayloadUpdate map[string]interface{}) error + + // Asserts the validity of custom session claims using provided validators. + AssertClaims func(claimValidators []claims.SessionClaimValidator) error + + // Fetches and sets a custom claim in the session. + FetchAndSetClaim func(claim *claims.TypeSessionClaim) error + + // Sets the value of a session claim. + SetClaimValue func(claim *claims.TypeSessionClaim, value interface{}) error + + // Gets the value of a session claim. + // Returns the value or nil if not found. + GetClaimValue func(claim *claims.TypeSessionClaim) interface{} + + // Removes a session claim. + RemoveClaim func(claim *claims.TypeSessionClaim) error + + // Attaches the session to a request-response cycle. + AttachToRequestResponse func(info RequestResponseInfo) error +} +``` + +
+ +### `GetSessionDataFromDatabase` vs `GetAccessTokenPayload` + +
+ +| | `GetSessionDataFromDatabase` | `GetAccessTokenPayload` | +|--------------------------------------|-----------------------------|-------------------------| +| **Source of Data** | Queries SuperTokens Core database | Reads directly from the access token in the request | +| **Speed** | Slower (requires a network call) | Faster (no network call required) | +| **Data Sensitivity** | Secure—data is not exposed to the frontend | The access token includes data, which is accessible to the frontend | +| **Use Case** | Best for storing sensitive session-related data | Best for frequently accessed data like user roles | +| **Persistence** | Updated via `UpdateSessionDataInDatabase` | Updated via `MergeIntoAccessTokenPayload` | + +
+ + + +```python +# exclude-from-type-checking + +class Session: + # Destroys this session in the database and on the frontend. + # Optional user_context can be used for additional contextual data. + async def revoke_session(self, user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Retrieves the session data stored in the database associated with the session. + # Optional user_context can be used for additional contextual data. + async def get_session_data_from_database(self, user_context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: + pass + + # Sets a new JSON object to the session data stored in the database. + # `new_session_data` is the new session data to store. + # Optional user_context can be used for additional contextual data. + async def update_session_data_in_database(self, new_session_data: Dict[str, Any], user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Returns the user ID of the logged-in user. + # Optional user_context can be used for additional contextual data. + def get_user_id(self, user_context: Optional[Dict[str, Any]] = None) -> str: + pass + + # Returns the `RecipeUserId` object for the session. + # This represents the user ID of the specific login method for this user. + # Optional user_context can be used for additional contextual data. + def get_recipe_user_id(self, user_context: Optional[Dict[str, Any]] = None) -> RecipeUserId: + pass + + # Returns the tenant ID of the session. + # Default value is "public" if multi-tenancy is not used. + # Optional user_context can be used for additional contextual data. + def get_tenant_id(self, user_context: Optional[Dict[str, Any]] = None) -> str: + pass + + # Returns the access token's payload for this session. + # Includes user-defined claims, standard claims, and SuperTokens specific ones. + # Optional user_context can be used for additional contextual data. + def get_access_token_payload(self, user_context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: + pass + + # Returns the `sessionHandle` for this session, + # a unique string constant for each session. + # Optional user_context can be used for additional contextual data. + def get_handle(self, user_context: Optional[Dict[str, Any]] = None) -> str: + pass + + # Returns an object containing the raw string representation + # of all tokens associated with the session, along with an update status. + def get_all_session_tokens_dangerously(self) -> GetSessionTokensDangerouslyDict: + pass + + # Returns the raw string access token for this session. + # Optional user_context can be used for additional contextual data. + def get_access_token(self, user_context: Optional[Dict[str, Any]] = None) -> str: + pass + + # Adds key/value pairs into a JSON object in the access token. + # Setting a key to None removes it from the payload. + # `access_token_payload_update` contains the updates to apply. + # Optional user_context can be used for additional contextual data. + async def merge_into_access_token_payload(self, access_token_payload_update: JSONObject, user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Returns the time in milliseconds of when this session was created. + # Optional user_context can be used for additional contextual data. + async def get_time_created(self, user_context: Optional[Dict[str, Any]] = None) -> int: + pass + + # Returns the time in milliseconds of when this session will expire if not refreshed. + # Optional user_context can be used for additional contextual data. + async def get_expiry(self, user_context: Optional[Dict[str, Any]] = None) -> int: + pass + + # Asserts the validity of custom session claims using provided validators. + # `claim_validators` is an array of session claim validators. + # Optional user_context can be used for additional contextual data. + async def assert_claims(self, claim_validators: List[SessionClaimValidator], user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Fetches and sets a custom claim in the session. + # `claim` is the session claim to fetch and set. + # Optional user_context can be used for additional contextual data. + async def fetch_and_set_claim(self, claim: SessionClaim[Any], user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Sets the value of a session claim. + # `claim` is the session claim to update. + # `value` is the new value for the claim. + # Optional user_context can be used for additional contextual data. + async def set_claim_value(self, claim: SessionClaim[_T], value: _T, user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Gets the value of a session claim. + # `claim` is the session claim to retrieve the value for. + # Optional user_context can be used for additional contextual data. + # Returns a promise that resolves with the claim value, or None if not found. + async def get_claim_value(self, claim: SessionClaim[_T], user_context: Optional[Dict[str, Any]] = None) -> Union[_T, None]: + pass + + # Removes a session claim. + # `claim` is the session claim to remove. + # Optional user_context can be used for additional contextual data. + async def remove_claim(self, claim: SessionClaim[Any], user_context: Optional[Dict[str, Any]] = None) -> None: + pass + + # Attaches the session to a request-response cycle. + # `req_res_info` contains information about the request-response. + # Optional user_context can be used for additional contextual data. + async def attach_to_request_response(self, request: BaseRequest, transfer_method: TokenTransferMethod, user_context: Optional[Dict[str, Any]] = None) -> None: + pass +``` + + +
+ +### `get_session_data_from_database` vs `get_access_token_payload` + +
+ + +| | `get_session_data_from_database` | `get_access_token_payload` | +|--------------------------------------|-----------------------------|-------------------------| +| **Source of Data** | Queries SuperTokens Core database | Reads directly from the access token in the request | +| **Speed** | Slower (requires a network call) | Faster (no network call required) | +| **Data Sensitivity** | Secure—data is not exposed to the frontend | The access token includes data, which is accessible to the frontend | +| **Use Case** | Best for storing sensitive session-related data | Best for frequently accessed data like user roles | +| **Persistence** | Updated via `update_session_data_in_database` | Updated via `merge_into_access_token_payload` | + +
+ +
+
### Optional session verification To make an API endpoint accessible even if there is no session update the middleware call to mark the session as not required. - - - - + + + + ```tsx import express from "express"; @@ -1807,8 +2599,8 @@ app.post("/like-comment", async (req, res, next) => { }); ``` - - + + ```tsx import Hapi from "@hapi/hapi"; @@ -1833,8 +2625,8 @@ server.route({ } }) ``` - - + + ```tsx import Fastify from "fastify"; @@ -1854,10 +2646,10 @@ fastify.post("/like-comment", async (req, res) => { }); ``` - - + + -```tsx +```tsx {17} import Session from "supertokens-node/recipe/session"; import { middleware } from "supertokens-node/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; @@ -1874,12 +2666,11 @@ async function likeComment(awsEvent: SessionEvent) { //.... }; -//highlight-next-line exports.handler = middleware(likeComment); ``` - - + + ```tsx import KoaRouter from "koa-router"; @@ -1900,8 +2691,8 @@ router.post("/like-comment", async (ctx, next) => { }); ``` - - + + ```tsx import { inject } from "@loopback/core"; @@ -1927,12 +2718,12 @@ class LikeComment { } ``` - - + + + - - + @@ -1968,7 +2759,6 @@ import SuperTokens from "supertokens-node"; import { withPreParsedRequestResponse } from "supertokens-node/nextjs"; import { CollectingResponse, PreParsedRequest } from "supertokens-node/framework/custom"; import Session from "supertokens-node/recipe/session"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -1988,10 +2778,10 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {9,10,11,12,13,14,15,16} import { Controller, Post, UseGuards, Req, Res } from "@nestjs/common"; import type { Request, Response } from "express"; import Session from "supertokens-node/recipe/session"; @@ -2000,7 +2790,6 @@ import Session from "supertokens-node/recipe/session"; export class ExampleController { @Post('example') async postExample(@Req() req: Request, @Res({ passthrough: true }) res: Response): Promise { - //highlight-start // This should be done inside a parameter decorator, for more information please read our NestJS guide. const session = await Session.getSession(req, res, { sessionRequired: false }) @@ -2009,16 +2798,15 @@ export class ExampleController { } else { // user is not logged in... } - //highlight-end //.... return true; } } ``` - - - - + + + + ```go import ( @@ -2053,20 +2841,19 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + -```python +```python {8} from fastapi import Request from supertokens_python.recipe.session.asyncio import get_session -@app.post("/like-comment") # type: ignore +@app.post("/like-comment") async def like_comment(request: Request): - # highlight-next-line session = await get_session(request, session_required=False) if session is not None: @@ -2077,18 +2864,17 @@ async def like_comment(request: Request): ``` - - + + -```python +```python {8} from flask.wrappers import Request from supertokens_python.recipe.session.syncio import get_session -@app.route("/like-comment", methods=["POST"]) # type: ignore +@app.route("/like-comment", methods=["POST"]) def like_comment(request: Request): - # highlight-next-line session = get_session(request, session_required=False) if session is not None: @@ -2099,17 +2885,16 @@ def like_comment(request: Request): ``` - - + + -```python +```python {7} from django.http import HttpRequest from supertokens_python.recipe.session.asyncio import get_session async def like_comment(request: HttpRequest): - # highlight-next-line session = await get_session(request, session_required=False) if session is not None: @@ -2120,11 +2905,11 @@ async def like_comment(request: HttpRequest): ``` - - + + - - + + ### Verify the claims of a session @@ -2134,19 +2919,18 @@ This can be achieved by including the user role claim validator in the middlewar The `global validators` represent other validators that apply to all API routes by default. This may include things like a validator that ensures that the user's email is verified. - - - - + + + + -```tsx +```tsx {7,8,9,10,11,12,13,14,15,16,17} import express from "express"; import Session from "supertokens-node/recipe/session"; import UserRoles from "supertokens-node/recipe/userroles"; let app = express(); -// highlight-start app.post("/like-comment", async (req, res, next) => { try { let session = await Session.getSession(req, res, { @@ -2158,7 +2942,6 @@ app.post("/like-comment", async (req, res, next) => { }); let userId = session.getUserId(); - // highlight-end //.... } catch (err) { next(err) @@ -2166,10 +2949,10 @@ app.post("/like-comment", async (req, res, next) => { }); ``` - - + + -```tsx +```tsx {10,11,12,13,14,15,16,17,18,19} import Hapi from "@hapi/hapi"; import Session from "supertokens-node/recipe/session"; import UserRoles from "supertokens-node/recipe/userroles"; @@ -2179,7 +2962,6 @@ let server = Hapi.server({ port: 8000 }); server.route({ path: "/like-comment", method: "post", - //highlight-start handler: async (req, res) => { let session = await Session.getSession(req, res, { overrideGlobalClaimValidators: async (globalValidators) => [ @@ -2190,22 +2972,20 @@ server.route({ }); let userId = session.getUserId(); - //highlight-end //... } }) ``` - - + + -```tsx +```tsx {7,8,9,10,11,12,13,14,15,16} import Fastify from "fastify"; import Session from "supertokens-node/recipe/session"; import UserRoles from "supertokens-node/recipe/userroles"; let fastify = Fastify(); -//highlight-start fastify.post("/like-comment", async (req, res) => { let session = await Session.getSession(req, res, { overrideGlobalClaimValidators: async (globalValidators) => [ @@ -2216,21 +2996,19 @@ fastify.post("/like-comment", async (req, res) => { }); let userId = session.getUserId(); - //highlight-end //.... }); ``` - - + + -```tsx +```tsx {6,7,8,9,10,11,12,13,14,15,19} import Session from "supertokens-node/recipe/session"; import { middleware } from "supertokens-node/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; import UserRoles from "supertokens-node/recipe/userroles"; -//highlight-start async function likeComment(awsEvent: SessionEvent) { let session = await Session.getSession(awsEvent, awsEvent, { overrideGlobalClaimValidators: async (globalValidators) => [ @@ -2241,25 +3019,22 @@ async function likeComment(awsEvent: SessionEvent) { }); let userId = session.getUserId(); - //highlight-end //.... }; -//highlight-next-line exports.handler = middleware(likeComment); ``` - - + + -```tsx +```tsx {7,8,9,10,11,12,13,14,15,16} import KoaRouter from "koa-router"; import Session from "supertokens-node/recipe/session"; import UserRoles from "supertokens-node/recipe/userroles"; let router = new KoaRouter(); -//highlight-start router.post("/like-comment", async (ctx, next) => { let session = await Session.getSession(ctx, ctx, { overrideGlobalClaimValidators: async (globalValidators) => [ @@ -2270,22 +3045,20 @@ router.post("/like-comment", async (ctx, next) => { }); let userId = session.getUserId(); - //highlight-end //.... }); ``` - - + + -```tsx +```tsx {7,8,9,10,11,12,13,14,15,16,17,18,19} import { inject } from "@loopback/core"; import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest"; import Session from "supertokens-node/recipe/session"; import UserRoles from "supertokens-node/recipe/userroles"; class LikeComment { - //highlight-start constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { } @post("/like-comment") @response(200) @@ -2299,28 +3072,26 @@ class LikeComment { }); let userId = session.getUserId(); - //highlight-end //.... } } ``` - - + + + - - + -```tsx +```tsx {6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import Session from "supertokens-node/recipe/session"; import { SessionRequest } from "supertokens-node/framework/express"; import UserRoles from "supertokens-node/recipe/userroles"; -// highlight-start export default async function likeComment(req: SessionRequest, res: any) { let session = await superTokensNextWrapper( async (next) => { @@ -2337,7 +3108,6 @@ export default async function likeComment(req: SessionRequest, res: any) { ) let userId = session.getUserId(); - // highlight-end //.... } ``` @@ -2352,7 +3122,6 @@ import { withPreParsedRequestResponse } from "supertokens-node/nextjs"; import { CollectingResponse, PreParsedRequest } from "supertokens-node/framework/custom"; import Session from "supertokens-node/recipe/session"; import UserRoles from "supertokens-node/recipe/userroles"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -2374,10 +3143,10 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {10,11,12,13,14,15,16,17,18,19} import { Controller, Post, UseGuards, Req, Res } from "@nestjs/common"; import type { Request, Response } from "express"; import Session from "supertokens-node/recipe/session"; @@ -2387,7 +3156,6 @@ import UserRoles from "supertokens-node/recipe/userroles"; export class ExampleController { @Post('example') async postExample(@Req() req: Request, @Res({passthrough: true}) res: Response): Promise { - //highlight-start // This should be done inside a parameter decorator, for more information please read our NestJS guide. const session = await Session.getSession(req, res, { overrideGlobalClaimValidators: async (globalValidators) => [ @@ -2398,18 +3166,17 @@ export class ExampleController { }); const userId = session.getUserId(); - //highlight-end //.... return true; } } ``` - - - - + + + + -```go +```go {14,15,16,17} import ( "fmt" "net/http" @@ -2423,12 +3190,10 @@ import ( func likeCommentAPI(w http.ResponseWriter, r *http.Request) { sessionContainer, err := session.GetSession(r, w, &sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, userrolesclaims.UserRoleClaimValidators.Includes("admin", nil, nil)) return globalClaimValidators, nil }, - // highlight-end }) if err != nil { @@ -2446,11 +3211,11 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + - - + + ```python from fastapi.requests import Request @@ -2459,7 +3224,7 @@ from supertokens_python.recipe.session.asyncio import get_session from supertokens_python.recipe.userroles import UserRoleClaim -@app.post('/like-comment') # type: ignore +@app.post('/like-comment') async def like_comment(request: Request): session = await get_session(request, override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \ @@ -2474,8 +3239,8 @@ async def like_comment(request: Request): # TODO ``` - - + + ```python from flask.wrappers import Request @@ -2484,7 +3249,7 @@ from supertokens_python.recipe.session.syncio import get_session from supertokens_python.recipe.userroles import UserRoleClaim -@app.route("/like-comment", methods=["POST"]) # type: ignore +@app.route("/like-comment", methods=["POST"]) def like_comment(request: Request): session = get_session( request, @@ -2503,8 +3268,8 @@ def like_comment(request: Request): ``` - - + + ```python from django.http import HttpRequest @@ -2529,14 +3294,14 @@ async def like_comment(request: HttpRequest): ``` - - + + - - + + -:::tip feature -You can also [build your own custom claim validators](/docs/additional-verification/session-verification/claim-validation#using-session-claims) based on your app's requirements. +:::tip[feature] +You can also [build your own custom claim validators](/additional-verification/session-verification/claim-validation#using-session-claims) based on your app's requirements. ::: ### Build your own middleware @@ -2548,8 +3313,8 @@ It throws an exception that you can handle if the access token expires or is inv Internally, `Verify Session` uses `Get Session` in the following way: - - + + ```tsx import { VerifySessionOptions } from "supertokens-node/recipe/session/types"; @@ -2596,8 +3361,8 @@ function verifySession(options?: VerifySessionOptions) { The `errorHandler` sends a `401` reply to the frontend if the `getSession` function throws an exception indicating that the session does not exist or if the access token has expired. - - + + ```go import ( @@ -2652,8 +3417,8 @@ func VerifySession(options *sessmodels.VerifySessionOptions, otherHandler http.H The `SuperTokens.ErrorHandler` sends a `401` reply to the frontend if the `getSession` function throws an exception indicating that the session does not exist or if the access token has expired. - - + + ```python from functools import wraps @@ -2737,8 +3502,8 @@ def verify_session( If `get_session` throws an error (in case the input access token is invalid or has expired), then the SuperTokens middleware added to your app handles that exception. It sends a `401` to the frontend. - - + + ### Get the session using the `Access Token` @@ -2752,8 +3517,8 @@ This function works similarly to `getSession`, except that it doesn't depend on It's your responsibility to provide this function the access token. You must write the update tokens to the response if the tokens update during this API call. - - + + ```tsx import { VerifySessionOptions } from "supertokens-node/recipe/session/types"; @@ -2803,8 +3568,8 @@ async function verifySession(accessToken: string, antiCsrfToken?: string, option } ``` - - + + ```go import ( @@ -2856,8 +3621,8 @@ func VerifySession(accessToken string, antiCsrfToken *string, options *sessmodel } ``` - - + + ```python from typing import Any, Callable, Dict, List, Optional, TypeVar @@ -2938,8 +3703,8 @@ def verify_session( ``` - - + + --- @@ -2952,11 +3717,10 @@ This method works for cases like: - You are using a non `http` protocol (like `websockets`) and passing in the access token. - You are using an API gateway which does JWT verification based on the JWKs endpoint. -:::caution -The downside to using JWT verification manually is that: +:::warning[The downside to using JWT verification manually is that:] - Pick and configure a JWT verification library for your framework. Many online guides explain how to do this. - You need to manually verify some custom claims in the JWT (like the user's role is `admin`, or that the user's email is verified) based on your authorization rules. -- You don't have access to the [`session` object](/docs/additional-verification/session-verification/protect-api-routes#using-verify-session) using which you can modify the session's access token payload, or revoke the session. These operations can occur in an offline manner, but they reflect in the user's session only after a session refresh. +- You don't have access to the [`session` object](/additional-verification/session-verification/protect-api-routes#using-verify-session) using which you can modify the session's access token payload, or revoke the session. These operations can occur in an offline manner, but they reflect in the user's session only after a session refresh. ::: The manual session verification method should work in this way: @@ -2967,18 +3731,17 @@ The manual session verification method should work in this way: ## Prevent cross-site request forgery (CSRF) attacks in case you are using cookies to store the JWT. - ### With the JSON Web Key Set (JWKS) Endpoint - - + + Some libraries let you provide a JSON Web Key Set (JWKS) endpoint to verify a JWT. The JSON Web Key Set (JWKS) endpoint exposed by SuperTokens is available at the following URL: ```bash -curl --location --request GET '^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json' +curl --location --request GET '/auth/jwt/jwks.json' ``` Below is an example for NodeJS showing how you can use `jsonwebtoken` and `jwks-rsa` together to achieve JWT verification using the `jwks.json` endpoint. @@ -2988,7 +3751,7 @@ import JsonWebToken, { JwtHeader, SigningKeyCallback } from 'jsonwebtoken'; import jwksClient from 'jwks-rsa'; var client = jwksClient({ - jwksUri: '^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json' + jwksUri: '/auth/jwt/jwks.json' }); function getKey(header: JwtHeader, callback: SigningKeyCallback) { @@ -3005,8 +3768,8 @@ JsonWebToken.verify(jwt, getKey, {}, function (err, decoded) { }); ``` - - + + Refer to this [GitHub gist](https://gist.github.com/rishabhpoddar/ea31502923ec9a53136371f2b6317ffa) for a code reference of how use `PyJWK` to do session verification. The gist contains two files: - `jwt_verification.py` (which you can copy/paste into your application). You need to modify the `JWKS_URI` in this file to point to your SuperTokens core instance (replacing the `try.supertokens.com` part of the URL). This file is for `sync` python apps and can be modified to work with `async` apps as well. @@ -3014,8 +3777,8 @@ Refer to this [GitHub gist](https://gist.github.com/rishabhpoddar/ea31502923ec9a - This function takes care of caching public keys in memory and auto re-fetching if the public keys have changed (which happens automatically every 24 hours with SuperTokens). This does not cause any user logouts and is a security feature. - `views.py`: This is an example `GET` API which extracts the JWT token from the authorization header in the request and calls the `verify_jwt` function from the other file. If you are using cookie based auth instead of header based auth, you should read the JWT from the `sAccessToken` cookie in the request. - - + + Refer to this [GitHub gist](https://gist.github.com/rishabhpoddar/8c26ed237add1a5b86481e72032abf8d) for a code reference of how use the Golang `jwt` lib to do session verification. The gist contains two files: - `verifyToken.go` (which you can copy/paste into your application). You need to modify the `coreUrl` in this file to point to your SuperTokens core instance (replacing the `try.supertokens.com` part of the URL). @@ -3023,8 +3786,8 @@ Refer to this [GitHub gist](https://gist.github.com/rishabhpoddar/8c26ed237add1a - This function takes care of caching public keys in memory and auto re-fetching if the public keys have changed (which happens automatically every 24 hours with SuperTokens). This does not cause any user logouts and is a security feature. - `main.go`: This is an example of how to verify a JWT using the golang JWT verification lib along with the helper function to get the JWKs keys. If you are using header-based auth, you can fetch the JWT from the `Authorization Bearer` header, otherwise for cookie-based auth, you can fetch it from the `sAccessToken` cookie. - - + + Refer to this [GitHub gist](https://gist.github.com/rishabhpoddar/5b2d19c02337ed7ee387723c84def9cd) for a code reference of how use the Java `nimbus-jose-jwt` lib to do session verification. The gist contains three files: - `JWTVerification.java` You need to modify the `CORE_URL` in this file to point to your SuperTokens core instance (replacing the `try.supertokens.com` part of the URL). @@ -3033,16 +3796,15 @@ Refer to this [GitHub gist](https://gist.github.com/rishabhpoddar/5b2d19c02337ed - `pom.xml`: This shows the version of `nimbus-jose-jwt` used for this project. - `InvalidClaimsException.java`: This holds the custom Exception thrown when someone has an invalid JWT body, hasn't verified their email, or hasn't set up MFA. - - + + ### With the public key string - - + + -:::caution -This method is less secure compared to the first method because it disables key rotation of the access token signing key. +:::warning[This method is less secure compared to the first method because it disables key rotation of the access token signing key.] In this case, if the private key is somehow stolen, it can be used indefinitely to forge access tokens (Unless you manually change the key in the database). ::: @@ -3050,13 +3812,11 @@ Some JWT verification libraries require you to provide the JWT secret / public k You can obtain the JWT secret from SuperTokens in the following way: - -## Query the `JWKS.json` endpoint: - -
+ +
```bash - curl --location --request GET '^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json' + curl --location --request GET '/auth/jwt/jwks.json' { "keys": [ @@ -3080,18 +3840,16 @@ You can obtain the JWT secret from SuperTokens in the following way: } ``` - :::important - The above shows an example output which returns two keys. + :::note[The above shows an example output which returns two keys.] More keys could return based on the configured key rotation setting in the core. If you notice, each key's `kid` starts with a `s-..` or a `d-..`. The `s-..` key is a static key that never changes, whereas `d-...` keys are dynamic keys that keep changing. If you are hard-coding public keys somewhere, you always want to pick the `s-..` key. One exception is that if you see a key with `kid` that doesn't start with `s-` or with `d-`, then treat that as a static key. This only happens if you used to run an older SuperTokens core that was less than version `5.0`. ::: - -## Run the NodeJS script below to convert the above output to a `PEM` file format. - -
+
+ +
```tsx import jwkToPem from 'jwk-to-pem'; @@ -3106,7 +3864,6 @@ You can obtain the JWT secret from SuperTokens in the following way: "use": "sig" }; - // @ts-ignore let certString = jwkToPem(jwk); ``` @@ -3135,12 +3892,11 @@ You can obtain the JWT secret from SuperTokens in the following way: // Use JWT }); ``` - -## Tell SuperTokens to always only use the static key when creating a new session. - +
+ You can accomplish this by setting the below configuration in the backend SDK: - ```tsx + ```tsx {15} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -3155,47 +3911,42 @@ You can accomplish this by setting the below configuration in the backend SDK: }, recipeList: [ Session.init({ - //highlight-next-line useDynamicAccessTokenSigningKey: false, }) ] }); ``` -:::caution -Updating this value causes a spike in the session refresh API, as and when users visit your application. +:::warning[Updating this value causes a spike in the session refresh API, as and when users visit your application.] ::: - +
-
- + + -:::caution -Not applicable. Please use method 1 instead. +:::warning[Not applicable. Please use method 1 instead.] ::: - - + + -:::caution -Not applicable. Please use method 1 instead. +:::warning[Not applicable. Please use method 1 instead.] ::: - - + + -:::caution -Not applicable. Please use method 1 instead. +:::warning[Not applicable. Please use method 1 instead.] ::: - -
+ + ### Check for custom claim values for authorization - - + + Once you have verified the access token, you can fetch the payload and perform authorization checks based on the values of the custom claims. For example, if you want to check if the user's email is verified, you should check the `st-ev` claim in the payload as shown below: @@ -3204,7 +3955,7 @@ import JsonWebToken, { JwtHeader, SigningKeyCallback } from 'jsonwebtoken'; import jwksClient from 'jwks-rsa'; var client = jwksClient({ - jwksUri: '^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json' + jwksUri: '/auth/jwt/jwks.json' }); function getKey(header: JwtHeader, callback: SigningKeyCallback) { @@ -3228,38 +3979,36 @@ JsonWebToken.verify(jwt, getKey, {}, function (err, decoded) { }); ``` -Claims like email verification and user roles claims are included in the access token by the backend SDK automatically. You can even [add your own custom claims](/docs/additional-verification/session-verification/claim-validation#using-the-access-token-payload) to the access token payload, and those claims will be in the JWT as expected. +Claims like email verification and user roles claims are included in the access token by the backend SDK automatically. You can even [add your own custom claims](/additional-verification/session-verification/claim-validation#using-the-access-token-payload) to the access token payload, and those claims will be in the JWT as expected. -:::important -On claim validation failure, you must send a `403` to the frontend, which causes the frontend SDK (pre-built UI SDK) to recheck the claims added on the frontend and navigate to the right screen. +:::note[On claim validation failure, you must send a `403` to the frontend, which causes the frontend SDK (pre-built UI SDK) to recheck the claims added on the frontend and navigate to the right screen.] ::: - - + + Referring once again to this [GitHub gist](https://gist.github.com/rishabhpoddar/ea31502923ec9a53136371f2b6317ffa), in `views.py`, between lines 20 and 28, the `st-ev` claim in the JWT payload undergoes verification. If the claim is not present or has a value of `false`, a `403` is sent to the frontend, causing the frontend SDK (pre-built UI SDK) to recheck the claims added on the frontend and navigate to the right screen. - - + + Referring once again to this [GitHub gist](https://gist.github.com/rishabhpoddar/8c26ed237add1a5b86481e72032abf8d), in `main.go`, between lines 32 and 44, the `st-ev` claim in the JWT payload undergoes verification. If the claim is not present or has a value of `false`, a `403` is sent to the frontend, causing the frontend SDK (pre-built UI SDK) to recheck the claims added on the frontend and navigate to the right screen. - - + + Referring once again to this [GitHub gist](https://gist.github.com/rishabhpoddar/5b2d19c02337ed7ee387723c84def9cd), in `JWTVerification.java`, between lines 42 and 58, the `st-ev` and `st-mfa` claims in the JWT payload undergo verification. If the claims are not present or have a value of `false`, a `403` is sent to the frontend, causing the frontend SDK (pre-built UI SDK) to recheck the claims added on the frontend and navigate to the right screen. - - + + ### Check for anti-csrf during authorization -:::important -You need to check for anti-cross-site request forgery (CSRF) for **non** GET requests when cookie-based authentication is active. +:::note[You need to check for anti-cross-site request forgery (CSRF) for **non** GET requests when cookie-based authentication is active.] ::: -Two methods exist for configuring [cross-site request forgery (CSRF) protection](/docs/post-authentication/session-management/security#anti-csrf): `VIA_CUSTOM_HEADER` and `VIA_TOKEN`. +Two methods exist for configuring [cross-site request forgery (CSRF) protection](/post-authentication/session-management/security#anti-csrf): `VIA_CUSTOM_HEADER` and `VIA_TOKEN`. #### `VIA_CUSTOM_HEADER` @@ -3275,9 +4024,9 @@ To verify the `anti-csrf` token, you need to compare it to the value of the `ant ## See also - - - - - - + + + + + + diff --git a/docs/additional-verification/session-verification/protect-frontend-routes.mdx b/docs/additional-verification/session-verification/protect-frontend-routes.mdx index 716f484e61..3b8c82d490 100644 --- a/docs/additional-verification/session-verification/protect-frontend-routes.mdx +++ b/docs/additional-verification/session-verification/protect-frontend-routes.mdx @@ -1,54 +1,43 @@ --- title: Protect frontend routes -hide_title: true -sidebar_position: 2 -description: >- - Protect frontend routes by requiring user sessions and verifying session - claims for access control. -page_type: guide -recipe: session -category: session-verification +description: Protect frontend routes by requiring user sessions and verifying session claims for access control. +sidebar: + order: 2 --- -# Protect frontend routes - - Protect frontend routes by requiring user sessions and verifying session claims for access control. - ## Before you start - +:::info[Access token guidance] ---
- + - + ## Protect a route - - + + You can wrap your components with the `` react component. This ensures that your component renders only if the user has logged in. If they are not logged in, the user gets redirected to the login page. -```tsx +```tsx {7,18,19,20,21} import React from "react"; import { BrowserRouter, Routes, Route, } from "react-router-dom"; -// highlight-next-line import { SuperTokensWrapper } from "supertokens-auth-react"; import { SessionAuth } from "supertokens-auth-react/recipe/session"; -// @ts-ignore import MyDashboardComponent from "./dashboard"; class App extends React.Component { @@ -58,12 +47,10 @@ class App extends React.Component { {/*Components that require to be protected by authentication*/} - // highlight-end } /> @@ -77,7 +64,7 @@ class App extends React.Component { You can provide the `requireAuth={false}` prop when using `` as shown below: -```tsx +```tsx {17,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42} import React from "react"; import { BrowserRouter, @@ -94,9 +81,7 @@ class App extends React.Component { - // highlight-end } /> @@ -107,7 +92,6 @@ class App extends React.Component { } } -// highlight-start function MyDashboardComponent(props: any) { let sessionContext = Session.useSessionContext(); @@ -123,12 +107,11 @@ function MyDashboardComponent(props: any) { return null; } -// highlight-end ``` - + - + You can use the `doesSessionExist` function to check if a session exists in all your routes. @@ -144,9 +127,9 @@ async function doesSessionExist() { } ``` - + - + ## Check the claims of a session @@ -156,8 +139,8 @@ For example, you may want to check that the session has the admin role claim for You can achieve this using the session claims validator feature. Let's take an example of using the user roles claim to check if the session has the admin claim: - - + + ```tsx import React from "react"; @@ -186,8 +169,7 @@ If all validation passes, the `props.children` component renders. If the claim validation has failed, it displays the `AccessDeniedScreen` component instead of rendering the children. You can also pass your own custom component to the `accessDeniedScreen` prop. -:::note -You can extend the `AdminRoute` component to check for other types of validators as well. +:::note[You can extend the `AdminRoute` component to check for other types of validators as well.] You can then reuse this component to protect all your app's components (In this case, you may want to rename this component to something more appropriate, like `ProtectedRoute`). ::: @@ -212,18 +194,17 @@ function ProtectedComponent() { } ``` - + - + -```tsx +```tsx {7,8,9,10,11,12,13} import Session from "supertokens-web-js/recipe/session"; import { UserRoleClaim, /*PermissionClaim*/ } from "supertokens-web-js/recipe/userroles"; async function shouldLoadRoute(): Promise { if (await Session.doesSessionExist()) { - // highlight-start let validationErrors = await Session.validateClaims({ overrideGlobalClaimValidators: (globalValidators) => [...globalValidators, @@ -231,7 +212,6 @@ async function shouldLoadRoute(): Promise { /* PermissionClaim.validators.includes("modify") */ ] }); - // highlight-end if (validationErrors.length === 0) { // user is an admin @@ -257,46 +237,43 @@ async function shouldLoadRoute(): Promise { - We can also add a `PermissionClaim` validator to enforce a permission. - If you want to have more complex access control, you can get the roles list from the session as follows, and check the list yourself: -```tsx +```tsx {6,7,8,9,10} import Session from "supertokens-web-js/recipe/session"; import { UserRoleClaim } from "supertokens-web-js/recipe/userroles"; async function shouldLoadRoute(): Promise { if (await Session.doesSessionExist()) { - // highlight-start let roles = await Session.getClaimValue({claim: UserRoleClaim}); if (Array.isArray(roles) && roles.includes("admin")) { // User is an admin return true; } - // highlight-end } // either a session does not exist, or the user is not an admin return false } ``` - + - + - + - + ## Protect a route You can use the `doesSessionExist` function to check if a session exists in all your routes. - - + + - - + + ```tsx import Session from 'supertokens-web-js/recipe/session'; @@ -310,11 +287,10 @@ async function doesSessionExist() { } ``` - - + + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; async function doesSessionExist() { if (await supertokensSession.doesSessionExist()) { // user is logged in @@ -324,16 +300,16 @@ async function doesSessionExist() { } ``` - - + + - + - + - + - + ```tsx import SuperTokens from 'supertokens-react-native'; @@ -347,9 +323,9 @@ async function doesSessionExist() { } ``` - + - + ```kotlin import android.app.Application @@ -368,9 +344,9 @@ class MainApplication: Application() { } ``` - + - + ```swift import UIKit @@ -387,9 +363,9 @@ fileprivate class ViewController: UIViewController { } ``` - + - + ```dart @@ -405,14 +381,14 @@ Future doesSessionExist() async { } ``` - + - + - + - + --- @@ -425,20 +401,19 @@ For example, you may want to check that the session has the admin role claim for You can achieve this using the session claims validator feature. Let's take an example of using the user roles claim to check if the session has the admin claim: - - + + - - + + -```tsx +```tsx {7,8,9,10,11,12,13} import Session from "supertokens-web-js/recipe/session"; import { UserRoleClaim, /*PermissionClaim*/ } from "supertokens-web-js/recipe/userroles"; async function shouldLoadRoute(): Promise { if (await Session.doesSessionExist()) { - // highlight-start let validationErrors = await Session.validateClaims({ overrideGlobalClaimValidators: (globalValidators) => [...globalValidators, @@ -446,7 +421,6 @@ async function shouldLoadRoute(): Promise { /* PermissionClaim.validators.includes("modify") */ ] }); - // highlight-end if (validationErrors.length === 0) { // user is an admin @@ -473,38 +447,32 @@ This may include a validator that enforces that you have verified the user's ema - We can also add a `PermissionClaim` validator to enforce a permission. - If you want to have more complex access control, you can get the roles list from the session as follows, and check the list yourself: -```tsx +```tsx {6,7,8,9,10} import Session from "supertokens-web-js/recipe/session"; import { UserRoleClaim } from "supertokens-web-js/recipe/userroles"; async function shouldLoadRoute(): Promise { if (await Session.doesSessionExist()) { - // highlight-start let roles = await Session.getClaimValue({claim: UserRoleClaim}); if (roles !== undefined && roles.includes("admin")) { // User is an admin return true; } - // highlight-end } // either a session does not exist, or the user is not an admin return false } ``` - - + + -```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensUserRoles from "supertokens-web-js-script/recipe/userroles"; +```tsx {4,5,6,7,8,9,10} async function shouldLoadRoute(): Promise { if (await supertokensSession.doesSessionExist()) { - // highlight-start let validationErrors = await supertokensSession.validateClaims({ overrideGlobalClaimValidators: (globalValidators) => [...globalValidators, @@ -512,7 +480,6 @@ async function shouldLoadRoute(): Promise { /* supertokensUserRoles.PermissionClaim.validators.includes("modify") */ ] }); - // highlight-end if (validationErrors.length === 0) { // user is an admin @@ -539,42 +506,37 @@ async function shouldLoadRoute(): Promise { If you want to have more complex access control, you can get the roles list from the session as follows, and check the list yourself: -```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensUserRoles from "supertokens-web-js-script/recipe/userroles"; +```tsx {3,4,5,6,7} async function shouldLoadRoute(): Promise { if (await supertokensSession.doesSessionExist()) { - // highlight-start let roles = await supertokensSession.getClaimValue({claim: supertokensUserRoles.UserRoleClaim}); if (roles !== undefined && roles.includes("admin")) { // User is an admin return true; } - // highlight-end } // either a session does not exist, or the user is not an admin return false } ``` - - + + - + - + - + - + -```tsx +```tsx {6,7,8,9,10,11,12} import SuperTokens from 'supertokens-react-native'; async function getRole() { if (await SuperTokens.doesSessionExist()) { - // highlight-start let roles: string[] = (await SuperTokens.getAccessTokenPayloadSecurely())["st-role"].v; if (roles.includes("admin")) { @@ -582,14 +544,13 @@ async function getRole() { } else { // TODO.. } - // highlight-end } } ``` - + - + ```kotlin import android.app.Application @@ -609,9 +570,9 @@ class MainApplication: Application() { } ``` - + - + ```swift import UIKit @@ -630,9 +591,9 @@ fileprivate class ViewController: UIViewController { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -656,27 +617,27 @@ Future checkIfUserIsAnAdmin() async { } ``` - + - + - + - + - + -:::tip Feature -You can also [build your own custom claim validators](/docs/additional-verification/session-verification/claim-validation#using-session-claims) based on your app's requirements. +:::tip[Feature] +You can also [build your own custom claim validators](/additional-verification/session-verification/claim-validation#using-session-claims) based on your app's requirements. ::: --- ## See also - - - - - - + + + + + + diff --git a/docs/additional-verification/session-verification/ssr.mdx b/docs/additional-verification/session-verification/ssr.mdx index 871116e09a..ec9af7c775 100644 --- a/docs/additional-verification/session-verification/ssr.mdx +++ b/docs/additional-verification/session-verification/ssr.mdx @@ -1,21 +1,10 @@ --- -id: ssr title: Session verification during server side rendering -hide_title: true -toc_max_heading_level: 4 -sidebar_position: 3 -description: >- - Enable session verification during server-side rendering using cookie-based - sessions and JWT verification. -page_type: guide -recipe: session -category: session-verification +description: Enable session verification during server-side rendering using cookie-based sessions and JWT verification. +sidebar: + order: 3 --- - - -# Session verification during server side rendering - ## Overview In Server Side Rendering (SSR) scenarios, the session verification process is slightly different. @@ -26,7 +15,7 @@ Check the following guide to understand how to adjust the flow to work with SSR. Getting access to the session during server side rendering is only possible using cookie-based sessions. This is the default setting, but you have to keep this in mind if you want to switch to header-based sessions. - +:::info[Access token guidance] ## Steps @@ -34,11 +23,11 @@ This is the default setting, but you have to keep this in mind if you want to sw If your API layer and website are on different sub domains (like `example.com` and `api.example.com`), then by default, the session tokens attach only to `api.example.com`. Change this to ensure that the session tokens attach to `.example.com` and the access token cookie goes to your web server on `example.com`. -Enable this by [setting the `cookieDomain` configuration on the backend](/docs/post-authentication/session-management/advanced-workflows/multiple-api-endpoints). +Enable this by [setting the `cookieDomain` configuration on the backend](/post-authentication/session-management/advanced-workflows/multiple-api-endpoints). ### 2. Do JWT verification -Follow the [JWT verification guide](/docs/additional-verification/session-verification/protect-api-routes#using-a-jwt-verification-library) to verify the JWT on the server side. +Follow the [JWT verification guide](/additional-verification/session-verification/protect-api-routes#using-a-jwt-verification-library) to verify the JWT on the server side. You can read the JWT from the `sAccessToken` cookie in the request object. If the JWT is missing, invalid, or expired, redirect the user to a `/refresh-session?redirectBack=` page. You can have any path for this since it's your website. @@ -59,12 +48,12 @@ Either way, you want to redirect the user to the login page. Below is the code snippet that you can use on the `/refresh-session` path on the frontend - + - + - - + + ```tsx import React from "react"; @@ -98,9 +87,9 @@ export function AttemptRefresh(props: any) { } ``` - + - + ```tsx import Session from 'supertokens-web-js/recipe/session'; @@ -121,19 +110,19 @@ function attemptRefresh() { } ``` - + - + - + - + - - + + - - + + ```tsx import Session from 'supertokens-web-js/recipe/session'; @@ -154,11 +143,10 @@ function attemptRefresh() { } ``` - - + + ```tsx -import supertokensSession from 'supertokens-web-js-script/recipe/session'; function attemptRefresh() { supertokensSession.attemptRefreshingSession().then(success => { if (success) { @@ -175,22 +163,21 @@ function attemptRefresh() { } ``` - - + + - + - + -:::caution -Server side rendering is not applicable for mobile apps. +:::warning[Server side rendering is not applicable for mobile apps.] ::: - + - + - + #### Why trigger the refresh session flow instead of redirecting the user to the login page directly? @@ -216,9 +203,9 @@ This can cause inconsistency between the access token payload as seen on the fro ## See also - - - - - - + + + + + + diff --git a/docs/additional-verification/session-verification/with-websocket.mdx b/docs/additional-verification/session-verification/with-websocket.mdx index 9da03a2d10..f99b0a6bae 100644 --- a/docs/additional-verification/session-verification/with-websocket.mdx +++ b/docs/additional-verification/session-verification/with-websocket.mdx @@ -1,19 +1,10 @@ --- -id: with-websocket title: WebSocket session verification -hide_title: true -sidebar_position: 4 -description: >- - Verify WebSocket sessions by fetching and sending JWTs during socket - connection initialization. -page_type: guide -recipe: session -category: session-verification +description: Verify WebSocket sessions by fetching and sending JWTs during socket connection initialization. +sidebar: + order: 4 --- - -# WebSocket Session Verification - ## Overview Socket connections do not always use HTTP, which means you cannot use cookies or HTTP authorization header here. @@ -21,7 +12,7 @@ Instead, the frontend must fetch the JWT and send it at the start of the socket ## Before you start - +:::info[Access token guidance] ## Steps @@ -30,10 +21,10 @@ Instead, the frontend must fetch the JWT and send it at the start of the socket Ensure that the JWT is available to the frontend. This is already the case in header based auth, but if you are using cookie based auth, then you should set the following boolean to true in `session.init` on the backend: - - + + -```tsx +```tsx {15} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -48,17 +39,15 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - //highlight-start exposeAccessTokenToFrontendInCookieBasedAuth: true - //highlight-end }) ] }); ``` - - + + -```go +```go {11} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -69,36 +58,33 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - //highlight-start ExposeAccessTokenToFrontendInCookieBasedAuth: true, - //highlight-end }), }, }) } ``` - - + + -```python +```python {10} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-next-line expose_access_token_to_frontend_in_cookie_based_auth=True ) ] ) ``` - - + + ### 2. Send the JWT on socket connection start @@ -106,7 +92,6 @@ On the client side, when you create a socket connection, you must fetch the JWT ```tsx import Session from "supertokens-web-js/recipe/session" -declare let io: any; // REMOVE_FROM_OUTPUT async function initSocketConnection() { const token = await Session.getAccessToken(); @@ -120,27 +105,24 @@ async function initSocketConnection() { } ``` -- See the [docs on how to fetch the access token on the frontend for all frameworks](/docs/post-authentication/session-management/access-session-data#on-the-frontend) if needed. +- See the [docs on how to fetch the access token on the frontend for all frameworks](/post-authentication/session-management/access-session-data#on-the-frontend) if needed. - The `Session.getAccessToken()` function auto refreshes the session before returning the JWT if needed. -:::caution -Make sure to close the socket connection whenever appropriate to avoid sending stale JWTs. +:::warning[Make sure to close the socket connection whenever appropriate to avoid sending stale JWTs.] ::: ### 3. Verify the JWT Verify the JWT on socket connection initialisation on the backend: - -```tsx +```tsx {18,19,20,21,22,23,24,25,26,27,28} import jwt, { JwtHeader, SigningKeyCallback } from 'jsonwebtoken'; import jwksClient from 'jwks-rsa'; -declare let io: any // REMOVE_FROM_OUTPUT // functions to fetch jwks var client = jwksClient({ - jwksUri: '^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json' + jwksUri: '/auth/jwt/jwks.json' }); function getKey(header: JwtHeader, callback: SigningKeyCallback) { @@ -152,7 +134,6 @@ function getKey(header: JwtHeader, callback: SigningKeyCallback) { // socket io connection io.use(function (socket: any, next: any) { - // highlight-start // we first try and verify the jwt from the token param. if (socket.handshake.query && socket.handshake.query.token) { jwt.verify(socket.handshake.query.token, getKey, {}, function (err, decoded) { @@ -164,7 +145,6 @@ io.use(function (socket: any, next: any) { else { next(new Error('Authentication error')); } - // highlight-end }) .on('connection', function (socket: any) { // Connection now authenticated to receive further events @@ -175,8 +155,7 @@ io.use(function (socket: any, next: any) { }); ``` -:::important -Post verification, ensure that the claims in the JWT align with your authorization rules. +:::note[Post verification, ensure that the claims in the JWT align with your authorization rules.] For example, if your app requires that the user verifies their email before they use it, check that the `decoded["st-ev"].v` claim in the JWT equals `true`. @@ -187,9 +166,9 @@ Normally, the backend SDK's `getSession` or `verifySession` function performs th ## See also - - - - - - + + + + + + diff --git a/docs/additional-verification/user-roles/_blocks/assign-role-to-session.mdx b/docs/additional-verification/user-roles/_blocks/assign-role-to-session.mdx deleted file mode 100644 index c86a224ae8..0000000000 --- a/docs/additional-verification/user-roles/_blocks/assign-role-to-session.mdx +++ /dev/null @@ -1,82 +0,0 @@ - - - - -```tsx -import {UserRoleClaim, PermissionClaim} from "supertokens-node/recipe/userroles"; -import {SessionContainer} from "supertokens-node/recipe/session" - -async function addRolesAndPermissionsToSession(session: SessionContainer) { - // we add the user's roles to the user's session - await session.fetchAndSetClaim(UserRoleClaim) - - // we add the permissions of a user to the user's session - await session.fetchAndSetClaim(PermissionClaim) -} -``` - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" - "github.com/supertokens/supertokens-golang/recipe/userroles/userrolesclaims" -) - -func addRolesAndPermissionsToSession(session sessmodels.SessionContainer) error { - // we add the user's roles to the user's session - err := session.FetchAndSetClaim(userrolesclaims.UserRoleClaim) - if err != nil { - return err - } - - // we add the user's permissions to the user's session - err = session.FetchAndSetClaim(userrolesclaims.PermissionClaim) - if err != nil { - return err - } - - return nil -} -``` - - - - - - - -```python -from supertokens_python.recipe.session import SessionContainer -from supertokens_python.recipe.userroles import UserRoleClaim, PermissionClaim - - -async def add_roles_and_permissions_to_session(session: SessionContainer): - # we add the user's roles to the user's session - await session.fetch_and_set_claim(UserRoleClaim) - - # we add the user's permissions to the user's session - await session.fetch_and_set_claim(PermissionClaim) -``` - - - - -```python -from supertokens_python.recipe.session import SessionContainer -from supertokens_python.recipe.userroles import UserRoleClaim, PermissionClaim - - -def add_roles_and_permissions_to_session(session: SessionContainer): - # we add the user's roles to the user's session - session.sync_fetch_and_set_claim(UserRoleClaim) - - # we add the user's permissions to the user's session - session.sync_fetch_and_set_claim(PermissionClaim) -``` - - - - - diff --git a/docs/additional-verification/user-roles/_blocks/assign-role-to-user.mdx b/docs/additional-verification/user-roles/_blocks/assign-role-to-user.mdx deleted file mode 100644 index 591f26eba3..0000000000 --- a/docs/additional-verification/user-roles/_blocks/assign-role-to-user.mdx +++ /dev/null @@ -1,119 +0,0 @@ - - - - - -```tsx -import UserRoles from "supertokens-node/recipe/userroles"; - -async function addRoleToUser(userId: string) { - // highlight-start - const response = await UserRoles.addRoleToUser("public", userId, "user"); - - if (response.status === "UNKNOWN_ROLE_ERROR") { - // No such role exists - return; - } - - if (response.didUserAlreadyHaveRole === true) { - // The user already had the role - } - // highlight-end -} -``` - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/userroles" -) - -func addRoleToUser(userId string) { - // highlight-start - response, err := userroles.AddRoleToUser("public", userId, "user", nil) - if err != nil { - // TODO: Handle error - return - } - - if response.UnknownRoleError != nil { - // No such role exists - return - } - - if response.OK.DidUserAlreadyHaveRole { - // The user already had the role - } - // highlight-end -} -``` - - - - - - - -```python -from supertokens_python.recipe.userroles.asyncio import add_role_to_user -from supertokens_python.recipe.userroles.interfaces import UnknownRoleError - - -async def add_role_to_user_func(user_id: str): - # highlight-start - role = "user" - res = await add_role_to_user("public", user_id, role) - if isinstance(res, UnknownRoleError): - # No such role exists - return - - if res.did_user_already_have_role: - # User already had this role - pass - # highlight-end -``` - - - - -```python -from supertokens_python.recipe.userroles.syncio import add_role_to_user -from supertokens_python.recipe.userroles.interfaces import UnknownRoleError - - -def add_role_to_user_func(user_id: str): - # highlight-start - role = "user" - res = add_role_to_user("public", user_id, role) - if isinstance(res, UnknownRoleError): - # No such role exists - return - - if res.did_user_already_have_role: - # User already had this role - pass - # highlight-end - -``` - - - - - - - -```bash -curl --location --request PUT 'http://localhost:3567/recipe/user/role' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "userId": "fa7a0841-b533-4478-95533-0fde890c3483", - "role": "user" -}' -``` - - - - diff --git a/docs/additional-verification/user-roles/_blocks/create-role.mdx b/docs/additional-verification/user-roles/_blocks/create-role.mdx deleted file mode 100644 index 14c498a206..0000000000 --- a/docs/additional-verification/user-roles/_blocks/create-role.mdx +++ /dev/null @@ -1,108 +0,0 @@ - - - - -```tsx -import UserRoles from "supertokens-node/recipe/userroles"; - -async function createRole() { - // highlight-start - const response = await UserRoles.createNewRoleOrAddPermissions("user", ["read"]); - - if (response.createdNewRole === false) { - // The role already exists - } - // highlight-end -} -``` - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/userroles" -) - -func createRole() { - // highlight-start - resp, err := userroles.CreateNewRoleOrAddPermissions("user", []string{ - "read", - }, nil) - - if err != nil { - // TODO: Handle error - return - } - if resp.OK.CreatedNewRole == false { - // The role already exists - } - // highlight-end -} -``` - - - - - - - -```python -from supertokens_python.recipe.userroles.asyncio import create_new_role_or_add_permissions - -async def create_role(): - # highlight-start - res = await create_new_role_or_add_permissions("user", ["read"]) - if not res.created_new_role: - # The role already existed - pass - # highlight-end - -``` - - - - - -```python -from supertokens_python.recipe.userroles.syncio import create_new_role_or_add_permissions - -def create_role(): - # highlight-start - res = create_new_role_or_add_permissions("user", ["read"]) - if not res.created_new_role: - # The role already existed - pass - # highlight-end - -``` - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}/recipe/role' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "role": "user", - "permissions": [ - "read" - ] -}' - -``` - - - - - -Create Role - - - - diff --git a/docs/additional-verification/user-roles/_category_.json b/docs/additional-verification/user-roles/_category_.json deleted file mode 100644 index f02d0f2e64..0000000000 --- a/docs/additional-verification/user-roles/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "User Roles", - "position": 4 -} diff --git a/docs/additional-verification/user-roles/initial-setup.mdx b/docs/additional-verification/user-roles/initial-setup.mdx index 8bfccd55a0..164dd11a13 100644 --- a/docs/additional-verification/user-roles/initial-setup.mdx +++ b/docs/additional-verification/user-roles/initial-setup.mdx @@ -1,30 +1,23 @@ --- -sidebar_position: 2 title: Initial Setup -toc_max_heading_level: 4 -hide_title: true description: Learn how to initialize and configure user roles with SuperTokens. -page_type: tutorial -recipe: userroles -category: user-roles +sidebar: + order: 2 --- - -import CreateRole from "./_blocks/create-role.mdx"; -import AssignRoleToUser from "./_blocks/assign-role-to-user.mdx"; -import AssignRoleToSession from "./_blocks/assign-role-to-session.mdx"; - -# Initial setup - - - ## Overview When you work with the `UserRoles` recipe you should follow these steps: -## Create a role and assign permissions to it -## Assign roles to users -## Protect frontend and backend routes by verifying that the user has the correct role and permissions + + + + + + + + + The next sections show you the actual instructions on how to achieve this. @@ -32,7 +25,7 @@ The next sections show you the actual instructions on how to achieve this. ## Before you start -:::info Multi Tenancy +:::info[Multi Tenancy] In a multi tenant setup, roles, and permissions share across all tenants, however, the mapping of users to roles are on a per tenant level. @@ -46,10 +39,10 @@ If you have user ID `user1` that has access to `tenant1` and `tenant2`, you can ### 1. Initialize the recipe - - + + -```tsx +```tsx {14} import SuperTokens from "supertokens-node"; import UserRoles from "supertokens-node/recipe/userroles"; @@ -63,16 +56,15 @@ SuperTokens.init({ websiteDomain: "..." }, recipeList: [ - // highlight-next-line UserRoles.init(), ] }); ``` - - + + -```go +```go {9} import ( "github.com/supertokens/supertokens-golang/recipe/userroles" "github.com/supertokens/supertokens-golang/supertokens" @@ -81,17 +73,16 @@ import ( func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ - // highlight-next-line userroles.Init(nil), }, }) } ``` - - + + -```python +```python {11} from supertokens_python import InputAppInfo, init from supertokens_python.recipe import userroles @@ -99,38 +90,35 @@ init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..." ), - framework='...', # type: ignore + framework='...', recipe_list=[ # Initialize other recipes as seen in the quick setup guide - # highlight-next-line userroles.init() ] ) ``` - - + + By default, the user roles recipe adds the roles and permission information into a user's session (if they have assigned roles & permissions). If you do not want roles or permissions information in the session, or want to manually add it yourself, you can provide the following input configs to the `UserRoles.init` function: - - + + -```tsx +```tsx {4,5} import UserRoles from "supertokens-node/recipe/userroles"; UserRoles.init({ - // highlight-start skipAddingRolesToAccessToken: true, skipAddingPermissionsToAccessToken: true, - // highlight-end }) ``` - - + + -```go +```go {11,12,13,14} import ( "github.com/supertokens/supertokens-golang/recipe/userroles" "github.com/supertokens/supertokens-golang/recipe/userroles/userrolesmodels" @@ -141,21 +129,19 @@ func main() { supertokens.Init(supertokens.TypeInput{ AppInfo: supertokens.AppInfo{ /*...*/ }, RecipeList: []supertokens.Recipe{ - // highlight-start userroles.Init(&userrolesmodels.TypeInput{ SkipAddingRolesToAccessToken: true, SkipAddingPermissionsToAccessToken: true, }), - // highlight-end }, }) } ``` - - + + -```python +```python {10,11} from supertokens_python import InputAppInfo, init from supertokens_python.recipe import userroles @@ -163,18 +149,16 @@ init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..." ), - framework='...', # type: ignore + framework='...', recipe_list=[ - # highlight-start userroles.init(skip_adding_roles_to_access_token=True, skip_adding_permissions_to_access_token=True) - # highlight-end ] ) ``` - - + + ### 2. Create roles and permissions @@ -184,7 +168,105 @@ They should represent entities and actions that are relevant to your business lo To create them use the next code snippet as a reference. When you create a role you can also include the permissions that the role should have. - + + + +```tsx {4,5,6,7,8} +import UserRoles from "supertokens-node/recipe/userroles"; + +async function createRole() { + const response = await UserRoles.createNewRoleOrAddPermissions("user", ["read"]); + + if (response.createdNewRole === false) { + // The role already exists + } +} +``` + + + + +```go {6,7,8,9,10,11,12,13,14,15,16} +import ( + "github.com/supertokens/supertokens-golang/recipe/userroles" +) + +func createRole() { + resp, err := userroles.CreateNewRoleOrAddPermissions("user", []string{ + "read", + }, nil) + + if err != nil { + // TODO: Handle error + return + } + if resp.OK.CreatedNewRole == false { + // The role already exists + } +} +``` + + + + + + + +```python {4,5,6,7} +from supertokens_python.recipe.userroles.asyncio import create_new_role_or_add_permissions + +async def create_role(): + res = await create_new_role_or_add_permissions("user", ["read"]) + if not res.created_new_role: + # The role already existed + pass + +``` + + + + + +```python {4,5,6,7} +from supertokens_python.recipe.userroles.syncio import create_new_role_or_add_permissions + +def create_role(): + res = create_new_role_or_add_permissions("user", ["read"]) + if not res.created_new_role: + # The role already existed + pass + +``` + + + + + + + + +```bash +curl --location --request PUT '/recipe/role' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "role": "user", + "permissions": [ + "read" + ] +}' + +``` + + + + + +Create Role + + + + ### 3. Assign roles to users @@ -192,19 +274,207 @@ When you create a role you can also include the permissions that the role should After you create a user account, you can assign roles to them. You can do this by overriding the authentication recipes with a function that calls the `UserRoles` API after a successful sign up. The next code snippet shows you what function to call to connect a user to a role. -To figure out where to call that function, check the documentation for the authentication method that you use: [passwordless](/docs/authentication/passwordless/hooks-and-overrides), [email-password](/docs/authentication/email-password/hooks-and-overrides) or [third-party](/docs/authentication/social/hooks-and-overrides). +To figure out where to call that function, check the documentation for the authentication method that you use: [passwordless](/authentication/passwordless/hooks-and-overrides), [email-password](/authentication/email-password/hooks-and-overrides) or [third-party](/authentication/social/hooks-and-overrides). + + + + +```tsx {4,5,6,7,8,9,10,11,12,13} +import UserRoles from "supertokens-node/recipe/userroles"; + +async function addRoleToUser(userId: string) { + const response = await UserRoles.addRoleToUser("public", userId, "user"); + + if (response.status === "UNKNOWN_ROLE_ERROR") { + // No such role exists + return; + } + + if (response.didUserAlreadyHaveRole === true) { + // The user already had the role + } +} +``` - + + + +```go {6,7,8,9,10,11,12,13,14,15,16,17,18,19} +import ( + "github.com/supertokens/supertokens-golang/recipe/userroles" +) + +func addRoleToUser(userId string) { + response, err := userroles.AddRoleToUser("public", userId, "user", nil) + if err != nil { + // TODO: Handle error + return + } + + if response.UnknownRoleError != nil { + // No such role exists + return + } + + if response.OK.DidUserAlreadyHaveRole { + // The user already had the role + } +} +``` + + + + + + + +```python {6,7,8,9,10,11,12,13,14} +from supertokens_python.recipe.userroles.asyncio import add_role_to_user +from supertokens_python.recipe.userroles.interfaces import UnknownRoleError + + +async def add_role_to_user_func(user_id: str): + role = "user" + res = await add_role_to_user("public", user_id, role) + if isinstance(res, UnknownRoleError): + # No such role exists + return + + if res.did_user_already_have_role: + # User already had this role + pass +``` + + + + +```python {6,7,8,9,10,11,12,13,14} +from supertokens_python.recipe.userroles.syncio import add_role_to_user +from supertokens_python.recipe.userroles.interfaces import UnknownRoleError + + +def add_role_to_user_func(user_id: str): + role = "user" + res = add_role_to_user("public", user_id, role) + if isinstance(res, UnknownRoleError): + # No such role exists + return + + if res.did_user_already_have_role: + # User already had this role + pass + +``` + + + + + + + +```bash +curl --location --request PUT 'http://localhost:3567/recipe/user/role' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "userId": "fa7a0841-b533-4478-95533-0fde890c3483", + "role": "user" +}' +``` + + + + #### Assign roles to a session If you want to associate a role to a user after you create a session, you can do this by manually calling the function described in the next code snippet. -For information on how to access the session object that you need to pass to the function, check either the [`Verify Session`](/docs/additional-verification/session-verification/protect-api-routes#using-verify-session) or the [`Get Session`](/docs/additional-verification/session-verification/protect-api-routes#using-get-session) documentation. +For information on how to access the session object that you need to pass to the function, check either the [`Verify Session`](/additional-verification/session-verification/protect-api-routes#using-verify-session) or the [`Get Session`](/additional-verification/session-verification/protect-api-routes#using-get-session) documentation. + + + + +```tsx +import {UserRoleClaim, PermissionClaim} from "supertokens-node/recipe/userroles"; +import {SessionContainer} from "supertokens-node/recipe/session" - +async function addRolesAndPermissionsToSession(session: SessionContainer) { + // we add the user's roles to the user's session + await session.fetchAndSetClaim(UserRoleClaim) -:::info Multi Tenancy + // we add the permissions of a user to the user's session + await session.fetchAndSetClaim(PermissionClaim) +} +``` + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" + "github.com/supertokens/supertokens-golang/recipe/userroles/userrolesclaims" +) + +func addRolesAndPermissionsToSession(session sessmodels.SessionContainer) error { + // we add the user's roles to the user's session + err := session.FetchAndSetClaim(userrolesclaims.UserRoleClaim) + if err != nil { + return err + } + + // we add the user's permissions to the user's session + err = session.FetchAndSetClaim(userrolesclaims.PermissionClaim) + if err != nil { + return err + } + + return nil +} +``` + + + + + + + +```python +from supertokens_python.recipe.session import SessionContainer +from supertokens_python.recipe.userroles import UserRoleClaim, PermissionClaim + + +async def add_roles_and_permissions_to_session(session: SessionContainer): + # we add the user's roles to the user's session + await session.fetch_and_set_claim(UserRoleClaim) + + # we add the user's permissions to the user's session + await session.fetch_and_set_claim(PermissionClaim) +``` + + + + +```python +from supertokens_python.recipe.session import SessionContainer +from supertokens_python.recipe.userroles import UserRoleClaim, PermissionClaim + + +def add_roles_and_permissions_to_session(session: SessionContainer): + # we add the user's roles to the user's session + session.sync_fetch_and_set_claim(UserRoleClaim) + + # we add the user's permissions to the user's session + session.sync_fetch_and_set_claim(PermissionClaim) +``` + + + + + + +:::info[Multi Tenancy] Whilst roles and permissions share across apps, the association of roles to users is on a per tenant level. If using SDK functions to add a role to a user, you can also pass in a `tenantId` to the function. This tells SuperTokens to add the role for that user for that tenant. @@ -218,10 +488,9 @@ Note that if you associate a role to a user ID for a tenant, and that user ID do ## See also - - - - - - - + + + + + + diff --git a/docs/additional-verification/user-roles/introduction.mdx b/docs/additional-verification/user-roles/introduction.mdx index 0f243b1826..ece59bb414 100644 --- a/docs/additional-verification/user-roles/introduction.mdx +++ b/docs/additional-verification/user-roles/introduction.mdx @@ -1,62 +1,37 @@ --- -sidebar_position: 1 title: Introduction -hide_title: true -skip_llms_txt: true description: Manage user roles and permissions with SuperTokens. -page_type: overview -recipe: userroles -category: user-roles +sidebar: + order: 1 --- - -# User roles - ## Overview **SuperTokens** provides a way to set different levels of authorization control through the `User Roles` feature. With it, you can create roles and permissions, assign them to your users and limit access based on your application logic. -Basic User Roles Architecture +Basic User Roles Architecture ## Getting started You can go through the *Initial Setup* page for a quick tutorial on how to configure the feature. - - - - Quickstart - - - Go through a quick tutorial that shows you how to add the **Email Verification** recipe to your application. - - - + + +Go through a quick tutorial that shows you how to add the **Email Verification** recipe to your application. + + ## Customization To adjust the functionality to fit your use case you can explore different sections from the documentation. - - - - Protect frontend and backend routes - - - Limit the access to your frontend and backend routes based on roles and permissions. - - - - - Manage roles and permissions - - - Create new roles and permissions, assign them to users and manage them. - - - - - - + + +Limit the access to your frontend and backend routes based on roles and permissions. + + +Create new roles and permissions, assign them to users and manage them. + + diff --git a/docs/additional-verification/user-roles/meta.ts b/docs/additional-verification/user-roles/meta.ts new file mode 100644 index 0000000000..f1adca2037 --- /dev/null +++ b/docs/additional-verification/user-roles/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "User Roles", + "icon": "shield-user", + "order": 4 +}); diff --git a/docs/additional-verification/user-roles/protecting-routes.mdx b/docs/additional-verification/user-roles/protecting-routes.mdx index 51bda315a9..e25a23d559 100644 --- a/docs/additional-verification/user-roles/protecting-routes.mdx +++ b/docs/additional-verification/user-roles/protecting-routes.mdx @@ -1,30 +1,22 @@ --- -sidebar_position: 5 title: Protect frontend and backend routes -hide_title: true -description: >- - Protect frontend and backend routes using SuperTokens session access tokens - and role-based validation. -page_type: guide -recipe: userroles -category: user-roles +description: Protect frontend and backend routes using SuperTokens session access tokens and role-based validation. +sidebar: + order: 5 --- - -# Protect frontend and backend routes - ## Overview To limit access to your application resources based on roles and permissions you have to use the `UserRoleClaim` inside the session validation logic. ## Before you start - +:::info[Access token guidance] -If you are implementing [**Unified Login**](/docs/authentication/unified-login/introduction), which uses **OAuth2 Access Tokens**, please check the [separate page](/docs/authentication/unified-login/verify-tokens) that shows you how to validate them. +If you are implementing [**Unified Login**](/authentication/unified-login/introduction), which uses **OAuth2 Access Tokens**, please check the [separate page](/authentication/unified-login/verify-tokens) that shows you how to validate them. You have to check for the `roles` claim in the token payload. - +::: --- @@ -39,10 +31,10 @@ To perform the verification follow these steps: - Optionally, add a `PermissionClaim` validator to enforce a permission. - - - - + + + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/express"; @@ -66,8 +58,8 @@ app.post( } ); ``` - - + + ```tsx import Hapi from "@hapi/hapi"; @@ -98,8 +90,8 @@ server.route({ } }) ``` - - + + ```tsx import Fastify from "fastify"; @@ -122,8 +114,8 @@ fastify.post("/update-blog", { }); ``` - - + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; @@ -143,8 +135,8 @@ exports.handler = verifySession(updateBlog, { }); ``` - - + + ```tsx import KoaRouter from "koa-router"; @@ -165,8 +157,8 @@ router.post("/update-blog", verifySession({ }); ``` - - + + ```tsx import { inject, intercept } from "@loopback/core"; @@ -192,22 +184,21 @@ class SetRole { } ``` - - + + + - - + -```tsx +```tsx {6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; import UserRoles from "supertokens-node/recipe/userroles"; -// highlight-start export default async function setRole(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { @@ -229,12 +220,11 @@ export default async function setRole(req: SessionRequest, res: any) { -```tsx +```tsx {18,19,20} import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import UserRoles from "supertokens-node/recipe/userroles"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -248,24 +238,21 @@ export function POST(request: NextRequest) { return NextResponse.json({}) }, { - // highlight-start overrideGlobalClaimValidators: async function (globalClaimValidators) { return [...globalClaimValidators, UserRoles.UserRoleClaim.validators.includes("admin")] } - // highlight-end }); } ``` - - + + ```tsx import { Controller, Post, UseGuards, Request, Response, Session } from "@nestjs/common"; import { SessionContainer, SessionClaimValidator } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; import UserRoles from "supertokens-node/recipe/userroles"; @@ -285,15 +272,15 @@ export class ExampleController { } } ``` - + - - - - - + + + + + -```go +```go {14,15,16,17} import ( "net/http" @@ -307,12 +294,10 @@ import ( func main() { _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, userrolesclaims.UserRoleClaimValidators.Includes("admin", nil, nil)) return globalClaimValidators, nil }, - // highlight-end }, exampleAPI).ServeHTTP(rw, r) }) } @@ -322,10 +307,10 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + -```go +```go {17,18,19,20} import ( "net/http" @@ -342,12 +327,10 @@ func main() { // Wrap the API handler in session.VerifySession router.POST("/likecomment", verifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, userrolesclaims.UserRoleClaimValidators.Includes("admin", nil, nil)) return globalClaimValidators, nil }, - // highlight-end }), exampleAPI) } @@ -369,10 +352,10 @@ func exampleAPI(c *gin.Context) { } ``` - - + + -```go +```go {17,18,19,20} import ( "net/http" @@ -389,12 +372,10 @@ func main() { // Wrap the API handler in session.VerifySession r.Post("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, userrolesclaims.UserRoleClaimValidators.Includes("admin", nil, nil)) return globalClaimValidators, nil }, - // highlight-end }, exampleAPI)) } @@ -404,10 +385,10 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { ``` - - + + -```go +```go {17,18,19,20} import ( "net/http" @@ -424,12 +405,10 @@ func main() { // Wrap the API handler in session.VerifySession router.HandleFunc("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{ - // highlight-start OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) { globalClaimValidators = append(globalClaimValidators, userrolesclaims.UserRoleClaimValidators.Includes("admin", nil, nil)) return globalClaimValidators, nil }, - // highlight-end }, exampleAPI)).Methods(http.MethodPost) } @@ -438,15 +417,15 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + - - + + -```python +```python {11,12,13} from fastapi import Depends from supertokens_python.recipe.session import SessionContainer @@ -454,45 +433,41 @@ from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.userroles import UserRoleClaim -@app.post('/like_comment') # type: ignore +@app.post('/like_comment') async def like_comment(session: SessionContainer = Depends( verify_session( - # highlight-start # We add the UserRoleClaim's includes validator override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \ [UserRoleClaim.validators.includes("admin")] - # highlight-end ) )): # All validator checks have passed and the user has a verified email address pass ``` - - + + -```python +```python {7,8,9} from supertokens_python.recipe.session.framework.flask import verify_session from supertokens_python.recipe.userroles import UserRoleClaim -@app.route('/update-jwt', methods=['POST']) # type: ignore +@app.route('/update-jwt', methods=['POST']) @verify_session( - # highlight-start # We add the UserRoleClaim's includes validator override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \ [UserRoleClaim.validators.includes("admin")] - # highlight-end ) def like_comment(): # All validator checks have passed and the user has a verified email address pass ``` - - + + -```python +```python {8,9,10} from django.http import HttpRequest from supertokens_python.recipe.session.framework.django.asyncio import verify_session @@ -500,34 +475,32 @@ from supertokens_python.recipe.userroles import UserRoleClaim @verify_session( - # highlight-start # We add the UserRoleClaim's includes validator override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \ [UserRoleClaim.validators.includes("admin")] - # highlight-end ) async def like_comment(request: HttpRequest): # All validator checks have passed and the user has a verified email address pass ``` - - + + - - + + ### Custom validation If you want to have more complex access control you can get the list of roles attached to the session and introduce your own logic. - - - - + + + + -```tsx +```tsx {10,11,12,13,14,15,16,17,18,19,20,21} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; @@ -537,7 +510,6 @@ import { Error as STError } from "supertokens-node/recipe/session" let app = express(); app.post("/update-blog", verifySession(), async (req: SessionRequest, res) => { - // highlight-start const roles = await req.session!.getClaimValue(UserRoles.UserRoleClaim); if (roles === undefined || !roles.includes("admin")) { @@ -550,14 +522,13 @@ app.post("/update-blog", verifySession(), async (req: SessionRequest, res) => { }] }) } - // highlight-end // user is an admin.. }); ``` - - + + -```tsx +```tsx {20,21,22,23,24,25,26,27,28,29,30,31} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import {SessionRequest} from "supertokens-node/framework/hapi"; @@ -577,7 +548,6 @@ server.route({ ], }, handler: async (req: SessionRequest, res) => { - // highlight-start const roles = await req.session!.getClaimValue(UserRoles.UserRoleClaim); if (roles === undefined || !roles.includes("admin")) { @@ -590,15 +560,14 @@ server.route({ }] }) } - // highlight-end // user is an admin.. } }) ``` - - + + -```tsx +```tsx {12,13,14,15,16,17,18,19,20,21,22,23} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import { SessionRequest } from "supertokens-node/framework/fastify"; @@ -610,7 +579,6 @@ let fastify = Fastify(); fastify.post("/update-blog", { preHandler: verifySession(), }, async (req: SessionRequest, res) => { - // highlight-start const roles = await req.session!.getClaimValue(UserRoles.UserRoleClaim); if (roles === undefined || !roles.includes("admin")) { @@ -623,22 +591,20 @@ fastify.post("/update-blog", { }] }) } - // highlight-end // user is an admin.. }); ``` - - + + -```tsx +```tsx {7,8,9,10,11,12,13,14,15,16,17,18} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; import UserRoles from "supertokens-node/recipe/userroles"; import { Error as STError } from "supertokens-node/recipe/session" async function updateBlog(awsEvent: SessionEvent) { - // highlight-start const roles = await awsEvent.session!.getClaimValue(UserRoles.UserRoleClaim); if (roles === undefined || !roles.includes("admin")) { @@ -651,17 +617,16 @@ async function updateBlog(awsEvent: SessionEvent) { }] }) } - // highlight-end // user is an admin.. }; exports.handler = verifySession(updateBlog); ``` - - + + -```tsx +```tsx {10,11,12,13,14,15,16,17,18,19,20,21} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from "supertokens-node/framework/koa"; @@ -671,7 +636,6 @@ import { Error as STError } from "supertokens-node/recipe/session" let router = new KoaRouter(); router.post("/update-blog", verifySession(), async (ctx: SessionContext, next) => { - // highlight-start const roles = await ctx.session!.getClaimValue(UserRoles.UserRoleClaim); if (roles === undefined || !roles.includes("admin")) { @@ -684,15 +648,14 @@ router.post("/update-blog", verifySession(), async (ctx: SessionContext, next) = }] }) } - // highlight-end // user is an admin.. }); ``` - - + + -```tsx +```tsx {14,15,16,17,18,19,20,21,22,23,24,25} import { inject, intercept } from "@loopback/core"; import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; @@ -706,7 +669,6 @@ class UpdateBlog { @intercept(verifySession()) @response(200) async handler() { - // highlight-start const roles = await ((this.ctx as any).session as Session.SessionContainer).getClaimValue(UserRoles.UserRoleClaim); if (roles === undefined || !roles.includes("admin")) { @@ -719,22 +681,21 @@ class UpdateBlog { }] }) } - // highlight-end // user is an admin.. } } ``` - - + + + - - + -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; @@ -750,7 +711,6 @@ export default async function updateBlog(req: SessionRequest, res: any) { res ) - // highlight-start const roles = await req.session!.getClaimValue(UserRoles.UserRoleClaim); if (roles === undefined || !roles.includes("admin")) { @@ -769,7 +729,6 @@ export default async function updateBlog(req: SessionRequest, res: any) { res ) } - // highlight-end // user is an admin.. } ``` @@ -782,7 +741,6 @@ import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import UserRoles from "supertokens-node/recipe/userroles"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; import { Error as STError } from "supertokens-node/recipe/session" @@ -813,13 +771,12 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {12,13,14,15,16,17,18,19,20,21,22,23} import { Controller, Post, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; import UserRoles from "supertokens-node/recipe/userroles"; import { Error as STError } from "supertokens-node/recipe/session" @@ -829,7 +786,6 @@ export class ExampleController { @Post('example') @UseGuards(new AuthGuard()) async postExample(@Session() session: SessionContainer): Promise { - // highlight-start const roles = await session.getClaimValue(UserRoles.UserRoleClaim); if (roles === undefined || !roles.includes("admin")) { @@ -842,20 +798,19 @@ export class ExampleController { }] }) } - // highlight-end // user is an admin.. return true; } } ``` - - - - - - - -```go + + + + + + + +```go {30,31,32,33,34,35,36,37,38,39,40,41,42,43} import ( "net/http" @@ -885,7 +840,6 @@ func corsMiddleware(next http.Handler) http.Handler { } func postExample(w http.ResponseWriter, r *http.Request) { - // highlight-start sessionContainer := session.GetSessionFromRequestContext(r.Context()) roles := sessionContainer.GetClaimValue(userrolesclaims.UserRoleClaim) @@ -900,7 +854,6 @@ func postExample(w http.ResponseWriter, r *http.Request) { // TODO: send 500 error to client } } - // highlight-end // User is an admin... } @@ -915,10 +868,10 @@ func contains(s []interface{}, e string) bool { } ``` - - + + -```go +```go {33,34,35,36,37,38,39,40,41,42,43,44,45,46} import ( "net/http" @@ -951,7 +904,6 @@ func verifySession(options *sessmodels.VerifySessionOptions) gin.HandlerFunc { // This is the API handler. func postExample(c *gin.Context) { - // highlight-start sessionContainer := session.GetSessionFromRequestContext(c.Request.Context()) roles := sessionContainer.GetClaimValue(userrolesclaims.UserRoleClaim) @@ -966,7 +918,6 @@ func postExample(c *gin.Context) { // TODO: send 500 error to client } } - // highlight-end // User is an admin... } @@ -981,10 +932,10 @@ func contains(s []interface{}, e string) bool { } ``` - - + + -```go +```go {20,21,22,23,24,25,26,27,28,29,30,31,32,33} import ( "net/http" @@ -1004,7 +955,6 @@ func main() { // This is the API handler. func postExample(w http.ResponseWriter, r *http.Request) { - // highlight-start sessionContainer := session.GetSessionFromRequestContext(r.Context()) roles := sessionContainer.GetClaimValue(userrolesclaims.UserRoleClaim) @@ -1019,7 +969,6 @@ func postExample(w http.ResponseWriter, r *http.Request) { // TODO: send 500 error to client } } - // highlight-end } func contains(s []interface{}, e string) bool { @@ -1032,10 +981,10 @@ func contains(s []interface{}, e string) bool { } ``` - - + + -```go +```go {21,22,23,24,25,26,27,28,29,30,31,32,33,34} import ( "net/http" @@ -1056,7 +1005,6 @@ func main() { // This is the API handler. func postExample(w http.ResponseWriter, r *http.Request) { - // highlight-start sessionContainer := session.GetSessionFromRequestContext(r.Context()) roles := sessionContainer.GetClaimValue(userrolesclaims.UserRoleClaim) @@ -1071,7 +1019,6 @@ func postExample(w http.ResponseWriter, r *http.Request) { // TODO: send 500 error to client } } - // highlight-end } func contains(s []interface{}, e string) bool { @@ -1084,15 +1031,15 @@ func contains(s []interface{}, e string) bool { } ``` - - - - + + + + - - + + -```python +```python {14,15,16,17,18} from fastapi import Depends from supertokens_python.recipe.session import SessionContainer @@ -1104,22 +1051,20 @@ from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.userroles import UserRoleClaim -@app.post("/update-blog") # type: ignore +@app.post("/update-blog") async def update_blog_api(session: SessionContainer = Depends(verify_session())): - # highlight-start roles = await session.get_claim_value(UserRoleClaim) if roles is None or "admin" not in roles: raise_invalid_claims_exception( "User is not an admin", [ClaimValidationError(UserRoleClaim.key, None)] ) - # highlight-end ``` - - + + -```python +```python {18,19,20,21,22} from flask import Flask, g from supertokens_python.recipe.session import SessionContainer @@ -1133,24 +1078,22 @@ from supertokens_python.recipe.userroles import UserRoleClaim app = Flask(__name__) -@app.route("/update-blog", methods=["POST"]) # type: ignore +@app.route("/update-blog", methods=["POST"]) @verify_session() def set_role_api(): - session: SessionContainer = g.supertokens # type: ignore - # highlight-start + session: SessionContainer = g.supertokens roles = session.sync_get_claim_value(UserRoleClaim) if roles is None or "admin" not in roles: raise_invalid_claims_exception( "User is not an admin", [ClaimValidationError(UserRoleClaim.key, None)] ) - # highlight-end ``` - - + + -```python +```python {17,18,19,20,21} from typing import cast from django.http import HttpRequest @@ -1166,22 +1109,20 @@ from supertokens_python.recipe.userroles import UserRoleClaim @verify_session() async def get_user_info_api(request: HttpRequest): - session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore - # highlight-start + session: SessionContainer = cast(SessionContainer, request.supertokens) roles = await session.get_claim_value(UserRoleClaim) if roles is None or "admin" not in roles: raise_invalid_claims_exception( "User is not an admin", [ClaimValidationError(UserRoleClaim.key, None)] ) - # highlight-end ``` - - + + - - + + --- @@ -1193,13 +1134,13 @@ On your frontend: 2. Use the roles / permissions claim validators to enforce certain roles and permissions. 3. If the user doesn't have the right roles, the system shows an error message indicating they don't have access. - + - + - + - + ```tsx import React from "react"; @@ -1225,8 +1166,7 @@ Above, you create a generic component called `AdminRoute` which enforces that it In the `AdminRoute` component, the `SessionAuth` wrapper ensures that the session exists. The `UserRoleClaim` validator is also added to the `` component which checks if the validators pass or not. If all validation passes, the `props.children` component renders. If the claim validation has failed, it displays the `AccessDeniedScreen` component instead of rendering the children. You can also pass a custom component to the `accessDeniedScreen` prop. -:::note -You can extend the `AdminRoute` component to check for other types of validators as well. This component can then reuse to protect all your app's components (In this case, you may want to rename this component to something more appropriate, like `ProtectedRoute`). +:::note[You can extend the `AdminRoute` component to check for other types of validators as well. This component can then reuse to protect all your app's components (In this case, you may want to rename this component to something more appropriate, like `ProtectedRoute`).] ::: @@ -1250,18 +1190,17 @@ function ProtectedComponent() { } ``` - + - + -```tsx +```tsx {7,8,9,10,11,12,13} import Session from "supertokens-web-js/recipe/session"; import { UserRoleClaim, /*PermissionClaim*/ } from "supertokens-web-js/recipe/userroles"; async function shouldLoadRoute(): Promise { if (await Session.doesSessionExist()) { - // highlight-start let validationErrors = await Session.validateClaims({ overrideGlobalClaimValidators: (globalValidators) => [...globalValidators, @@ -1269,7 +1208,6 @@ async function shouldLoadRoute(): Promise { /* PermissionClaim.validators.includes("modify") */ ] }); - // highlight-end if (validationErrors.length === 0) { // user is an admin @@ -1295,51 +1233,47 @@ async function shouldLoadRoute(): Promise { - We can also add a `PermissionClaim` validator to enforce a permission. - If you want to have more complex access control, you can get the roles list from the session as follows, and check the list yourself: -```tsx +```tsx {6,7,8,9,10} import Session from "supertokens-web-js/recipe/session"; import { UserRoleClaim } from "supertokens-web-js/recipe/userroles"; async function shouldLoadRoute(): Promise { if (await Session.doesSessionExist()) { - // highlight-start let roles = await Session.getClaimValue({claim: UserRoleClaim}); if (Array.isArray(roles) && roles.includes("admin")) { // User is an admin return true; } - // highlight-end } // either a session does not exist, or the user is not an admin return false } ``` - + - + - + - + - - + + - - + + -```tsx +```tsx {7,8,9,10,11,12,13} import Session from "supertokens-web-js/recipe/session"; import { UserRoleClaim, /*PermissionClaim*/ } from "supertokens-web-js/recipe/userroles"; async function shouldLoadRoute(): Promise { if (await Session.doesSessionExist()) { - // highlight-start let validationErrors = await Session.validateClaims({ overrideGlobalClaimValidators: (globalValidators) => [...globalValidators, @@ -1347,7 +1281,6 @@ async function shouldLoadRoute(): Promise { /* PermissionClaim.validators.includes("modify") */ ] }); - // highlight-end if (validationErrors.length === 0) { // user is an admin @@ -1368,7 +1301,7 @@ async function shouldLoadRoute(): Promise { } ``` - +
- We call the `validateClaims` function with the `UserRoleClaim` validator which makes sure that the user has an `admin` role. @@ -1377,37 +1310,32 @@ async function shouldLoadRoute(): Promise { If you want to have more complex access control, you can get the roles list from the session as follows, and check the list yourself: - +
-```tsx +```tsx {6,7,8,9,10} import Session from "supertokens-web-js/recipe/session"; import { UserRoleClaim } from "supertokens-web-js/recipe/userroles"; async function shouldLoadRoute(): Promise { if (await Session.doesSessionExist()) { - // highlight-start let roles = await Session.getClaimValue({claim: UserRoleClaim}); if (roles !== undefined && roles.includes("admin")) { // User is an admin return true; } - // highlight-end } // either a session does not exist, or the user is not an admin return false } ``` -
- +
+ -```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensUserRoles from "supertokens-web-js-script/recipe/userroles"; +```tsx {4,5,6,7,8,9,10} async function shouldLoadRoute(): Promise { if (await supertokensSession.doesSessionExist()) { - // highlight-start let validationErrors = await supertokensSession.validateClaims({ overrideGlobalClaimValidators: (globalValidators) => [...globalValidators, @@ -1415,7 +1343,6 @@ async function shouldLoadRoute(): Promise { /* supertokensUserRoles.PermissionClaim.validators.includes("modify") */ ] }); - // highlight-end if (validationErrors.length === 0) { // user is an admin @@ -1442,42 +1369,37 @@ async function shouldLoadRoute(): Promise { If you want to have more complex access control, you can get the roles list from the session as follows, and check the list yourself: -```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensUserRoles from "supertokens-web-js-script/recipe/userroles"; +```tsx {3,4,5,6,7} async function shouldLoadRoute(): Promise { if (await supertokensSession.doesSessionExist()) { - // highlight-start let roles = await supertokensSession.getClaimValue({claim: supertokensUserRoles.UserRoleClaim}); if (roles !== undefined && roles.includes("admin")) { // User is an admin return true; } - // highlight-end } // either a session does not exist, or the user is not an admin return false } ``` - - + +
-
+ - + - + - + -```tsx +```tsx {6,7,8,9,10,11,12} import SuperTokens from 'supertokens-react-native'; async function getRole() { if (await SuperTokens.doesSessionExist()) { - // highlight-start let roles: string[] = (await SuperTokens.getAccessTokenPayloadSecurely())["st-role"].v; if (roles.includes("admin")) { @@ -1485,14 +1407,13 @@ async function getRole() { } else { // TODO.. } - // highlight-end } } ``` - + - + ```kotlin import android.app.Application @@ -1512,9 +1433,9 @@ class MainApplication: Application() { } ``` - + - + ```swift import UIKit @@ -1533,9 +1454,9 @@ fileprivate class ViewController: UIViewController { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -1559,23 +1480,23 @@ Future checkIfUserIsAnAdmin() async { } ``` - + - + - + -
+ -
+ --- ## See also - - - - - - + + + + + + diff --git a/docs/additional-verification/user-roles/role-management-actions.mdx b/docs/additional-verification/user-roles/role-management-actions.mdx index 41893a04ec..7c4236d7cb 100644 --- a/docs/additional-verification/user-roles/role-management-actions.mdx +++ b/docs/additional-verification/user-roles/role-management-actions.mdx @@ -1,22 +1,10 @@ --- -sidebar_position: 4 title: Role management actions -hide_title: true -description: >- - Discover how to perform common actions that can be use to manage roles and - permissions. -page_type: guide -recipe: userroles -category: user-roles +description: Discover how to perform common actions that can be use to manage roles and permissions. +sidebar: + order: 4 --- - -import CreateRole from "./_blocks/create-role.mdx"; -import AssignRoleToUser from "./_blocks/assign-role-to-user.mdx"; -import AssignRoleToSession from "./_blocks/assign-role-to-session.mdx"; - -# Role management actions - ## Overview @@ -25,10 +13,8 @@ Actions like listing roles, creating permissions, or checking which roles you as ## Before you start -:::info - -You can also perform most of the actions outlined on this page from the user management dashboard. -To know more about how to use it check [the documentation](/docs/post-authentication/dashboard/user-management) +:::info[You can also perform most of the actions outlined on this page from the user management dashboard.] +To know more about how to use it check [the documentation](/post-authentication/dashboard/user-management) ::: @@ -36,89 +22,181 @@ To know more about how to use it check [the documentation](/docs/post-authentica ## Create a role - + + + +```tsx {4,5,6,7,8} +import UserRoles from "supertokens-node/recipe/userroles"; + +async function createRole() { + const response = await UserRoles.createNewRoleOrAddPermissions("user", ["read"]); + + if (response.createdNewRole === false) { + // The role already exists + } +} +``` + + + + +```go {6,7,8,9,10,11,12,13,14,15,16} +import ( + "github.com/supertokens/supertokens-golang/recipe/userroles" +) + +func createRole() { + resp, err := userroles.CreateNewRoleOrAddPermissions("user", []string{ + "read", + }, nil) + + if err != nil { + // TODO: Handle error + return + } + if resp.OK.CreatedNewRole == false { + // The role already exists + } +} +``` + + + + + + + +```python {4,5,6,7} +from supertokens_python.recipe.userroles.asyncio import create_new_role_or_add_permissions + +async def create_role(): + res = await create_new_role_or_add_permissions("user", ["read"]) + if not res.created_new_role: + # The role already existed + pass + +``` + + + + + +```python {4,5,6,7} +from supertokens_python.recipe.userroles.syncio import create_new_role_or_add_permissions + +def create_role(): + res = create_new_role_or_add_permissions("user", ["read"]) + if not res.created_new_role: + # The role already existed + pass + +``` + + + + + + + + +```bash +curl --location --request PUT '/recipe/role' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "role": "user", + "permissions": [ + "read" + ] +}' + +``` + + + + + +Create Role + + + + --- ## List roles - - + + -```tsx +```tsx {4} import UserRoles from "supertokens-node/recipe/userroles"; async function getAllRoles() { - // highlight-start const roles: string[] = (await UserRoles.getAllRoles()).roles; - // highlight-end } ``` - - + + -```go +```go {6,7,8,9,10,11} import ( "github.com/supertokens/supertokens-golang/recipe/userroles" ) func getAllRoles() { - // highlight-start response, err := userroles.GetAllRoles(nil) if err != nil { // TODO: Handle error return } _ = response.OK.Roles - // highlight-end } ``` - - + + - - + + -```python +```python {4} from supertokens_python.recipe.userroles.asyncio import get_all_roles async def create_role(): - # highlight-next-line _ = (await get_all_roles()).roles ``` - + - + -```python +```python {4} from supertokens_python.recipe.userroles.syncio import get_all_roles def create_role(): - # highlight-next-line _ = get_all_roles().roles ``` - + - + - + - + ```bash curl --location --request GET 'http://localhost:3567/recipe/roles' \ ---header 'api-key: ^{coreInfo.key}' +--header 'api-key: ' ``` - + - + --- @@ -126,34 +204,31 @@ curl --location --request GET 'http://localhost:3567/recipe/roles' \ You can delete any role you have created, if the role you are trying to delete does not exist then this has no effect. - - + + -```tsx +```tsx {4,5,6,7,8,9} import UserRoles from "supertokens-node/recipe/userroles"; async function deleteRole() { - // highlight-start // Delete the user role const response = await UserRoles.deleteRole("user"); if (!response.didRoleExist) { // There was no such role } - // highlight-end } ``` - - + + -```go +```go {6,7,8,9,10,11,12,13,14,15} import ( "github.com/supertokens/supertokens-golang/recipe/userroles" ) func deleteRole() { - // highlight-start // Delete the user role response, err := userroles.DeleteRole("user", nil) if err != nil { @@ -164,62 +239,57 @@ func deleteRole() { if response.OK.DidRoleExist == false { // There was no such role } - // highlight-end } ``` - - + + - - + + -```python +```python {4,5,6,7} from supertokens_python.recipe.userroles.asyncio import delete_role async def delete_role_function(): - # highlight-start res = await delete_role("user") if res.did_role_exist: # The role actually existed pass - # highlight-end ``` - - + + -```python +```python {4,5,6,7} from supertokens_python.recipe.userroles.syncio import delete_role def delete_role_function(): - # highlight-start res = delete_role("user") if res.did_role_exist: # The role actually existed pass - # highlight-end ``` - - + + - + - + ```bash curl --location --request POST 'http://localhost:3567/recipe/role/remove' \ ---header 'api-key: ^{coreInfo.key}' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "role": "admin" }' ``` - - + + --- @@ -228,78 +298,72 @@ curl --location --request POST 'http://localhost:3567/recipe/role/remove' \ The SDK function only adds missing permissions and does not have any effect on permissions that are already assigned to a role. - - + + -```tsx +```tsx {4,5} import UserRoles from "supertokens-node/recipe/userroles"; async function addPermissionForRole() { - // highlight-start // Add the "write" permission to the "user" role await UserRoles.createNewRoleOrAddPermissions("user", ["write"]); - // highlight-end } ``` - - + + -```go +```go {6,7,8,9,10,11} import ( "github.com/supertokens/supertokens-golang/recipe/userroles" ) func addPermissionForRole() { - // highlight-start // Add the write permission to the user role _, err := userroles.CreateNewRoleOrAddPermissions("user", []string{"write"}, nil) if err != nil { // TODO: Handle error return } - // highlight-end } ``` - - + + - - + + -```python +```python {5} from supertokens_python.recipe.userroles.asyncio import create_new_role_or_add_permissions async def add_permission_for_role(): - # highlight-next-line await create_new_role_or_add_permissions("user", ["write"]) ``` - + - + -```python +```python {5} from supertokens_python.recipe.userroles.syncio import create_new_role_or_add_permissions def add_permission_for_role(): - # highlight-next-line create_new_role_or_add_permissions("user", ["write"]) ``` - - + + - + - + -:::info Multi Tenancy +:::info[Multi Tenancy] In a multi-tenant setup, roles, and permissions share across all tenants. This means that you can create a role and add permissions to it once, and reuse that role across any tenant in your app. @@ -311,34 +375,31 @@ In a multi-tenant setup, roles, and permissions share across all tenants. This m To remove one or more permissions from a role, first create the role before you use this function. - - + + -```tsx +```tsx {4,5,6,7,8,9} import UserRoles from "supertokens-node/recipe/userroles"; async function removePermissionFromRole() { - // highlight-start // Remove the "write" permission to the "user" role const response = await UserRoles.removePermissionsFromRole("user", ["write"]); if (response.status === "UNKNOWN_ROLE_ERROR") { // No such role exists } - // highlight-end } ``` - - + + -```go +```go {6,7,8,9,10,11,12,13,14,15} import ( "github.com/supertokens/supertokens-golang/recipe/userroles" ) func removePermissionFromRole() { - // highlight-start // Remove the write permission to the user role response, err := userroles.RemovePermissionsFromRole("user", []string{"write"}, nil) if err != nil { @@ -349,53 +410,48 @@ func removePermissionFromRole() { if response.UnknownRoleError != nil { // No such role exists } - // highlight-end } ``` - - + + - - + + -```python +```python {5,6,7,8} from supertokens_python.recipe.userroles.asyncio import remove_permissions_from_role from supertokens_python.recipe.userroles.interfaces import UnknownRoleError async def remove_permission_from_role_func(): - # highlight-start res = await remove_permissions_from_role("user", ["write"]) if isinstance(res, UnknownRoleError): # No such role exists pass - # highlight-end ``` - - + + -```python +```python {5,6,7,8} from supertokens_python.recipe.userroles.syncio import remove_permissions_from_role from supertokens_python.recipe.userroles.interfaces import UnknownRoleError def remove_permission_from_role_func(): - # highlight-start res = remove_permissions_from_role("user", ["write"]) if isinstance(res, UnknownRoleError): # No such role exists pass - # highlight-end ``` - - + + - + - + --- @@ -403,14 +459,13 @@ def remove_permission_from_role_func(): Get a list of all permissions assigned to a role. - - + + -```tsx +```tsx {4,5,6,7,8,9,10,11} import UserRoles from "supertokens-node/recipe/userroles"; async function getPermissionsForRole() { - // highlight-start const response = await UserRoles.getPermissionsForRole("user"); if (response.status === "UNKNOWN_ROLE_ERROR") { @@ -419,20 +474,18 @@ async function getPermissionsForRole() { } const permissions: string[] = response.permissions; - // highlight-end } ``` - - + + -```go +```go {6,7,8,9,10,11,12,13,14,15,16,17,18} import ( "github.com/supertokens/supertokens-golang/recipe/userroles" ) func getPermissionsForRole() { - // highlight-start // const response = await UserRoles.getPermissionsForRole("user"); response, err := userroles.GetPermissionsForRole("user", nil) if err != nil { @@ -446,56 +499,51 @@ func getPermissionsForRole() { } _ = response.OK.Permissions - // highlight-end } ``` - - + + - - + + -```python +```python {5,6,7,8,9,10} from supertokens_python.recipe.userroles.asyncio import get_permissions_for_role from supertokens_python.recipe.userroles.interfaces import UnknownRoleError async def remove_permission_from_role(): - # highlight-start res = await get_permissions_for_role("user") if isinstance(res, UnknownRoleError): # No such role exists return _ = res.permissions - # highlight-end ``` - - + + -```python +```python {5,6,7,8,9,10} from supertokens_python.recipe.userroles.syncio import get_permissions_for_role from supertokens_python.recipe.userroles.interfaces import UnknownRoleError def remove_permission_from_role(): - # highlight-start res = get_permissions_for_role("user") if isinstance(res, UnknownRoleError): # No such role exists return _ = res.permissions - # highlight-end ``` - + - + - + - + --- @@ -503,93 +551,273 @@ def remove_permission_from_role(): Get a list of all the roles assigned a specific permission. - - + + -```tsx +```tsx {4,5} import UserRoles from "supertokens-node/recipe/userroles"; async function getRolesWithPermission() { - // highlight-start const response = await UserRoles.getRolesThatHavePermission("write"); const roles: string[] = response.roles; - // highlight-end } ``` - - + + -```go +```go {6,7,8,9,10,11} import ( "github.com/supertokens/supertokens-golang/recipe/userroles" ) func getRolesWithPermission() { - // highlight-start response, err := userroles.GetRolesThatHavePermission("write", nil) if err != nil { // TODO: Handle error return } _ = response.OK.Roles - // highlight-end } ``` - - + + - - + + -```python +```python {5,6} from supertokens_python.recipe.userroles.asyncio import get_roles_that_have_permission async def get_roles_with_permission(): - # highlight-start res = await get_roles_that_have_permission("write") _ = res.roles - # highlight-end ``` - - + + -```python +```python {5,6} from supertokens_python.recipe.userroles.syncio import get_roles_that_have_permission def get_roles_with_permission(): - # highlight-start res = get_roles_that_have_permission("write") _ = res.roles - # highlight-end ``` - - + + - + - + --- ## Assign roles to a user - + + + +```tsx {4,5,6,7,8,9,10,11,12,13} +import UserRoles from "supertokens-node/recipe/userroles"; + +async function addRoleToUser(userId: string) { + const response = await UserRoles.addRoleToUser("public", userId, "user"); + + if (response.status === "UNKNOWN_ROLE_ERROR") { + // No such role exists + return; + } + + if (response.didUserAlreadyHaveRole === true) { + // The user already had the role + } +} +``` + + + + +```go {6,7,8,9,10,11,12,13,14,15,16,17,18,19} +import ( + "github.com/supertokens/supertokens-golang/recipe/userroles" +) + +func addRoleToUser(userId string) { + response, err := userroles.AddRoleToUser("public", userId, "user", nil) + if err != nil { + // TODO: Handle error + return + } + + if response.UnknownRoleError != nil { + // No such role exists + return + } + + if response.OK.DidUserAlreadyHaveRole { + // The user already had the role + } +} +``` + + + + + + + +```python {6,7,8,9,10,11,12,13,14} +from supertokens_python.recipe.userroles.asyncio import add_role_to_user +from supertokens_python.recipe.userroles.interfaces import UnknownRoleError + + +async def add_role_to_user_func(user_id: str): + role = "user" + res = await add_role_to_user("public", user_id, role) + if isinstance(res, UnknownRoleError): + # No such role exists + return + + if res.did_user_already_have_role: + # User already had this role + pass +``` + + + + +```python {6,7,8,9,10,11,12,13,14} +from supertokens_python.recipe.userroles.syncio import add_role_to_user +from supertokens_python.recipe.userroles.interfaces import UnknownRoleError + + +def add_role_to_user_func(user_id: str): + role = "user" + res = add_role_to_user("public", user_id, role) + if isinstance(res, UnknownRoleError): + # No such role exists + return + + if res.did_user_already_have_role: + # User already had this role + pass + +``` + + + + + + + +```bash +curl --location --request PUT 'http://localhost:3567/recipe/user/role' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "userId": "fa7a0841-b533-4478-95533-0fde890c3483", + "role": "user" +}' +``` + + + + ## Assign roles to a session - + + +```tsx +import {UserRoleClaim, PermissionClaim} from "supertokens-node/recipe/userroles"; +import {SessionContainer} from "supertokens-node/recipe/session" + +async function addRolesAndPermissionsToSession(session: SessionContainer) { + // we add the user's roles to the user's session + await session.fetchAndSetClaim(UserRoleClaim) -:::info Multi Tenancy + // we add the permissions of a user to the user's session + await session.fetchAndSetClaim(PermissionClaim) +} +``` + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" + "github.com/supertokens/supertokens-golang/recipe/userroles/userrolesclaims" +) + +func addRolesAndPermissionsToSession(session sessmodels.SessionContainer) error { + // we add the user's roles to the user's session + err := session.FetchAndSetClaim(userrolesclaims.UserRoleClaim) + if err != nil { + return err + } + + // we add the user's permissions to the user's session + err = session.FetchAndSetClaim(userrolesclaims.PermissionClaim) + if err != nil { + return err + } + + return nil +} +``` + + + + + + + +```python +from supertokens_python.recipe.session import SessionContainer +from supertokens_python.recipe.userroles import UserRoleClaim, PermissionClaim + + +async def add_roles_and_permissions_to_session(session: SessionContainer): + # we add the user's roles to the user's session + await session.fetch_and_set_claim(UserRoleClaim) + + # we add the user's permissions to the user's session + await session.fetch_and_set_claim(PermissionClaim) +``` + + + + +```python +from supertokens_python.recipe.session import SessionContainer +from supertokens_python.recipe.userroles import UserRoleClaim, PermissionClaim + + +def add_roles_and_permissions_to_session(session: SessionContainer): + # we add the user's roles to the user's session + session.sync_fetch_and_set_claim(UserRoleClaim) + + # we add the user's permissions to the user's session + session.sync_fetch_and_set_claim(PermissionClaim) +``` + + + + + + + +:::info[Multi Tenancy] Whilst roles and permissions share across apps, the association of roles to users is on a per-tenant level. If using SDK functions to add a role to a user, you can also pass in a `tenantId` to the function. This tells SuperTokens to add the role for that user for that tenant. In the code examples above, the `"public"` `tenantId` appears, which is the default `tenantId` for users. You can fetch the user's `tenantId` from their current session, or from their user object (which you can fetch using their `userId`). @@ -603,8 +831,8 @@ Note that if you associate a role to a user ID for a tenant, and that user ID do You can remove roles from a user. The system removes the role you provide only if the user previously had that role. - - + + ```tsx import UserRoles from "supertokens-node/recipe/userroles"; @@ -628,8 +856,8 @@ async function removeRoleFromUserAndTheirSession(session: SessionContainer) { } ``` - - + + ```go import ( @@ -660,11 +888,11 @@ func removeRoleFromUserAndTheirSession(session sessmodels.SessionContainer) { } ``` - - + + - - + + ```python from supertokens_python.recipe.userroles.asyncio import remove_user_role @@ -687,8 +915,8 @@ async def remove_role_from_user_and_their_session(session: SessionContainer): await session.fetch_and_set_claim(PermissionClaim) ``` - - + + ```python from supertokens_python.recipe.userroles.syncio import remove_user_role @@ -711,16 +939,16 @@ def remove_role_from_user_and_their_session(session: SessionContainer): session.sync_fetch_and_set_claim(PermissionClaim) ``` - - + + - + - + ```bash curl --location --request POST 'http://localhost:3567/recipe/user/role/remove' \ ---header 'api-key: ^{coreInfo.key}' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "userId": "fa7a0841-b533-4478-95533-0fde890c3483", @@ -728,11 +956,11 @@ curl --location --request POST 'http://localhost:3567/recipe/user/role/remove' \ }' ``` - + - + -:::info Multi Tenancy +:::info[Multi Tenancy] When using the multi-tenancy feature, in the previous snippets, only the user's role for the tenant they used to log in gets removed. That's the one stored in the session. @@ -743,83 +971,77 @@ You can pass in another tenant ID if you like, or call the function above for al ## List the roles of a user - - + + -```tsx +```tsx {4,5} import UserRoles from "supertokens-node/recipe/userroles"; async function getRolesForUser(userId: string) { - // highlight-start const response = await UserRoles.getRolesForUser("public", userId); const roles: string[] = response.roles; - // highlight-end } ``` - - + + -```go +```go {6,7,8,9,10,11} import ( "github.com/supertokens/supertokens-golang/recipe/userroles" ) func getRolesForUser(userId string) { - // highlight-start response, err := userroles.GetRolesForUser("public", userId, nil) if err != nil { // TODO: Handle error return } _ = response.OK.Roles - // highlight-end } ``` - - + + - - + + -```python +```python {4} from supertokens_python.recipe.userroles.asyncio import get_roles_for_user async def get_roles_for_user_func(user_id: str): - # highlight-next-line _ = (await get_roles_for_user("public", user_id)).roles ``` - - + + -```python +```python {4} from supertokens_python.recipe.userroles.syncio import get_roles_for_user def get_roles_for_user_func(user_id: str): - # highlight-next-line _ = get_roles_for_user("public", user_id).roles ``` - - + + - + - + ```bash curl --location --request GET 'http://localhost:3567/recipe/user/roles?userId=fa7a0841-b533-4478-95533-0fde890c3483' \ ---header 'api-key: ^{coreInfo.key}' +--header 'api-key: ' ``` - + - + -:::info Multi Tenancy +:::info[Multi Tenancy] In the code examples above, the `"public"` `tenantId` appears, which is the default `tenantId` for users. You can fetch the user's `tenantId` from their current session, or from their user object (which you can fetch using their `userId`). ::: @@ -828,14 +1050,13 @@ In the code examples above, the `"public"` `tenantId` appears, which is the defa ## List the users of a role - - + + -```tsx +```tsx {4,5,6,7,8,9,10,11} import UserRoles from "supertokens-node/recipe/userroles"; async function getUsersThatHaveRole(role: string) { - // highlight-start const response = await UserRoles.getUsersThatHaveRole("public", role); if (response.status === "UNKNOWN_ROLE_ERROR") { @@ -844,20 +1065,18 @@ async function getUsersThatHaveRole(role: string) { } const users: string[] = response.users; - // highlight-end } ``` - - + + -```go +```go {6,7,8,9,10,11,12,13,14,15,16,17} import ( "github.com/supertokens/supertokens-golang/recipe/userroles" ) func getUsersThatHaveRole(role string) { - // highlight-start response, err := userroles.GetUsersThatHaveRole("public", role, nil) if err != nil { // TODO: Handle error @@ -870,69 +1089,64 @@ func getUsersThatHaveRole(role string) { } _ = response.OK.Users - // highlight-end } ``` - - + + - - + + -```python +```python {5,6,7,8,9,10} from supertokens_python.recipe.userroles.asyncio import get_users_that_have_role from supertokens_python.recipe.userroles.interfaces import UnknownRoleError async def get_users_that_have_role_func(role: str): - # highlight-start res = await get_users_that_have_role("public", role) if isinstance(res, UnknownRoleError): # No such role exists return _ = res.users - # highlight-end ``` - + - + -```python +```python {5,6,7,8,9,10} from supertokens_python.recipe.userroles.syncio import get_users_that_have_role from supertokens_python.recipe.userroles.interfaces import UnknownRoleError def get_users_that_have_role_func(role: str): - # highlight-start res = get_users_that_have_role("public", role) if isinstance(res, UnknownRoleError): # No such role exists return _ = res.users - # highlight-end ``` - - + + - + - + ```bash curl --location --request GET 'http://localhost:3567/recipe/role/users?role=user' \ ---header 'api-key: ^{coreInfo.key}' +--header 'api-key: ' ``` - + - + -:::info Multi Tenancy +:::info[Multi Tenancy] In the code examples above, the `"public"` `tenantId` appears, which is the default `tenantId` for users. This returns the list of users that have that role in the `"public"` tenant. You can also pass in a different tenant ID, or call the function in a loop with all the tenants that exist in your app. @@ -943,8 +1157,8 @@ You can also pass in a different tenant ID, or call the function in a loop with ## See also - - - - - + + + + + diff --git a/docs/authentication/_category_.json b/docs/authentication/_category_.json deleted file mode 100644 index 54ad7957a5..0000000000 --- a/docs/authentication/_category_.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "label": "Authentication", - "collapsible": true, - "collapsed": true, - "customProps": { - "isMainCategory": true - }, - "position": 3 -} diff --git a/docs/authentication/ai-authentication.mdx b/docs/authentication/ai-authentication.mdx index 3df644ce5e..bc66cd4eae 100644 --- a/docs/authentication/ai-authentication.mdx +++ b/docs/authentication/ai-authentication.mdx @@ -1,18 +1,11 @@ --- title: MCP Authentication -hide_title: true -sidebar_position: 8 -pagination_next: null -pagination_prev: null -description: >- - Authenticate MCP server actions using the SuperTokens MCP plugin. -category: authentication -recipe: oauth2 -page_type: tutorial +description: Authenticate MCP server actions using the SuperTokens MCP plugin. +sidebar: + badge: Beta + order: 8 --- -# Authenticate MCP Servers - ## Overview This guide explains how to authenticate Model Context Protocol (MCP) Servers using **SuperTokens**. @@ -21,7 +14,9 @@ It is a new way to abstract common functionalities into a reusable package. ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: The [MCP authentication flow](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) complies with the OAuth2 specifications. This means that you will have to use the `OAuth2` recipe in your configuration which is a paid feature. @@ -36,17 +31,17 @@ Keep in mind that the feature is currently in beta and might be subject to break Add the `supertokens-mcp-plugin` package to your project. - - ```bash + + ```bash npm i -s supertokens-mcp-plugin ``` - - ```bash + + ```bash yarn add supertokens-mcp-plugin ``` - + ```bash pnpm add supertokens-auth-react supertokens-web-js ``` @@ -60,7 +55,7 @@ Use the `SuperTokensMcpServer` class when in your implementation. The class extends the base MCP server exposed by the `@modelcontextprotocol/sdk`, and adds custom authentication logic on top of it. You can authorize the client requests in two different ways. -By using the standard [claim validators](/docs/additional-verification/session-verification/claim-validation). +By using the standard [claim validators](/additional-verification/session-verification/claim-validation). Or you can write your own custom validation logic in the `validateTokenPayload` function. The authentication state can be accessed inside a tool call through the second function argument, `extra.authInfo`. @@ -150,5 +145,3 @@ supertokens.init({ }, }); ``` - - diff --git a/docs/authentication/email-password/_category_.json b/docs/authentication/email-password/_category_.json deleted file mode 100644 index ac15286c75..0000000000 --- a/docs/authentication/email-password/_category_.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "label": "Email Password", - "position": 1.2, - "customProps": { - "childrenOrder": [ - "introduction", - "callbacks", - "password-hashing", - "sing-in-form", - "sign-up-form", - "password-managers", - "password-reset" - ] - } -} diff --git a/docs/authentication/email-password/customize-the-sign-in-form.mdx b/docs/authentication/email-password/customize-the-sign-in-form.mdx index 9fa748ce28..b918c65adb 100644 --- a/docs/authentication/email-password/customize-the-sign-in-form.mdx +++ b/docs/authentication/email-password/customize-the-sign-in-form.mdx @@ -1,19 +1,10 @@ --- title: Customize the Sign In form -hide_title: true -sidebar_position: 2 -description: >- - Customize form fields in the sign in component by modifying labels, - placeholders, default values, and error messages. -page_type: guide -recipe: emailpassword -category: email-password +description: Customize form fields in the sign in component by modifying labels, placeholders, default values, and error messages. +sidebar: + order: 2 --- - -# Customize form fields - - ## Before you start The following instructions are only relevant if you are using the pre-built UI components. @@ -23,11 +14,11 @@ If you have created your own authentication UI, you can skip this guide. To change the labels and placeholders of the fields update the `formFields` property, in the recipe configuration. - + - + -```tsx preview="/img/emailpassword/signin-with-default-values.png" +```tsx {15,16,17,18,19} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import Session from "supertokens-auth-react/recipe/session"; @@ -42,13 +33,11 @@ SuperTokens.init({ EmailPassword.init({ signInAndUpFeature: { signInForm: { - // highlight-start formFields: [{ id: "email", label: "customFieldName", placeholder: "Custom value" }] - // highlight-end } } }), @@ -56,15 +45,12 @@ SuperTokens.init({ ] }); ``` - + - + -```tsx preview="/img/emailpassword/signin-with-default-values.png" previewAlt="Prebuilt form UI with custom labels and placeholder" +```tsx {13,14,15,16,17} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -76,13 +62,11 @@ supertokensUIInit({ supertokensUIEmailPassword.init({ signInAndUpFeature: { signInForm: { - // highlight-start formFields: [{ id: "email", label: "customFieldName", placeholder: "Custom value" }] - // highlight-end } } }), @@ -90,8 +74,8 @@ supertokensUIInit({ ] }); ``` - - + + --- @@ -100,10 +84,10 @@ supertokensUIInit({ Add a `getDefaultValue` option in the `formFields` configuration to pre-fill the inputs. Keep in mind that the function needs to return a string. - - + + -```tsx preview="/img/emailpassword/signin-with-default-values.png" previewAlt="Pre-built sign in form UI with default values for fields" +```tsx {18} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import Session from "supertokens-auth-react/recipe/session"; @@ -121,9 +105,7 @@ SuperTokens.init({ formFields: [{ id: "email", label: "Your Email", - // highlight-start getDefaultValue: () => "john.doe@gmail.com" - // highlight-end }] } } @@ -132,15 +114,12 @@ SuperTokens.init({ ] }); ``` - + - + -```tsx preview="/img/emailpassword/signin-with-default-values.png" previewAlt="Pre-built sign in form UI with default values for fields" +```tsx {16} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -155,9 +134,7 @@ supertokensUIInit({ formFields: [{ id: "email", label: "Your Email", - // highlight-start getDefaultValue: () => "john.doe@gmail.com" - // highlight-end }] } } @@ -166,8 +143,8 @@ supertokensUIInit({ ] }); ``` - - + + --- @@ -176,10 +153,10 @@ supertokensUIInit({ When you try to submit the login form without filling in the required fields, the UI, by default, shows an error stating that the `Field is not optional`. To customize this message set the `nonOptionalErrorMsg` property to a custom string. - - + + -```tsx preview="/img/emailpassword/signin-with-custom-error-msg.png" previewAlt="Pre-built sign in UI with custom error message" +```tsx {19} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import Session from "supertokens-auth-react/recipe/session"; @@ -198,9 +175,7 @@ SuperTokens.init({ id: "email", label: "Your Email", placeholder: "Email", - // highlight-start nonOptionalErrorMsg: "Please add your email" - // highlight-end }] } } @@ -209,15 +184,12 @@ SuperTokens.init({ ] }); ``` - + - + -```tsx preview="/img/emailpassword/signin-with-custom-error-msg.png" previewAlt="Pre-built sign in UI with custom error message" +```tsx {17} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -233,9 +205,7 @@ supertokensUIInit({ id: "email", label: "Your Email", placeholder: "Email", - // highlight-start nonOptionalErrorMsg: "Please add your email" - // highlight-end }] } } @@ -244,8 +214,8 @@ supertokensUIInit({ ] }); ``` - - + + --- @@ -254,17 +224,17 @@ supertokensUIInit({ To add custom validation logic to the sign in form, update the sign up form configuration. The `email` and `password` fields validation synchronizes between the two forms. -Check the [sign up form instructions](/docs/authentication/email-password/customize-the-sign-up-form#change-the-default-email-and-password-validators) for more details. +Check the [sign up form instructions](/authentication/email-password/customize-the-sign-up-form#change-the-default-email-and-password-validators) for more details. --- ## See also - - - - - - - + + + + + + + diff --git a/docs/authentication/email-password/customize-the-sign-up-form.mdx b/docs/authentication/email-password/customize-the-sign-up-form.mdx index 5be0eadeba..78f226aac7 100644 --- a/docs/authentication/email-password/customize-the-sign-up-form.mdx +++ b/docs/authentication/email-password/customize-the-sign-up-form.mdx @@ -1,23 +1,16 @@ --- title: Customize the Sign Up Form -hide_title: true -sidebar_position: 3 -toc_max_heading_level: 4 description: Customize the sign up form by adding new fields or modifying existing ones. -page_type: guide -recipe: emailpassword -category: email-password +sidebar: + order: 3 --- -# Customize the sign up form - - ## Before you start The next instructions assume that you have a working application that uses **SuperTokens** for authentication. -If not, please refer to the [quickstart guide](/docs/quickstart/frontend-setup) and then return here. +If not, please refer to the [quickstart guide](/quickstart/frontend-setup) and then return here. - + ## Add extra fields @@ -27,18 +20,18 @@ Then, when the sing up payload arrives on the backend, you should add a way to p ### 1. Add the new fields to the UI - + You first need to add the new fields to your sign up interface. Given that you are using a custom implementation, the steps vary based on your code. After you have updated the form, ensure that the submit action follows the next example. - - + + - - + + ```tsx import { signUp } from "supertokens-web-js/recipe/emailpassword"; @@ -66,11 +59,10 @@ async function signUpClicked(email: string, password: string, name: string, age: } ``` - - + + ```tsx -import supertokensEmailPassword from "supertokens-web-js-script/recipe/emailpassword"; async function signUpClicked(email: string, password: string, name: string, age: number, country: string) { let response = await supertokensEmailPassword.signUp({ formFields: [{ @@ -94,18 +86,16 @@ async function signUpClicked(email: string, password: string, name: string, age: } ``` - - - - + + - + - + ```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signup' +curl --location --request POST '/auth/signup' --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "formFields": [{ @@ -127,19 +117,19 @@ curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signu }' ``` - + - + - + - + - - + + -```tsx preview="/img/emailpassword/signup-with-name-and-age.png" previewAlt="Prebuilt form UI with extra custom fields" +```tsx {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import Session from "supertokens-auth-react/recipe/session"; @@ -153,7 +143,6 @@ SuperTokens.init({ recipeList: [ EmailPassword.init({ signInAndUpFeature: { - // highlight-start signUpForm: { formFields: [{ id: "name", @@ -170,22 +159,18 @@ SuperTokens.init({ optional: true }] } - // highlight-end } }), Session.init() ] }); ``` - + - + -```tsx preview="/img/emailpassword/signup-with-name-and-age.png" previewAlt="Prebuilt form UI with extra custom fields" +```tsx {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -196,7 +181,6 @@ supertokensUIInit({ recipeList: [ supertokensUIEmailPassword.init({ signInAndUpFeature: { - // highlight-start signUpForm: { formFields: [{ id: "name", @@ -213,15 +197,14 @@ supertokensUIInit({ optional: true }] } - // highlight-end } }), supertokensUISession.init() ] }); ``` - - + + #### Create custom components @@ -229,18 +212,18 @@ supertokensUIInit({ By default, the new fields use `input` elements. To enable more complex fields you can create your own custom components. -:::important -You may need to disable the Shadow DOM if you're integrating with a different component library that requires you to import its own CSS. For instance, some component libraries, such as [react-international-phone](https://github.com/goveo/react-international-phone), might expect you to include their CSS alongside their components. For more information, refer to [Disable use of shadow DOM](/docs/references/frontend-sdks/prebuilt-ui/shadow-dom). +:::note +You may need to disable the Shadow DOM if you're integrating with a different component library that requires you to import its own CSS. For instance, some component libraries, such as [react-international-phone](https://github.com/goveo/react-international-phone), might expect you to include their CSS alongside their components. For more information, refer to [Disable use of shadow DOM](/references/frontend-sdks/prebuilt-ui/shadow-dom). ::: Set the `inputComponent` property for each field that you want to customize. - - + + -```tsx preview="/img/emailpassword/signup-with-custom-components.png" previewAlt="Pre-built form UI with custom components" +```tsx {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword" import Session from "supertokens-auth-react/recipe/session"; @@ -254,7 +237,6 @@ SuperTokens.init({ recipeList: [ EmailPassword.init({ signInAndUpFeature: { - // highlight-start signUpForm: { formFields: [{ id: "select-dropdown", @@ -314,35 +296,33 @@ SuperTokens.init({ ), }] } - // highlight-end } }), Session.init() ] }); ``` - + - + -:::caution -This is not applicable for non React apps. You have to create your own custom UI instead. +:::warning[This is not applicable for non React apps. You have to create your own custom UI instead.] ::: - - + + - + ### 2. Include the extra fields in the backend configuration Change the **Backend SDK** initialization call to ensure that the system processes the new fields when a new user registers. - - + + -```tsx +```tsx {17,18,19,20,21,22,23,24} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -359,7 +339,6 @@ SuperTokens.init({ recipeList: [ EmailPassword.init({ signUpFeature: { - // highlight-start formFields: [{ id: "name" }, { @@ -368,7 +347,6 @@ SuperTokens.init({ id: "country", optional: true }] - // highlight-end } }), Session.init({ /* ... */ }) @@ -376,10 +354,10 @@ SuperTokens.init({ }); ``` - - + + -```go +```go {13,14,15,16,17,18,19,20,21,22,23,24} import ( "github.com/supertokens/supertokens-golang/recipe/emailpassword" "github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels" @@ -392,7 +370,6 @@ func main() { RecipeList: []supertokens.Recipe{ emailpassword.Init(&epmodels.TypeInput{ SignUpFeature: &epmodels.TypeInputSignUp{ - //highlight-start FormFields: []epmodels.TypeInputFormField{ { ID: "name", @@ -405,7 +382,6 @@ func main() { Optional: &countryOptional, }, }, - //highlight-end }, }), }, @@ -413,10 +389,10 @@ func main() { } ``` - - + + -```python +```python {11,12,13} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailpassword, session from supertokens_python.recipe.emailpassword import InputFormField @@ -424,33 +400,31 @@ from supertokens_python.recipe.emailpassword import InputFormField init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( - # highlight-start sign_up_feature=emailpassword.InputSignUpFeature( form_fields=[InputFormField(id='name'), InputFormField(id='age'), InputFormField(id='country', optional=True)] ) - # highlight-end ), session.init() ] ) ``` - - + + ### 3. Save the values after a successful sign up Use the `signUpPOST` API function to process the field values and persist them. -:::caution -**SuperTokens** does not store custom form fields. You can either save them in your database or use the [User Metadata feature ](/docs/post-authentication/user-management/user-metadata). +:::warning +**SuperTokens** does not store custom form fields. You can either save them in your database or use the [User Metadata feature ](/post-authentication/user-management/user-metadata). ::: - - + + ```tsx import SuperTokens from "supertokens-node"; @@ -498,8 +472,8 @@ SuperTokens.init({ ] }); ``` - - + + ```go import ( @@ -541,10 +515,10 @@ func main() { }) } ``` - - + + -```python +```python {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,51,52,53} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailpassword, session from supertokens_python.recipe.emailpassword.interfaces import ( @@ -557,7 +531,6 @@ from typing import List, Dict, Any, Union from supertokens_python.recipe.session.interfaces import SessionContainer -# highlight-start def override_email_password_apis(original_implementation: APIInterface): original_sign_up_post = original_implementation.sign_up_post @@ -590,49 +563,45 @@ def override_email_password_apis(original_implementation: APIInterface): return original_implementation -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( - # highlight-start override=emailpassword.InputOverrideConfig( apis=override_email_password_apis ) - # highlight-end ), session.init(), ], ) ``` - - + + --- ## Customize each form field - + -:::caution Not applicable +:::warning[Not applicable] This section is not relevant for custom UI, as you create your own UI and already have control over the form fields. ::: - + - + ### Modify labels and placeholders To change the labels and placeholders of the fields, update the `formFields` property, in the recipe configuration. - - + + -```tsx preview="/img/emailpassword/custom-field-name-signup-ep.png" previewAlt="Prebuilt form UI with custom labels and placeholder" +```tsx {15,16,17,18,19,20} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword" import Session from "supertokens-auth-react/recipe/session"; @@ -647,29 +616,24 @@ SuperTokens.init({ EmailPassword.init({ signInAndUpFeature: { signUpForm: { - // highlight-start formFields: [{ id: "email", label: "customFieldName", placeholder: "Custom value" }] } - // highlight-end } }), Session.init() ] }); ``` - + - + -```tsx preview="/img/emailpassword/custom-field-name-signup-ep.png" previewAlt="Prebuilt form UI with custom labels and placeholder" +```tsx {13,14,15,16,17,18} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword" -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -681,22 +645,20 @@ supertokensUIInit({ supertokensUIEmailPassword.init({ signInAndUpFeature: { signUpForm: { - // highlight-start formFields: [{ id: "email", label: "customFieldName", placeholder: "Custom value" }] } - // highlight-end } }), supertokensUISession.init() ] }); ``` - - + + ### Set default values @@ -704,11 +666,11 @@ supertokensUIInit({ Add a `getDefaultValue` option to the `formFields` configuration to set default values. Keep in mind that the function needs to return a string. - + - + -```tsx preview="/img/emailpassword/signup-with-default-values.png" previewAlt="Prebuilt form UI with default values for fields" +```tsx {18,22} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword" import Session from "supertokens-auth-react/recipe/session"; @@ -726,15 +688,11 @@ SuperTokens.init({ formFields: [{ id: "email", label: "Your Email", - // highlight-start getDefaultValue: () => "john.doe@gmail.com" - // highlight-end }, { id: "name", label: "Full name", - // highlight-start getDefaultValue: () => "John Doe", - // highlight-end }] } } @@ -743,15 +701,12 @@ SuperTokens.init({ ] }); ``` - + - + -```tsx preview="/img/emailpassword/signup-with-default-values.png" previewAlt="Prebuilt form UI with default values for fields" +```tsx {16,20} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword" -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -766,15 +721,11 @@ supertokensUIInit({ formFields: [{ id: "email", label: "Your Email", - // highlight-start getDefaultValue: () => "john.doe@gmail.com" - // highlight-end }, { id: "name", label: "Full name", - // highlight-start getDefaultValue: () => "John Doe", - // highlight-end }] } } @@ -783,9 +734,9 @@ supertokensUIInit({ ] }); ``` - + - + ### Change the optional error message @@ -793,10 +744,10 @@ supertokensUIInit({ When you try to submit the login form without filling in the required fields, the UI, by default, shows an error stating that the `Field is not optional`. To customize this message set the `nonOptionalErrorMsg` property to a custom string. - - + + -```tsx preview="/img/emailpassword/signup-with-custom-error-msg.png" previewAlt="Prebuilt form UI with custom error message" +```tsx {19,24} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword" import Session from "supertokens-auth-react/recipe/session"; @@ -815,16 +766,12 @@ SuperTokens.init({ id: "email", label: "Your Email", placeholder: "Email", - // highlight-start nonOptionalErrorMsg: "Please add your email" - // highlight-end }, { id: "name", label: "Full name", placeholder: "Name", - // highlight-start nonOptionalErrorMsg: "Full name is required", - // highlight-end }] } } @@ -833,15 +780,12 @@ SuperTokens.init({ ] }); ``` - + - + -```tsx preview="/img/emailpassword/signup-with-custom-error-msg.png" previewAlt="Prebuilt form UI with custom error message" +```tsx {17,22} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword" -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -857,16 +801,12 @@ supertokensUIInit({ id: "email", label: "Your Email", placeholder: "Email", - // highlight-start nonOptionalErrorMsg: "Please add your email" - // highlight-end }, { id: "name", label: "Full name", placeholder: "Name", - // highlight-start nonOptionalErrorMsg: "Full name is required", - // highlight-end }] } } @@ -875,8 +815,8 @@ supertokensUIInit({ ] }); ``` - - + + ### Change the field order @@ -884,14 +824,14 @@ supertokensUIInit({ To customize the order of fields in your sign up form, override the `EmailPasswordSignUpForm` component. Use the next example as a reference. - - + + - + - + -```tsx preview="/img/emailpassword/signup-with-custom-field-order.png" previewAlt="Pre-built form UI with custom fields order" +```tsx {10,11,12,13,14,15,16,17,18,19,20,21} import React from "react"; import { SuperTokensWrapper } from "supertokens-auth-react"; import { EmailPasswordComponentsOverrideProvider } from "supertokens-auth-react/recipe/emailpassword"; @@ -901,7 +841,6 @@ function App() { { return ( ); }, - // highlight-end }}> {/* Rest of the JSX */} @@ -923,11 +861,11 @@ function App() { } export default App; ``` - + - + -```tsx preview="/img/emailpassword/signup-with-custom-field-order.png" previewAlt="Pre-built form UI with custom fields order" +```tsx {12,13,14,15,16,17,18,19,20,21,22,23} import React from "react"; import { SuperTokensWrapper } from "supertokens-auth-react"; import { EmailPasswordPreBuiltUI } from 'supertokens-auth-react/recipe/emailpassword/prebuiltui'; @@ -939,7 +877,6 @@ function App() { return ( { return ( ); }, - // highlight-end }}> {getRoutingComponent([EmailPasswordPreBuiltUI])} @@ -967,28 +903,24 @@ function App() { export default App; ``` - - - + - + - + -:::caution + -This is not applicable for non React apps. You have to create your own custom UI instead. +:::warning[This is not applicable for non React apps. You have to create your own custom UI instead.] ::: - - - - + + - + --- @@ -998,24 +930,24 @@ This is not applicable for non React apps. You have to create your own custom UI ### 1. Update the frontend configuration - + -:::caution Not applicable +:::warning[Not applicable] For your custom UI, you have to implement field validation checking yourself. Note that you need to also update the backend validation to ensure a complete flow. Check the next section for more details. ::: - + - + Add a `validate` method to any of your `formFields`. The following example shows how to add age verification to the form: - - + + -```tsx preview="/img/emailpassword/signup-with-name-and-age-failure.png" previewAlt="Pre-built form UI with custom validation" +```tsx {26,27,28,29,30,31} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import Session from "supertokens-auth-react/recipe/session"; @@ -1041,14 +973,12 @@ SuperTokens.init({ optional: true, /* Validation method to make sure that age is above 18 */ - // highlight-start validate: async (value) => { if (parseInt(value) > 18) { return undefined; // means that there is no error } return "You must be over 18 to register"; } - // highlight-end }, { id: "country", @@ -1063,15 +993,12 @@ SuperTokens.init({ ] }); ``` - + - + -```tsx preview="/img/emailpassword/signup-with-name-and-age-failure.png" previewAlt="Pre-built form UI with custom validation" +```tsx {24,25,26,27,28,29} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -1094,14 +1021,12 @@ supertokensUIInit({ optional: true, /* Validation method to make sure that age is above 18 */ - // highlight-start validate: async (value) => { if (parseInt(value) > 18) { return undefined; // means that there is no error } return "You must be over 18 to register"; } - // highlight-end }, { id: "country", @@ -1116,19 +1041,19 @@ supertokensUIInit({ ] }); ``` - - + + - + ### 2. Update the backend configuration Add `validate` functions to each of the form fields, in the backend SDK initialization call. - - + + -```tsx +```tsx {22,23,24,25,26,27} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -1150,14 +1075,12 @@ SuperTokens.init({ }, { id: "age", /* Validation method to make sure that age >= 18 */ - // highlight-start validate: async (value, tenantId) => { if (parseInt(value) >= 18) { return undefined; // means that there is no error } return "You must be over 18 to register"; } - // highlight-end }, { id: "country", optional: true @@ -1169,10 +1092,10 @@ SuperTokens.init({ ] }); ``` - - + + -```go +```go {21,22,23,24,25,26,27,28,29} import ( "strconv" @@ -1193,7 +1116,6 @@ func main() { }, { ID: "age", - //highlight-start Validate: func(value interface{}, tenantId string) *string { age, _ := strconv.Atoi(value.(string)) if age >= 18 { @@ -1203,7 +1125,6 @@ func main() { err := "You must be over 18 to register" return &err }, - //highlight-end }, { ID: "country", @@ -1217,35 +1138,31 @@ func main() { } ``` - - + + -```python +```python {6,7,8,9,10,21} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailpassword from supertokens_python.recipe.emailpassword import InputFormField from typing import Any -# highlight-start async def validate_age(value: Any, tenant_id: str): # Validation method to make sure that age >= 18 if int(value) >= 18: return None # means that there is no error return 'You must be over 18 to register' -# highlight-end init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( sign_up_feature=emailpassword.InputSignUpFeature( form_fields=[ InputFormField(id='name'), - # highlight-start InputFormField(id='age', validate=validate_age), - # highlight-end InputFormField(id='country', optional=True) ] ) @@ -1254,10 +1171,10 @@ init( ) ``` - - + + -:::info Multi-tenancy +:::info[Multi-tenancy] Notice the `tenantId` argument passed into the `validate` function. Using that, you can define custom logic per tenant. For example, you can define different password policies for different tenants. @@ -1274,8 +1191,7 @@ By default, SuperTokens adds an email and a password validator to the sign up fo To add your own validators follow the steps described initially in this section. -:::important -- The email validator that you define for **sign up** is also applied automatically to **sign in**. +:::note[- The email validator that you define for **sign up** is also applied automatically to **sign in**.] - The password validator that you define for **sign up** is also applied automatically to **reset password** forms. ::: @@ -1284,21 +1200,21 @@ Here is an example of what you need to change. ##### 1. Update the frontend configuration - + -:::caution Not applicable +:::warning[Not applicable] For your custom UI, you have to implement field validation checking yourself. Note that you need to also update the backend validation to ensure a complete flow. Check the next section for more details. ::: - + - - - + + + -```tsx +```tsx {15,16,17,18,19,20,21,22,23,24,25,26,27} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; @@ -1313,7 +1229,6 @@ SuperTokens.init({ signInAndUpFeature: { signUpForm: { formFields: [{ - // highlight-start id: "email", label: "...", validate: async (value) => { @@ -1327,7 +1242,6 @@ SuperTokens.init({ // Your own validation returning a string or undefined if no errors. return "..."; } - // highlight-end }] } } @@ -1335,14 +1249,12 @@ SuperTokens.init({ ] }); ``` - + - + -```tsx +```tsx {14,15,16,17,18,19,20,21,22,23,24,25,26} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; supertokensUIInit({ appInfo: { @@ -1355,7 +1267,6 @@ supertokensUIInit({ signInAndUpFeature: { signUpForm: { formFields: [{ - // highlight-start id: "email", label: "...", validate: async (value) => { @@ -1369,7 +1280,6 @@ supertokensUIInit({ // Your own validation returning a string or undefined if no errors. return "..."; } - // highlight-end }] } } @@ -1377,16 +1287,16 @@ supertokensUIInit({ ] }); ``` - - - + + + ##### 1. Update the backend configuration - - + + -```tsx +```tsx {17,18,19,20,21,22,23,24,25,26,27} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; @@ -1403,7 +1313,6 @@ SuperTokens.init({ EmailPassword.init({ signUpFeature: { formFields: [{ - // highlight-start id: "email", validate: async (value, tenantId) => { // Your own validation returning a string or undefined if no errors. @@ -1415,17 +1324,16 @@ SuperTokens.init({ // Your own validation returning a string or undefined if no errors. return "..."; } - // highlight-end }] } }), ] }); ``` - - + + -```go +```go {13,14,15,16,17,18,19,20,21,22,23,24,25,26} import ( "github.com/supertokens/supertokens-golang/recipe/emailpassword" "github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels" @@ -1438,7 +1346,6 @@ func main() { emailpassword.Init(&epmodels.TypeInput{ SignUpFeature: &epmodels.TypeInputSignUp{ FormFields: []epmodels.TypeInputFormField{ - //highlight-start { ID: "email", Validate: func(value interface{}, tenantId string) *string { @@ -1453,7 +1360,6 @@ func main() { return nil }, }, - //highlight-end }, }, }), @@ -1462,36 +1368,30 @@ func main() { } ``` - - + + -```python +```python {6,7,9,10,19,20} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailpassword from supertokens_python.recipe.emailpassword import InputFormField from typing import Any -# highlight-start async def validate_password(value: Any, tenant_id: str): pass # TODO -# highlight-end -# highlight-start async def validate_email(value: Any, tenant_id: str): pass # TODO -# highlight-end init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( sign_up_feature=emailpassword.InputSignUpFeature( form_fields=[ - # highlight-start InputFormField(id='password', validate=validate_password), InputFormField(id='email', validate=validate_email) - # highlight-end ] ) ) @@ -1499,14 +1399,14 @@ init( ) ``` - - + + --- ## Add terms of service and privacy policy links - + To add "Terms of service" and "Privacy policy" links to your sign up page add the links in the frontend SDK initialization call. Based on the provided configuration the data renders in the following way: @@ -1514,10 +1414,10 @@ Based on the provided configuration the data renders in the following way: - Provided only Terms of service link: "By signing up, you agree to the [Terms of Service](#add-terms-of-service-and-privacy-policy-links)" - Provided only Privacy policy link: "By signing up, you agree to the [Privacy Policy](#add-terms-of-service-and-privacy-policy-links)" - - + + -```tsx +```tsx {9,10} import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ @@ -1526,20 +1426,17 @@ SuperTokens.init({ appName: "...", websiteDomain: "..." }, - // highlight-start termsOfServiceLink: "https://example.com/terms-of-service", privacyPolicyLink: "https://example.com/privacy-policy", - // highlight-end recipeList: [/* ... */] }); ``` - + - + -```tsx +```tsx {9,10} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -1547,34 +1444,31 @@ supertokensUIInit({ appName: "...", websiteDomain: "..." }, - // highlight-start termsOfServiceLink: "https://example.com/terms-of-service", privacyPolicyLink: "https://example.com/privacy-policy", - // highlight-end recipeList: [/* ... */] }); ``` - - + + - - + + -:::caution -Not applicable since you do not use the pre-built UI. +:::warning[Not applicable since you do not use the pre-built UI.] ::: - + --- ## See also - - - - - - + + + + + + diff --git a/docs/authentication/email-password/disable-signup.mdx b/docs/authentication/email-password/disable-signup.mdx index 19f6830a54..ab02dfa934 100644 --- a/docs/authentication/email-password/disable-signup.mdx +++ b/docs/authentication/email-password/disable-signup.mdx @@ -1,21 +1,14 @@ --- title: Disable Sign Up -hide_title: true description: Learn how to disable the sign up flow -sidebar_position: 8 -page_type: guide -recipe: emailpassword -category: email-password +sidebar: + order: 8 --- +Learn how to disable the sign up flow for the `EmailPassword` recipe. -# Disable the Sign Up Flow - - - Learn how to disable the sign up flow for the `EmailPassword` recipe. - +--- - ## Overview @@ -28,21 +21,19 @@ This can be done in two steps: ## Before you start This guide assumes that you already have configured your application to use **SuperTokens** for authentication. -If you have not, please check the [Quickstart Guide](/docs/quickstart/introduction). - +If you have not, please check the [Quickstart Guide](/quickstart/introduction). ## Remove the sign up UI - + - + + - - - + Remove the sign up UI by overriding the `AuthPageComponentList` component and setting the `showSuperTokensAuth` prop to `false`. @@ -70,15 +61,14 @@ function App() { export default App; ``` - + - + Remove the sign up UI by customizing the `CSS` of the authentication page. ```tsx // this goes in the auth route config of your frontend app (once the pre built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -95,28 +85,28 @@ supertokensUIInit({ }); ``` - + - + - + - + If you have a custom UI, this step will depend on your implementation. Just make sure that the user will not be able to view any sign up elements on the authentication page. - + ## Disable the Backend SDK sign up endpoints Override the **Backend SDK** API functions to prevent sign up attempts. - - + + -```tsx +```tsx {19} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; @@ -135,7 +125,6 @@ SuperTokens.init({ apis: (originalImplementation) => { return { ...originalImplementation, - // highlight-next-line signUpPOST: undefined, } } @@ -145,10 +134,10 @@ SuperTokens.init({ }); ``` - - + + -```go +```go {13} import ( "github.com/supertokens/supertokens-golang/recipe/emailpassword" "github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels" @@ -161,7 +150,6 @@ func main() { emailpassword.Init(&epmodels.TypeInput{ Override: &epmodels.OverrideStruct{ APIs: func(originalImplementation epmodels.APIInterface) epmodels.APIInterface { - // highlight-next-line originalImplementation.SignUpPOST = nil return originalImplementation }, @@ -171,22 +159,21 @@ func main() { }) } ``` - - + + -```python +```python {6} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailpassword from supertokens_python.recipe.emailpassword.interfaces import APIInterface def apis_override(original_impl: APIInterface): - # highlight-next-line original_impl.disable_sign_up_post = True return original_impl init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( override=emailpassword.InputOverrideConfig( @@ -197,25 +184,21 @@ init( ) ``` - - + + ## See also - - - Account Creation - Import accounts using the SuperTokens API. - - - User Management - SDK functions that can be used to manage users. - - - Dashboard - UI exposed by the SuperTokens SDK that allows you to view and manage users. - - - + + +Import accounts using the SuperTokens API. + + +SDK functions that can be used to manage users. + + +UI exposed by the SuperTokens SDK that allows you to view and manage users. + + diff --git a/docs/authentication/email-password/hooks-and-overrides.mdx b/docs/authentication/email-password/hooks-and-overrides.mdx index 4129a8ea75..8bb6afc2e7 100644 --- a/docs/authentication/email-password/hooks-and-overrides.mdx +++ b/docs/authentication/email-password/hooks-and-overrides.mdx @@ -1,30 +1,22 @@ --- title: Hooks and overrides -hide_title: true -sidebar_position: 4 -description: >- - Add custom logic in the authentication flow by overriding the SuperTokens - APIs. -page_type: guide -recipe: emailpassword -category: email-password +description: Add custom logic in the authentication flow by overriding the SuperTokens APIs. +sidebar: + order: 4 --- -# Hooks and overrides - - **SuperTokens** exposes a set of constructs that allow you to trigger different actions during the authentication lifecycle or to even fully customize the logic based on your use case. The following sections describe how you can modify adjust the `emailpassword` recipe to your needs. -Explore the [references pages](/docs/references) for a more in depth guide on hooks and overrides. +Explore the [references pages](/references) for a more in depth guide on hooks and overrides. ## Sign in ### Frontend hook - + - + This method gets fired, with the `SUCCESS` action, immediately after a successful sign in or sign up. Follow the code snippet to determine if the user is signing up or signing in. @@ -32,13 +24,13 @@ Follow the code snippet to determine if the user is signing up or signing in. With this method you can fire events immediately after a successful sign in. You can use it to send analytics events. - + - + -```tsx +```tsx {13,14,15,16,17,18,19,20,21} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import Session from "supertokens-auth-react/recipe/session"; @@ -51,7 +43,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start onHandleEvent: async (context) => { if (context.action === "SUCCESS") { if (context.isNewRecipeUser && context.user.loginMethods.length === 1) { @@ -61,7 +52,6 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init() ] @@ -69,16 +59,13 @@ SuperTokens.init({ ``` - + - + -```tsx +```tsx {10,11,12,13,14,15,16,17,18} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { apiDomain: "...", @@ -87,7 +74,6 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailPassword.init({ - // highlight-start onHandleEvent: async (context) => { if (context.action === "SUCCESS") { if (context.isNewRecipeUser && context.user.loginMethods.length === 1) { @@ -97,7 +83,6 @@ supertokensUIInit({ } } } - // highlight-end }), supertokensUISession.init() ] @@ -105,20 +90,20 @@ supertokensUIInit({ ``` - + - + - + - + -:::caution Not applicable +:::warning[Not applicable] This section is not applicable for custom UI since you are calling the sign in API yourself anyway. You can perform anything you want to do post sign in based on the result of the API call. ::: - + ### Backend override @@ -126,10 +111,10 @@ Overriding the `signIn` function allows you to introduce your own logic for the Use it to persist different types of data or trigger actions. - - + + -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -145,7 +130,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -178,16 +162,15 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init({ /* ... */ }) ] }); ``` - - + + -```go +```go {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42} import ( "fmt" @@ -200,7 +183,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ emailpassword.Init(&epmodels.TypeInput{ - //highlight-start Override: &epmodels.OverrideStruct{ Functions: func(originalImplementation epmodels.RecipeInterface) epmodels.RecipeInterface { // create a copy of the originalImplementation func @@ -231,17 +213,16 @@ func main() { return originalImplementation }, }, - //highlight-end }), }, }) } ``` - - + + -```python +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,54,55,56} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session, emailpassword from supertokens_python.recipe.emailpassword.interfaces import ( @@ -252,7 +233,6 @@ from typing import Dict, Any, Union from supertokens_python.recipe.session.interfaces import SessionContainer -# highlight-start def override_emailpassword_functions( original_implementation: RecipeInterface, ) -> RecipeInterface: @@ -290,26 +270,22 @@ def override_emailpassword_functions( return original_implementation -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( - # highlight-start override=emailpassword.InputOverrideConfig( functions=override_emailpassword_functions ), - # highlight-end ), session.init(), ], ) ``` - - + + --- @@ -320,13 +296,13 @@ init( This method gets fired, with the `SUCCESS` action, immediately after a successful sign in or sign up. Follow the code snippet to determine if the user is signing up. - + - + - + -```tsx +```tsx {13,14,15,16,17,18,19,20,21} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import Session from "supertokens-auth-react/recipe/session"; @@ -339,7 +315,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start onHandleEvent: async (context) => { if (context.action === "SUCCESS") { if (context.isNewRecipeUser && context.user.loginMethods.length === 1) { @@ -349,7 +324,6 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init() ] @@ -357,16 +331,13 @@ SuperTokens.init({ ``` - + - + -```tsx +```tsx {10,11,12,13,14,15,16,17,18} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { apiDomain: "...", @@ -375,7 +346,6 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailPassword.init({ - // highlight-start onHandleEvent: async (context) => { if (context.action === "SUCCESS") { if (context.isNewRecipeUser && context.user.loginMethods.length === 1) { @@ -385,7 +355,6 @@ supertokensUIInit({ } } } - // highlight-end }), supertokensUISession.init() ] @@ -393,20 +362,20 @@ supertokensUIInit({ ``` - + - + - + - + -:::caution Not applicable +:::warning[Not applicable] This section is not applicable for custom UI since you are calling the sign up API yourself anyway. You can perform anything you want to do post sign up based on the result of the API call. ::: - + ### Backend override @@ -415,10 +384,10 @@ Overriding the `signUp` function allows you to introduce your own logic for the Use it to persist different types of data, synchronize users between **SuperTokens** and your systems or to trigger other types of actions. - - + + -```tsx +```tsx {17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -435,7 +404,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -466,16 +434,15 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init({ /* ... */ }) ] }); ``` - - + + -```go +```go {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43} import ( "fmt" @@ -489,7 +456,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ emailpassword.Init(&epmodels.TypeInput{ - //highlight-start Override: &epmodels.OverrideStruct{ Functions: func(originalImplementation epmodels.RecipeInterface) epmodels.RecipeInterface { // create a copy of the originalImplementation func @@ -520,17 +486,16 @@ func main() { return originalImplementation }, }, - //highlight-end }), }, }) } ``` - - + + -```python +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,54,55,56} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session, emailpassword from supertokens_python.recipe.emailpassword.interfaces import ( @@ -541,7 +506,6 @@ from typing import Dict, Any, Union from supertokens_python.recipe.session.interfaces import SessionContainer -# highlight-start def override_emailpassword_functions( original_implementation: RecipeInterface, ) -> RecipeInterface: @@ -579,26 +543,22 @@ def override_emailpassword_functions( return original_implementation -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( - # highlight-start override=emailpassword.InputOverrideConfig( functions=override_emailpassword_functions ), - # highlight-end ), session.init(), ], ) ``` - - + + --- @@ -609,18 +569,18 @@ init( ### Frontend hook - + This method gets fired during the password reset flow with either the `PASSWORD_RESET_SUCCESSFUL` or `RESET_PASSWORD_EMAIL_SENT` action. Use it to fire analytics events or to add any additional logic. - + - + -```tsx +```tsx {13,14,15,16,17,18,19} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import Session from "supertokens-auth-react/recipe/session"; @@ -633,7 +593,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start onHandleEvent: async (context) => { if (context.action === "PASSWORD_RESET_SUCCESSFUL") { // Add you custom logic here @@ -641,7 +600,6 @@ SuperTokens.init({ // Add you custom logic here } } - // highlight-end }), Session.init() ] @@ -649,16 +607,13 @@ SuperTokens.init({ ``` - + - + -```tsx +```tsx {10,11,12,13,14,15,16} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { apiDomain: "...", @@ -667,7 +622,6 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailPassword.init({ - // highlight-start onHandleEvent: async (context) => { if (context.action === "PASSWORD_RESET_SUCCESSFUL") { // Add you custom logic here @@ -675,7 +629,6 @@ supertokensUIInit({ // Add you custom logic here } } - // highlight-end }), supertokensUISession.init() ] @@ -683,20 +636,20 @@ supertokensUIInit({ ``` - + - + - + - + -:::caution Not applicable +:::warning[Not applicable] This section is not applicable for custom UI since you are calling the sign in API yourself anyway. You can perform anything you want to do during the password reset flow based on the result of the API call. ::: - + ### Backend override @@ -704,10 +657,10 @@ This section is not applicable for custom UI since you are calling the sign in A Overriding the `passwordResetPOST` function allows you to introduce your own logic for the password reset process. Use it to introduce your own logic for the flow. - - + + -```tsx +```tsx {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -720,7 +673,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start override: { apis: (originalImplementation) => { return { @@ -743,16 +695,15 @@ SuperTokens.init({ }; }, }, - // highlight-end }), Session.init() ] }); ``` - - + + -```go +```go {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37} import ( "github.com/supertokens/supertokens-golang/recipe/emailpassword" "github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels" @@ -764,7 +715,6 @@ func main() { RecipeList: []supertokens.Recipe{ emailpassword.Init(&epmodels.TypeInput{ - //highlight-start Override: &epmodels.OverrideStruct{ APIs: func(originalImplementation epmodels.APIInterface) epmodels.APIInterface { @@ -791,17 +741,16 @@ func main() { return originalImplementation }, }, - //highlight-end }), }, }) } ``` - - + + -```python +```python {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,42} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailpassword from supertokens_python.recipe.emailpassword.interfaces import ( @@ -813,7 +762,6 @@ from supertokens_python.recipe.emailpassword.types import FormField from typing import Dict, List, Any -# highlight-start def override_apis(original_implementation: APIInterface): original_password_reset_post = original_implementation.password_reset_post @@ -838,33 +786,29 @@ def override_apis(original_implementation: APIInterface): return original_implementation -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( - # highlight-start override=emailpassword.InputOverrideConfig(apis=override_apis) - # highlight-end ) ], ) ``` - - + + --- ## See also - - - - - - - + + + + + + + diff --git a/docs/authentication/email-password/implement-username-login.mdx b/docs/authentication/email-password/implement-username-login.mdx index b3111b6d52..ecd333f05c 100644 --- a/docs/authentication/email-password/implement-username-login.mdx +++ b/docs/authentication/email-password/implement-username-login.mdx @@ -1,20 +1,10 @@ --- title: Implement username login -hide_title: true -sidebar_position: 7 -toc_max_heading_level: 4 -description: >- - Enable username login by replacing email with username in the SuperTokens - authentication flow. -page_type: guide -recipe: emailpassword -category: email-password +description: Enable username login by replacing email with username in the SuperTokens authentication flow. +sidebar: + order: 7 --- - -# Implement username login - - ## Overview @@ -38,8 +28,8 @@ Then the optional email value gets saved against the `userID` of the user and yo ## Before you start -This guide assumes that you have already implemented the [EmailPassword recipe](/docs/authentication/email-password/introduction) and have a working application integrated with **SuperTokens**. -If you have not, please check the [Quickstart Guide](/docs/quickstart/introduction). +This guide assumes that you have already implemented the [EmailPassword recipe](/authentication/email-password/introduction) and have a working application integrated with **SuperTokens**. +If you have not, please check the [Quickstart Guide](/quickstart/introduction). ## Steps @@ -55,8 +45,8 @@ This ensures that the username is unique and that the authentication flows works Use the next code snippet as a reference. - - + + ```tsx import SuperTokens from "supertokens-node"; @@ -105,8 +95,8 @@ SuperTokens.init({ }); ``` - - + + ```go import ( @@ -158,8 +148,8 @@ func main() { } ``` - - + + ```python from re import fullmatch @@ -190,7 +180,7 @@ async def validate(value: str, tenant_id: str): init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( sign_up_feature=InputSignUpFeature(form_fields=[ @@ -201,8 +191,8 @@ init( ) ``` - - + + ### 2. Save the user email @@ -211,14 +201,14 @@ init( The sign up `API` takes in the username, password, and an optional email. Add a new form field for the email, along with a `validate` function that checks the uniqueness and syntax of the input email. -:::warning Custom Implementation +:::warning[Custom Implementation] To check if the email is unique you need to persist values in your own database and then check against them. ::: - - + + -```tsx +```tsx {33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; @@ -251,7 +241,6 @@ SuperTokens.init({ return undefined } }, { - // highlight-start id: "actualEmail", validate: async (value) => { if (value === "") { @@ -271,7 +260,6 @@ SuperTokens.init({ } }, optional: true - // highlight-end }] } }) @@ -279,10 +267,10 @@ SuperTokens.init({ }); ``` - - + + -```go +```go {38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63} import ( "regexp" @@ -320,7 +308,6 @@ func main() { return nil }, }, - // highlight-start { ID: "actualEmail", Validate: func(value interface{}, tenantId string) *string { @@ -347,7 +334,6 @@ func main() { }, Optional: &actualEmailOptional, }, - // highlight-end }, }, }), @@ -356,10 +342,10 @@ func main() { } ``` - - + + -```python +```python {11,12,13,14,15,16,17,18,43,44} from re import fullmatch from typing import Dict @@ -370,7 +356,6 @@ from supertokens_python.recipe.emailpassword.utils import InputSignUpFeature email_user_map: Dict[str, str] = {} -# highlight-start async def get_user_using_email(email: str): # TODO: Check your database for if the email is associated with a user # and return that user ID if it is. @@ -379,7 +364,6 @@ async def get_user_using_email(email: str): if email in email_user_map: return email_user_map[email] return None -# highlight-end async def validate(value: str, tenant_id: str): # from previous code snippet.. @@ -399,23 +383,21 @@ async def validate_actual_email(value: str, tenant_id: str): init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( sign_up_feature=InputSignUpFeature(form_fields=[ InputFormField(id="email", validate=validate), - # highlight-start InputFormField(id="actualEmail", validate=validate_actual_email, optional=True) - # highlight-end ]) ) ] ) ``` - - + + #### 2.2 Save the email field value @@ -424,10 +406,10 @@ Override the sign up API to save the custom email form field. Use a mapping of `userID` to `email` to keep track of the association. Save the email value in your own database. - - + + -```tsx +```tsx {32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; @@ -459,7 +441,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start override: { apis: (original) => { return { @@ -482,7 +463,6 @@ SuperTokens.init({ } } }, - // highlight-end signUpFeature: { formFields: [ /* ... from previous code snippet ... */] } @@ -491,10 +471,10 @@ SuperTokens.init({ }); ``` - - + + -```go +```go {39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74} import ( "errors" @@ -533,7 +513,6 @@ func main() { SignUpFeature: &epmodels.TypeInputSignUp{ FormFields: []epmodels.TypeInputFormField{ /* ... from previous code... */}, }, - // highlight-start Override: &epmodels.OverrideStruct{ APIs: func(originalImplementation epmodels.APIInterface) epmodels.APIInterface { ogSignUpPOST := *originalImplementation.SignUpPOST @@ -570,17 +549,16 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74} from typing import Any, Dict, List, Union from supertokens_python import InputAppInfo, init @@ -610,7 +588,6 @@ async def get_user_using_email(email: str): return None -# highlight-start async def save_email_for_user(email: str, user_id: str): # TODO: Save email and userId mapping @@ -656,11 +633,9 @@ def apis_override(original: APIInterface): return original -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( sign_up_feature=InputSignUpFeature( @@ -674,8 +649,8 @@ init( ) ``` - - + + ### 3. Allow username or email during sign in @@ -686,10 +661,10 @@ Override the sign in recipe function to allow this. Use the next code snippet as a reference. The example use the `email` to `userId` mapping, mentioned earlier, to figure out which username to use. - - + + -```tsx +```tsx {21,22,23,24,25,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; @@ -710,13 +685,11 @@ async function saveEmailForUser(email: string, userId: string) { emailUserMap[email] = userId } -// highlight-start function isInputEmail(input: string): boolean { return input.match( /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ ) !== null; } -// highlight-end SuperTokens.init({ appInfo: { @@ -730,7 +703,6 @@ SuperTokens.init({ recipeList: [ EmailPassword.init({ override: { - // highlight-start functions: (original) => { return { ...original, @@ -754,7 +726,6 @@ SuperTokens.init({ } } }, - // highlight-end apis: (original) => { return { ...original, @@ -770,10 +741,10 @@ SuperTokens.init({ }); ``` - - + + -```go +```go {31,32,33,34,35,36,37,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73} import ( "regexp" @@ -804,7 +775,6 @@ func saveEmailForUser(email string, userId string) error { return nil } -// highlight-start func isInputEmail(email string) bool { emailCheck, err := regexp.Match(`^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$`, []byte(email)) if err != nil || !emailCheck { @@ -812,7 +782,6 @@ func isInputEmail(email string) bool { } return true } -// highlight-end func main() { @@ -827,7 +796,6 @@ func main() { // ...from previous code snippet... return originalImplementation }, - // highlight-start Functions: func(originalImplementation epmodels.RecipeInterface) epmodels.RecipeInterface { ogSignIn := *originalImplementation.SignIn (*originalImplementation.SignIn) = func(email, password, tenantId string, userContext supertokens.UserContext) (epmodels.SignInResponse, error) { @@ -850,7 +818,6 @@ func main() { } return originalImplementation }, - // highlight-end }, }), }, @@ -858,10 +825,10 @@ func main() { } ``` - - + + -```python +```python {34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86} from re import fullmatch from typing import Any, Dict, Union @@ -895,9 +862,6 @@ async def save_email_for_user(email: str, user_id: str): email_user_map[email] = user_id -# highlight-start - - def is_input_email(email: str): return ( fullmatch( @@ -949,12 +913,9 @@ def recipe_override(original: RecipeInterface): return original -# highlight-end - - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( sign_up_feature=InputSignUpFeature( @@ -971,8 +932,8 @@ init( ) ``` - - + + ### 4. Allow username or email during password reset @@ -988,10 +949,10 @@ The user should enter either their username or their email when starting the pas Like the sign in customization, you must check if the input is an email and, if it is, retrieve the username associated with the email. If you can't find a username from an email you have to return an appropriate message to the frontend. - - + + -```tsx +```tsx {28,29,30,31,32,33,34,35,36,37,38,39,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import supertokensTypes from "supertokens-node/types"; @@ -1019,7 +980,6 @@ function isInputEmail(input: string): boolean { ) !== null; } -// highlight-start async function getEmailUsingUserId(userId: string) { // TODO: check your database mapping.. @@ -1032,7 +992,6 @@ async function getEmailUsingUserId(userId: string) { } return undefined; } -// highlight-end SuperTokens.init({ appInfo: { @@ -1056,7 +1015,6 @@ SuperTokens.init({ return { ...original, // ...override from previous code snippet... - // highlight-start generatePasswordResetTokenPOST: async function (input) { let emailOrUsername = input.formFields.find(i => i.id === "email")!.value as string; if (isInputEmail(emailOrUsername)) { @@ -1098,7 +1056,6 @@ SuperTokens.init({ } return original.generatePasswordResetTokenPOST!(input); }, - // highlight-end } } }, @@ -1110,10 +1067,10 @@ SuperTokens.init({ }); ``` - - + + -```go +```go {40,41,42,43,44,45,46,47,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132} import ( "regexp" "errors" @@ -1153,7 +1110,6 @@ func isInputEmail(email string) bool { return true } -// highlight-start func getEmailUsingUserId(userId string) (*string, error) { for email, mappedUserId := range emailUserMap { if mappedUserId == userId { @@ -1162,7 +1118,6 @@ func getEmailUsingUserId(userId string) (*string, error) { } return nil, nil } -// highlight-end func main() { @@ -1176,7 +1131,6 @@ func main() { APIs: func(originalImplementation epmodels.APIInterface) epmodels.APIInterface { // ...override sign up API from previous code snippet... - // highlight-start ogGeneratePasswordResetTokenPOST := *originalImplementation.GeneratePasswordResetTokenPOST (*originalImplementation.GeneratePasswordResetTokenPOST) = func(formFields []epmodels.TypeFormField, tenantId string, options epmodels.APIOptions, userContext supertokens.UserContext) (epmodels.GeneratePasswordResetTokenPOSTResponse, error) { @@ -1249,7 +1203,6 @@ func main() { return ogGeneratePasswordResetTokenPOST(formFields, tenantId, options, userContext) } - // highlight-end return originalImplementation }, @@ -1264,10 +1217,10 @@ func main() { } ``` - - + + -```python +```python {49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126} from re import fullmatch from typing import Any, Dict, List @@ -1316,7 +1269,6 @@ def is_input_email(email: str): ) -# highlight-start async def get_email_using_user_id(user_id: str): for email in email_user_map: if email_user_map[email] == user_id: @@ -1395,12 +1347,9 @@ def apis_override(original: APIInterface): return original -# highlight-end - - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( sign_up_feature=InputSignUpFeature( @@ -1417,17 +1366,17 @@ init( ) ``` - - + + #### 4.2 Override the email sending API Update the email sending API to retrieve the user email if the user used a username in the password reset flow. - - + + -```tsx +```tsx {57,58,59,60,61,62,63,64,65,66,67} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; @@ -1484,7 +1433,6 @@ SuperTokens.init({ signUpFeature: { formFields: [ /* ... from previous code snippet ... */] }, - // highlight-start emailDelivery: { override: (original) => { return { @@ -1496,16 +1444,15 @@ SuperTokens.init({ } } }, - // highlight-end }) ] }); ``` - - + + -```go +```go {67,68,69,70,71,72,73,74,75,76,77,78,79,80} import ( "regexp" @@ -1572,7 +1519,6 @@ func main() { return originalImplementation }, }, - // highlight-start EmailDelivery: &emaildelivery.TypeInput{ Override: func(originalImplementation emaildelivery.EmailDeliveryInterface) emaildelivery.EmailDeliveryInterface { ogSendEmail := *originalImplementation.SendEmail @@ -1587,17 +1533,16 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {49,50,51,52,53,54,55,56,57,58,59,60,76} from re import fullmatch from typing import Any, Dict @@ -1646,7 +1591,6 @@ async def get_email_using_user_id(user_id: str): return email return None -# highlight-start def custom_email_deliver(original_implementation: EmailDeliveryOverrideInput) -> EmailDeliveryOverrideInput: original_send_email = original_implementation.send_email @@ -1659,13 +1603,12 @@ def custom_email_deliver(original_implementation: EmailDeliveryOverrideInput) -> original_implementation.send_email = send_email return original_implementation -# highlight-end init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( sign_up_feature=InputSignUpFeature(form_fields=[ @@ -1675,23 +1618,20 @@ init( # functions=..., from previous code snippet # apis=..., from previous code snippet ), - # highlight-next-line email_delivery=EmailDeliveryConfig(override=custom_email_deliver) ) ] ) ``` - - - + + ### 5. Show the new fields in the user interface -:::info -The following instructions are only relevant if you are using the pre-built UI. +:::info[The following instructions are only relevant if you are using the pre-built UI.] If you created your own custom UI on the frontend, please make sure to pass the new email `formField` when you call the sign up function. Even if the user has not given an email, you must add it with an empty string. ::: @@ -1704,7 +1644,7 @@ Update the pre-built UI to reflect the new flow: - Change the "Email" label in the password reset form to say "Username or email". - Update translations for the email field if necessary. -```tsx +```tsx {10,11,12,13,14,15,16,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45} import SuperTokens from "supertokens-auth-react" import EmailPassword from "supertokens-auth-react/recipe/emailpassword" @@ -1714,7 +1654,6 @@ SuperTokens.init({ apiDomain: "...", websiteDomain: "...", }, - // highlight-start languageTranslations: { translations: { "en": { @@ -1722,11 +1661,9 @@ SuperTokens.init({ } } }, - // highlight-end recipeList: [ EmailPassword.init({ signInAndUpFeature: { - // highlight-start signInForm: { formFields: [{ id: "email", @@ -1753,7 +1690,6 @@ SuperTokens.init({ optional: true }] } - // highlight-end } }), // other recipes initialisation.. @@ -1762,13 +1698,12 @@ SuperTokens.init({ ``` - ## See also - - - - - - - + + + + + + + diff --git a/docs/authentication/email-password/introduction.mdx b/docs/authentication/email-password/introduction.mdx index a0f8f3dd94..040dfc60ff 100644 --- a/docs/authentication/email-password/introduction.mdx +++ b/docs/authentication/email-password/introduction.mdx @@ -1,97 +1,49 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -pagination_next: null -pagination_prev: null -skip_llms_txt: true -description: >- - Authenticate users with email/password, customize UI, and explore SDK - integration options. -page_type: overview -recipe: emailpassword -category: email-password +description: Authenticate users with email/password, customize UI, and explore SDK integration options. +sidebar: + order: 1 --- - -# Introduction - ## Overview The **Email/Password** `recipe` provides a way of authenticating users with basic credentials. You can use it out of the box, with the **Pre-Built UI**, or implement your own interface through the available SDKs. -Sign in form UI for email password login +Sign in form UI for email password login ## Getting started You can either follow the quickstart tutorial or use the `CLI` tool to generate an example app that shows you how the recipe works. - - - - Quickstart - - - Go through a quick tutorial that shows you how to add the **Email/Password** recipe to your app. - - - - - Example Applications - - - Use the CLI to generate a boilerplate app that you can use as a starting point. - - - + + +Go through a quick tutorial that shows you how to add the **Email/Password** recipe to your app. + + +Use the CLI to generate a boilerplate app that you can use as a starting point. + + ## Customization To adjust the functionality to fit your use case you can explore different sections from the documentation. - - - - Sign In Form Customization - - - Adapt the look and feel of the pre-built sign in form. - - - - - Sign Up Form Customization - - - Adapt the look and feel of the pre-built sign up form. - - - - - Hooks and Overrides - - - Add custom logic after the user logs in or signs up. - - - - - Password Hashing - - - Read which hashing algorithms you can use and how to use them. - - - - - Username Login - - - Discover how you can implement an authentication flow that makes use of usernames instead of email addresses. - - - - - + + +Adapt the look and feel of the pre-built sign in form. + + +Adapt the look and feel of the pre-built sign up form. + + +Add custom logic after the user logs in or signs up. + + +Read which hashing algorithms you can use and how to use them. + + +Discover how you can implement an authentication flow that makes use of usernames instead of email addresses. + + diff --git a/docs/authentication/email-password/meta.ts b/docs/authentication/email-password/meta.ts new file mode 100644 index 0000000000..d7e41d0bae --- /dev/null +++ b/docs/authentication/email-password/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Email Password", + "icon": "rectangle-ellipsis", + "order": 1.2 +}); diff --git a/docs/authentication/email-password/password-hashing.mdx b/docs/authentication/email-password/password-hashing.mdx index c540b47fec..0bfa577bbc 100644 --- a/docs/authentication/email-password/password-hashing.mdx +++ b/docs/authentication/email-password/password-hashing.mdx @@ -1,19 +1,10 @@ --- title: Password hashing -hide_title: true -sidebar_position: 5 -description: >- - Learn about the password hashing algorithms used by SuperTokens and how to - customize and calibrate them. -page_type: guide -recipe: emailpassword -category: email-password +description: Learn about the password hashing algorithms used by SuperTokens and how to customize and calibrate them. +sidebar: + order: 5 --- - - -# Password hashing - ## Overview **SuperTokens** supports two password hashing algorithms: `BCrypt` and `Argon2`. @@ -34,28 +25,26 @@ For example, if you hash a password with `BCrypt`, it verifies using `BCrypt` ev Instructions: - + - + 1. Go to the [SuperTokens SaaS dashboard](https://supertokens.com/dashboard) and select the relevant **Managed** deployment. 2. Open **Configuration** and find the **Password Hashing Algorithm** setting. 3. Change the algorithm. Configuration changes are saved automatically. - + - + -```bash +```bash {3,4} docker run \ -p 3567:3567 \ - // highlight-start -e PASSWORD_HASHING_ALG=BCRYPT \ -e BCRYPT_LOG_ROUNDS=11 \ - // highlight-end -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -64,22 +53,21 @@ docker run \ password_hashing_alg: BCRYPT bcrypt_log_rounds: 11 ``` - + - + ## Hashing calibration This information is relevant only for self hosted core instances. The managed service instances have already calibrated the algorithms based on the hardware. -:::important -When you change the hashing settings make sure to run the calibration CLI command to find the right balance for your hardware. +:::note[When you change the hashing settings make sure to run the calibration CLI command to find the right balance for your hardware.] ::: - + - + #### Algorithm settings @@ -102,24 +90,22 @@ Password hashing occurs during sign in, sign up, and password reset flows. There #### Change the settings - - + + -```bash +```bash {3,4,5,6,7} docker run \ -p 3567:3567 \ - // highlight-start -e PASSWORD_HASHING_ALG=ARGON2 \ -e ARGON2_ITERATIONS=1 \ -e ARGON2_MEMORY_KB=87795 \ -e ARGON2_PARALLELISM=2 \ -e ARGON2_HASHING_POOL_SIZE=1 \ - // highlight-end -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -132,8 +118,8 @@ argon2_parallelism: 2 argon2_hashing_pool_size: 1 ``` - - + + #### Calibrate to your hardware @@ -157,22 +143,22 @@ To find the optimal setting for your hardware, you can run the `hashingCalibrate Running the algorithm takes minutes. - - + + ```bash docker run supertokens/supertokens- supertokens hashingCalibrate --with_alg=argon2 ``` - + - + ```bash supertokens hashingCalibrate --with_alg=argon2 ``` - - + + The above produces an output like: ```text @@ -211,11 +197,9 @@ Calculating average hashing time.... ..................................................Took 494 MS per hash - <....Truncated....> - Adjusting memory to reach target time. Current argon2 settings @@ -251,7 +235,7 @@ The contents of the `====Final values====` gives you the values of the parameter The algorithm starts with the highest amount of memory per hash (= `with_argon2_max_memory_mb/with_argon2_hashing_pool_size`) and `1` iteration. It calculates the current average hashing time by simulating hashes concurrently (based on the value of `with_argon2_hashing_pool_size`). If the hashing time is greater than the target time, it reduces the memory by 5%. If it's less than the target time, it increases the number of iterations. The algorithm stops if the current time is within 10 milliseconds (higher or lower) of the target time. -:::info debug +:::info[debug] If you see an output like: ```bash /usr/bin/supertokens: line 9: 15 Killed "${ST_INSTALL_LOC}"jre/bin/java -classpath "${ST_INSTALL_LOC}cli/*" io.supertokens.cli.Main false "${ST_INSTALL_LOC}" $@ @@ -259,9 +243,9 @@ If you see an output like: it means that the system doesn't have enough memory. Try to run the algorithm again with a lower memory value by passing `--with_argon2_max_memory_mb` ::: - + - + #### Algorithm settings @@ -273,21 +257,19 @@ it means that the system doesn't have enough memory. Try to run the algorithm ag #### Change settings - - + + -```bash +```bash {3,4} docker run \ -p 3567:3567 \ - // highlight-start -e PASSWORD_HASHING_ALG=BCRYPT \ -e BCRYPT_LOG_ROUNDS=11 \ - // highlight-end -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -297,8 +279,8 @@ password_hashing_alg: BCRYPT bcrypt_log_rounds: 11 ``` - - + + #### Calibrate to your hardware @@ -311,22 +293,22 @@ To find the optimal setting for your hardware, you can run the `hashingCalibrate - This requires the target time per hash (in milliseconds). - The default value is `300` - - + + ```bash docker run supertokens/supertokens- supertokens hashingCalibrate --with_alg=bcrypt ``` - + - + ```bash supertokens hashingCalibrate --with_alg=bcrypt ``` - - + + The above produces an output like: ```text @@ -357,16 +339,16 @@ The contents of the `====Final values====` gives you the values of the parameter The algorithm starts with the minimum recommended value (`11`), and increments it until the average time per hash is greater than the target time. The final value is then equal to the value that yields the closest time per hash as the target one. - + ## See also - - - - - - + + + + + + diff --git a/docs/authentication/email-password/password-managers.mdx b/docs/authentication/email-password/password-managers.mdx index d9a06b485f..814d7e6709 100644 --- a/docs/authentication/email-password/password-managers.mdx +++ b/docs/authentication/email-password/password-managers.mdx @@ -1,34 +1,23 @@ --- -id: password-managers title: Password managers -hide_title: true -sidebar_position: 9 -description: >- - Ensure password managers detect authentication fields by disabling shadow DOM - in your application. -page_type: guide -recipe: emailpassword -category: email-password +description: Ensure password managers detect authentication fields by disabling shadow DOM in your application. +sidebar: + order: 9 --- - -# Password managers - - ## Overview Styling encapsulation relies on the ["shadow DOM" browser feature](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM). Password managers such as Dashlane, LastPass, or OnePassword do not detect authentication forms fields inside shadow DOMs. Therefore, if you would like to make sure that your end users can use their password managers, you have to disable shadow DOM. -:::info no-title -These instructions are only relevant if you are using the pre-built UI components. +:::info[These instructions are only relevant if you are using the pre-built UI components.] ::: - - + + -```tsx preview="/img/emailpassword/password-manager.png" previewAlt="Demo of a password manager working with prebuilt UI when shadow DOM is not active" +```tsx import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ @@ -42,12 +31,11 @@ SuperTokens.init({ }); ``` - - + + -```tsx preview="/img/emailpassword/password-manager.png" previewAlt="Demo of a password manager working with prebuilt UI when shadow DOM is not active" +```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { apiDomain: "...", @@ -59,24 +47,21 @@ supertokensUIInit({ }); ``` - - + + - -:::caution -- SuperTokens uses a special attribute to define its styling. Disabling shadow DOM should not impact the rest of your application's styles. Verify that your CSS does not impact how SuperTokens UI appears when disabling Shadow DOM. +:::warning[- SuperTokens uses a special attribute to define its styling. Disabling shadow DOM should not impact the rest of your application's styles. Verify that your CSS does not impact how SuperTokens UI appears when disabling Shadow DOM.] - Shadow DOM is always disabled with Internet Explorer since it does not support it. Similarly, if you intend to support Internet Explorer for your application make sure to verify how SuperTokens UI appears. ::: - ## See also - - - - - - - + + + + + + + diff --git a/docs/authentication/email-password/password-reset.mdx b/docs/authentication/email-password/password-reset.mdx index 90cd2219a4..419914097f 100644 --- a/docs/authentication/email-password/password-reset.mdx +++ b/docs/authentication/email-password/password-reset.mdx @@ -1,17 +1,10 @@ --- title: Password reset -hide_title: true -sidebar_position: 7 description: Learn how the password reset functionality works -page_type: guide -recipe: emailpassword -category: email-password +sidebar: + order: 7 --- - -# Password reset - - ## Overview The password reset feature consists of two actions: one in which a user requests a reset password link over email and another where the user sets the new password. @@ -19,38 +12,38 @@ The password reset feature consists of two actions: one in which a user requests ### The password reset forms - + - + The following images show how the password reset forms render when you are using the pre-built UI. - + - + -You see this if you navigate to `^{appInfo.websiteBasePath}/reset-password`. +You see this if you navigate to `/auth/reset-password`. - -UI to send password reset email - +
+UI to send password reset email +
-
+ - + You see this if you navigate to `/auth/reset-password?token=TOKEN`. - -UI to change password - - +
+UI to change password +
+
-
+ - + To implement your own interface create two different forms: - One where the user requests a password reset link. @@ -59,16 +52,16 @@ To implement your own interface create two different forms: Use the pre-built UI components as a reference. - + ### The password reset email This is how the email that gets delivered to the learner looks like: -Email UI for password reset email +Email UI for password reset email You can find the [source code of this template on GitHub](https://github.com/supertokens/email-sms-templates/blob/master/email-html/password-reset.html). -To customize the template check the [email delivery](/docs/platform-configuration/email-delivery) section for more information. +To customize the template check the [email delivery](/platform-configuration/email-delivery) section for more information. --- @@ -76,14 +69,14 @@ To customize the template check the [email delivery](/docs/platform-configuratio To embed the reset form in a page you can use the next steps. - + ### 1. Disable the default implementation - - + + -```tsx +```tsx {12,13,14} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; @@ -95,23 +88,19 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start resetPasswordUsingTokenFeature: { disableDefaultUI: true }, - // highlight-end }), ] }); ``` - + - + -```tsx +```tsx {11,12,13} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; supertokensUIInit({ appInfo: { @@ -121,18 +110,16 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailPassword.init({ - // highlight-start resetPasswordUsingTokenFeature: { disableDefaultUI: true }, - // highlight-end }), ] }); ``` - - + + If you navigate to `/auth/reset-password`, you should not see the widget anymore. @@ -141,10 +128,10 @@ If you navigate to `/auth/reset-password`, you should not see the widget anymore Add the `ResetPasswordUsingToken` component in your app: - - + + -```tsx +```tsx {8} import React from "react"; import {ResetPasswordUsingToken} from 'supertokens-auth-react/recipe/emailpassword/prebuiltui'; @@ -152,46 +139,43 @@ class ResetPasswordPage extends React.Component { render() { return (
- // highlight-next-line
) } } ``` -
+ - + -:::caution -You have to build your own UI for this. +:::warning[You have to build your own UI for this.] ::: - -
+ + -
- + + -:::caution -Not applicable since you do not use pre-built UI. +:::warning[Not applicable since you do not use pre-built UI.] ::: - + ### 3. Change the website path for reset password UI This step is optional. -The default path for this is component is `^{appInfo.websiteBasePath}/reset-password`. +The default path for this is component is `/auth/reset-password`. If you are displaying this at some custom path, then you need to add additional configuration on the backend and frontend: #### 3.1 On the backend - - + + -```tsx +```tsx {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; @@ -206,7 +190,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start emailDelivery: { override: (originalImplementation) => { return { @@ -216,7 +199,7 @@ SuperTokens.init({ return originalImplementation.sendEmail({ ...input, passwordResetLink: input.passwordResetLink.replace( - // This is: `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/reset-password` + // This is: `/auth/reset-password` "http://localhost:3000/auth/reset-password", "http://localhost:3000/your/path" ) @@ -227,15 +210,14 @@ SuperTokens.init({ } } } - // highlight-end }) ] }); ``` - - + + -```go +```go {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30} import ( "strings" @@ -250,13 +232,12 @@ func main() { RecipeList: []supertokens.Recipe{ emailpassword.Init(&epmodels.TypeInput{ - //highlight-start EmailDelivery: &emaildelivery.TypeInput{ Override: func(originalImplementation emaildelivery.EmailDeliveryInterface) emaildelivery.EmailDeliveryInterface { ogSendEmail := *originalImplementation.SendEmail (*originalImplementation.SendEmail) = func(input emaildelivery.EmailType, userContext supertokens.UserContext) error { - // This is: `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/reset-password` + // This is: `/auth/reset-password` input.PasswordReset.PasswordResetLink = strings.Replace( input.PasswordReset.PasswordResetLink, "http://localhost:3000/auth/reset-password", @@ -267,17 +248,16 @@ func main() { return originalImplementation }, }, - //highlight-end }), }, }) } ``` - - + + -```python +```python {10,11,12,13,14} from supertokens_python import init, InputAppInfo from supertokens_python.recipe.emailpassword.types import EmailDeliveryOverrideInput, EmailTemplateVars from supertokens_python.recipe import emailpassword @@ -287,20 +267,18 @@ from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConf def custom_email_deliver(original_implementation: EmailDeliveryOverrideInput) -> EmailDeliveryOverrideInput: original_send_email = original_implementation.send_email - # highlight-start async def send_email(template_vars: EmailTemplateVars, user_context: Dict[str, Any]) -> None: - # This is: `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/reset-password` + # This is: `/auth/reset-password` template_vars.password_reset_link = template_vars.password_reset_link.replace( "http://localhost:3000/auth/reset-password", "http://localhost:3000/your/path") return await original_send_email(template_vars, user_context) - # highlight-end original_implementation.send_email = send_email return original_implementation init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( email_delivery=EmailDeliveryConfig(override=custom_email_deliver) @@ -309,17 +287,17 @@ init( ) ``` - - + + #### 3.2 On the frontend - + - - + + -```tsx +```tsx {12,13,14,15,16,17,18} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; @@ -331,7 +309,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - //highlight-start // The user will be taken to the custom path when they click on forgot password. getRedirectionURL: async (context) => { @@ -339,20 +316,17 @@ SuperTokens.init({ return "/custom-reset-password-path"; }; } - //highlight-end }) ] }) ``` - + - + -```tsx +```tsx {11,12,13,14,15,16,17} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; supertokensUIInit({ appInfo: { @@ -362,7 +336,6 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailPassword.init({ - //highlight-start // The user will be taken to the custom path when they click on forgot password. getRedirectionURL: async (context) => { @@ -370,31 +343,29 @@ supertokensUIInit({ return "/custom-reset-password-path"; }; } - //highlight-end }) ] }) ``` - - + + - - + + -:::caution -Not applicable since you do not use pre-built UI. +:::warning[Not applicable since you do not use pre-built UI.] ::: - + ## Generate a reset link manually You can use the backend SDK to generate the reset password link as shown below: - - + + ```tsx import EmailPassword from "supertokens-node/recipe/emailpassword"; @@ -410,8 +381,8 @@ async function createResetPasswordLink(userId: string, email: string) { } ``` - - + + ```go import ( @@ -438,11 +409,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.emailpassword.asyncio import create_reset_password_link @@ -455,8 +426,8 @@ async def create_link(user_id: str, email: str): else: print("user does not exist or is not an email password user") ``` - - + + ```python from supertokens_python.recipe.emailpassword.syncio import create_reset_password_link @@ -470,14 +441,14 @@ def create_link(user_id: str, email: str): print("user does not exist or is not an email password user") ``` - - + + - - + + -:::info Multy-tenancy +:::info[Multy-tenancy] Notice that the first argument to the function call above is `"public"`. This refers to the default tenant ID used in SuperTokens. It means that the generated password reset link can only apply to users belonging to the `"public"` tenant. @@ -493,21 +464,20 @@ Finally, the generated link uses the configured `websiteDomain` from the `appInf By default, the password reset link's lifetime is 1 hour. You can change this via a core's configuration (time in milliseconds): - - + + -```bash +```bash {5} # Here we set the lifetime to 2 hours. docker run \ -p 3567:3567 \ - // highlight-next-line -e EMAIL_VERIFICATION_TOKEN_LIFETIME=7200000 \ -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -516,8 +486,8 @@ docker run \ email_verification_token_lifetime: 7200000 ``` - - + + :::info @@ -529,10 +499,10 @@ email_verification_token_lifetime: 7200000 ## See also - - - - - - - + + + + + + + diff --git a/docs/authentication/enterprise/_blocks/create-tenant.mdx b/docs/authentication/enterprise/_blocks/create-tenant.mdx deleted file mode 100644 index 23502ebadb..0000000000 --- a/docs/authentication/enterprise/_blocks/create-tenant.mdx +++ /dev/null @@ -1,176 +0,0 @@ - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function createNewTenant() { - let resp = await Multitenancy.createOrUpdateTenant("customer1", { - firstFactors: ["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-phone", "link-email"] - }); - - if (resp.createdNew) { - // Tenant created successfully - } else { - // Existing tenant's config was modified. - } -} -``` - -The snippet creates a new tenant with the id `"customer1"`. -It enables the email password, third party and passwordless login methods for this tenant. -You can also disable any of these by not including them in the `firstFactors` input. -If `firstFactors` is not specified, by default, the system does not enable any of the login methods. - -If you set `firstFactors` to `null` the SDK uses any of the login methods. - -The built-in Factor IDs available for `firstFactors` include: - -| Authentication Type | Factor ID | -|-------------------|-----------| -| Email password auth | `emailpassword` | -| Social login / enterprise SSO auth | `thirdparty` | -| Passwordless - Email OTP | `otp-email` | -| Passwordless - SMS OTP | `otp-phone` | -| Passwordless - Email magic link | `link-email` | -| Passwordless - SMS magic link | `link-phone` | - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/multitenancy/multitenancymodels" -) - -func main() { - tenantId := "customer1" - emailPasswordEnabled := true - thirdPartyEnabled := true - passwordlessEnabled := true - - // highlight-start - resp, err := multitenancy.CreateOrUpdateTenant(tenantId, multitenancymodels.TenantConfig{ - EmailPasswordEnabled: &emailPasswordEnabled, - ThirdPartyEnabled: &thirdPartyEnabled, - PasswordlessEnabled: &passwordlessEnabled, - }) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // new tenant was created - } else { - // existing tenant's config was modified. - } -} -``` - -The code snippet creates a new tenant with the id `"customer1"`. -It enables the email password, third party and passwordless login methods for this tenant. -You can also disable any of these by setting the corresponding field to `false`. - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant -from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate - -async def some_func(): - response = await create_or_update_tenant("customer1", TenantConfigCreateOrUpdate( - first_factors=["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-phone", "link-email"] - )) - - if response.status != "OK": - print("Handle error") - elif response.created_new: - print("New tenant was created") - else: - print("Existing tenant's config was updated") -``` - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant -from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate - -def some_func(): - response = create_or_update_tenant("customer1", TenantConfigCreateOrUpdate( - first_factors=["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-phone", "link-email"] - )) - - if response.status != "OK": - print("Handle error") - elif response.created_new: - print("New tenant was created") - else: - print("Existing tenant's config was updated") -``` - - - - -The code snippet creates a new tenant with the id `"customer1"`. -It enables the email password, third party and passwordless login methods for this tenant. -You can also disable any of these by setting the corresponding field to `false`. - - - - - -```bash -curl --location --request PUT 'http://localhost:3567/recipe/multitenancy/tenant/v2' \ ---header 'api-key: YOUR_API_KEY' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "tenantId": "customer1", - "firstFactors": ["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-email", "link-phone"] -}' -``` - -The request includes the `appId` for which you need to create a new tenant. -If you are using the default (`"public"`) app, you can omit the `/appid-` part of the URL. - -The snippet creates a new tenant with the id `"customer1"`. -It enables the email password, third party and passwordless login methods for this tenant. -You can also disable any of these by not including them in the `firstFactors` input. -If `firstFactors` is not specified, by default, the system does not enable any of the login methods. - -The built-in Factor IDs available for `firstFactors` include: - -| Authentication Type | Factor ID | -|-------------------|-----------| -| Email password auth | `emailpassword` | -| Social login / enterprise SSO auth | `thirdparty` | -| Passwordless - Email OTP | `otp-email` | -| Passwordless - SMS OTP | `otp-phone` | -| Passwordless - Email magic link | `link-email` | -| Passwordless - SMS magic link | `link-phone` | - - - - - -Create Tenant - -Create a new tenant by clicking on the **Add Tenant** button and specify the tenant ID. - -All Login Methods Enabled - -Once you create the tenant, turn on the Login Methods as required for the tenant. In the above example, you turn on all the Login Methods. - - - - diff --git a/docs/authentication/enterprise/_blocks/get-tenant.mdx b/docs/authentication/enterprise/_blocks/get-tenant.mdx deleted file mode 100644 index febe702957..0000000000 --- a/docs/authentication/enterprise/_blocks/get-tenant.mdx +++ /dev/null @@ -1,160 +0,0 @@ - - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function getTenant(tenantId: string) { - - // highlight-start - let resp = await Multitenancy.getTenant(tenantId); - // highlight-end - - if (resp === undefined) { - // tenant does not exist - } else { - let coreConfig = resp.coreConfig; - - let firstFactors = resp.firstFactors; - - let configuredThirdPartyProviders = resp.thirdParty.providers; - } -} -``` - - - - -```go -import ( - "fmt" - - "github.com/supertokens/supertokens-golang/recipe/multitenancy" -) - -func main() { - tenantId := "customer1" - - // highlight-start - tenant, err := multitenancy.GetTenant(tenantId) - // highlight-end - - if err != nil { - // handle error - } - if tenant == nil { - // tenant does not exist - } else { - isEmailPasswordLoginEnabled := tenant.EmailPassword.Enabled; - isThirdPartyLoginEnabled := tenant.ThirdParty.Enabled; - isPasswordlessLoginEnabled := tenant.Passwordless.Enabled; - - if (isEmailPasswordLoginEnabled) { - // Tenant support email password login - } - - if (isThirdPartyLoginEnabled) { - // Tenant support third party login - configuredThirdPartyProviders := tenant.ThirdParty.Providers; - fmt.Println(configuredThirdPartyProviders); - } - - if (isPasswordlessLoginEnabled) { - // Tenant support passwordless login - } - } -} -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import get_tenant - -async def some_func(): - tenant = await get_tenant("customer1") - - if tenant is None: - print("tenant does not exist") - else: - core_config = tenant.core_config - first_factors = tenant.first_factors - providers = tenant.third_party_providers - - print(core_config) - print(first_factors) - print(providers) -``` - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import get_tenant - -tenant = get_tenant("customer1") - -if tenant is None: - print("tenant does not exist") -else: - core_config = tenant.core_config - first_factors = tenant.first_factors - providers = tenant.third_party_providers - - print(core_config) - print(first_factors) - print(providers) -``` - - - - - - - - -```bash -curl --location --request GET 'http://localhost:3567/customer1/recipe/multitenancy/tenant/v2' \ ---header 'api-key: YOUR_API_KEY' \ ---header 'Content-Type: application/json' -``` - -Notice that you add `customer1` to the path of the request. This tells the core that the tenant you want to get the information about is `customer1` (the one created before in this page). - -If the input tenant does not exist, you get back a `200` status code with the following JSON: - -```json -{"status": "TENANT_NOT_FOUND_ERROR"} -``` - -Otherwise you get a `200` status code with the following JSON output: - -```json -{ - "status": "OK", - "thirdParty": { - "providers": [...] - }, - "coreConfig": { - "email_verification_token_lifetime": 7200000, - "password_reset_token_lifetime": 3600000, - "postgresql_connection_uri": "postgresql://localhost:5432/db2" - }, - "tenantId": "customer1", - "firstFactors": ["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-email", "link-phone"] -} -``` - - - - - -The returned `coreConfig` is the same as what you set when creating / updating the tenant. The rest of the core configurations for this tenant inherit from the app's (or the `public` tenant) configuration. The `public` tenant, for the `public` app inherits its configurations from the `config.yaml` / docker environment variables values. diff --git a/docs/authentication/enterprise/_blocks/paid-feature-banner.mdx b/docs/authentication/enterprise/_blocks/paid-feature-banner.mdx deleted file mode 100644 index fb93304c11..0000000000 --- a/docs/authentication/enterprise/_blocks/paid-feature-banner.mdx +++ /dev/null @@ -1,9 +0,0 @@ -:::warning Paid Feature - -This is a paid feature. - -For self hosted users, [Sign up](https://supertokens.com/auth) to get a license key and follow the instructions sent to you by email. Creation of tenants is free on the `dev` license key. - -This feature is already enabled for managed service users. Creation of additional tenant is free on the provided development environment. - -::: \ No newline at end of file diff --git a/docs/authentication/enterprise/_blocks/update-tenant-config.mdx b/docs/authentication/enterprise/_blocks/update-tenant-config.mdx deleted file mode 100644 index f9e5abfb75..0000000000 --- a/docs/authentication/enterprise/_blocks/update-tenant-config.mdx +++ /dev/null @@ -1,192 +0,0 @@ - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function createNewTenant() { - - // highlight-start - let resp = await Multitenancy.createOrUpdateTenant("customer1", { - coreConfig: { - "email_verification_token_lifetime": 7200000, - "password_reset_token_lifetime": 3600000, - "postgresql_connection_uri": "postgresql://localhost:5432/db2", - } - }); - // highlight-end - - if (resp.createdNew) { - // new tenant was created - } else { - // existing tenant's config was modified. - } -} -``` - -In the above example, the system assigns different values for certain configurations for `customer1` tenant. -All other configurations inherit from the base configuration. - -Notice the `postgresql_connection_uri`. -This allows you to achieve **data isolation on a tenant level**. -This configuration is not required. -If not provided, the database stores the tenant's information as specified in the core's configuration. -It is still a different user pool though. - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/multitenancy/multitenancymodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateTenant(tenantId, multitenancymodels.TenantConfig{ - CoreConfig: map[string]interface{}{ - "email_verification_token_lifetime": 7200000, - "password_reset_token_lifetime": 3600000, - "postgresql_connection_uri": "postgresql://localhost:5432/db2", - }, - }) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // new tenant was created - } else { - // existing tenant's config was modified. - } -} -``` - -In the above example, the system assigns different values for certain configurations for `customer1` tenant. -All other configurations inherit from the base configuration. - -Notice the `postgresql_connection_uri`. -This allows you to achieve **data isolation on a tenant level**. -This configuration is not required. -If not provided, the database stores the tenant's information as specified in the core's configuration. -It is still a different user pool though. - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant -from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_tenant(tenant_id, TenantConfigCreateOrUpdate( - core_config={ - "email_verification_token_lifetime": 7200000, - "password_reset_token_lifetime": 3600000, - "postgresql_connection_uri": "postgresql://localhost:5432/db2", - }, - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("new tenant created") - else: - print("existing tenant's config was modified.") -``` - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant -from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate - -tenant_id = "customer1" -result = create_or_update_tenant(tenant_id, TenantConfigCreateOrUpdate( - core_config={ - "email_verification_token_lifetime": 7200000, - "password_reset_token_lifetime": 3600000, - "postgresql_connection_uri": "postgresql://localhost:5432/db2", - }, -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("new tenant created") -else: - print("existing tenant's config was modified.") -``` - - - - -In the above example, the system assigns different values for certain configurations for `customer1` tenant. -All other configurations inherit from the base configuration. - -Notice the `postgresql_connection_uri`. -This allows you to achieve **data isolation on a tenant level**. -This configuration is not required. -If not provided, the database stores the tenant's information as specified in the core's configuration. -It is still a different user pool though. - - - - - - -```bash -curl --location --request PUT 'http://localhost:3567/recipe/multitenancy/tenant/v2' \ ---header 'api-key: YOUR_API_KEY' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "tenantId": "customer1", - "coreConfig": { - "email_verification_token_lifetime": 7200000, - "password_reset_token_lifetime": 3600000, - "postgresql_connection_uri": "postgresql://localhost:5432/db2" - } -}' -``` - -In the above example, the system assigns different values for certain configurations for `customer1` tenant. -All other configurations inherit from the base configuration. - -Notice the `postgresql_connection_uri`. -This allows you to achieve **data isolation on a tenant level**. -This configuration is not required. -If not provided, the database stores the tenant's information as specified in the core's configuration. -It is still a different user pool though. - - - - - -Custom tenant configuration - - -In the above example, the system assigns different values for certain configurations for `customer1` tenant. -All other configurations inherit from the base configuration. -You can edit the values by clicking on the pencil icon and then specifying a new value. - -:::caution - -You cannot edit database connection settings directly from the Dashboard, and you may need to use the SDK or cURL to update them. - -::: - - - - diff --git a/docs/authentication/enterprise/_category_.json b/docs/authentication/enterprise/_category_.json deleted file mode 100644 index aa8107cd25..0000000000 --- a/docs/authentication/enterprise/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Enterprise Login", - "position": 5 -} diff --git a/docs/authentication/enterprise/common-domain-login.mdx b/docs/authentication/enterprise/common-domain-login.mdx index 13f5eecbb3..7c7de061bc 100644 --- a/docs/authentication/enterprise/common-domain-login.mdx +++ b/docs/authentication/enterprise/common-domain-login.mdx @@ -1,16 +1,10 @@ --- title: Implement common domain login -hide_title: true -toc_max_heading_level: 4 -sidebar_position: 3 description: Authenticate users across different tenants through a common domain. -page_type: guide -recipe: thirdparty -category: enterprise-login +sidebar: + order: 3 --- -# Common domain login - ## Overview This guide shows you how to authenticate users through the same page, `https://example.com/auth`, and then redirect to their sub domain after login. @@ -19,7 +13,7 @@ The login page adjusts the authentication method based on the tenant's configura You can figure out which is the tenant that you are working with through different methods. A common way is to ask the user to enter their organisation name, which is equal to the `tenantId` that you configure in SuperTokens. -:::info Important +:::info[Important] You can find an example app for this setup with the **pre-built UI** on [the GitHub example directory](https://github.com/supertokens/supertokens-auth-react/tree/master/examples/with-one-login-many-subdomains). The app is setup to have three tenants: - `tenant1`: Login with `emailpassword` + Google sign in - `tenant2`: Login with `emailpassword` @@ -36,44 +30,44 @@ npx create-supertokens-app@latest --recipe=multitenancy ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: The tutorial assumes that you already have a working application integrated with **SuperTokens**. -If you have not, please check the [Quickstart Guide](/docs/quickstart/introduction). +If you have not, please check the [Quickstart Guide](/quickstart/introduction). You also need to create the tenants that your application requires. -View the [previous tutorial](/docs/authentication/enterprise/initial-setup) for more information on how to do this. +View the [previous tutorial](/authentication/enterprise/initial-setup) for more information on how to do this. ## Steps ### 1. Ask for the tenant ID on the login page - + - + - -If you have [followed the pre-built UI setup](/docs/quickstart/frontend-setup), when you visit the login screen, you see the login screen immediately. +If you have [followed the pre-built UI setup](/quickstart/frontend-setup), when you visit the login screen, you see the login screen immediately. The flow needs to change to first ask the user to enter their tenant ID and then display the login UI based on the tenant ID. To do that, first obtain the tenant ID from the user. You can achieve this by building a UI that asks them to enter their `tenantId` or Organisation name (which can serve as the tenant ID). This UI builds in a component called `AuthPage`. -:::warning no-title -You have to [create tenants](/docs/authentication/enterprise/initial-setup) before you can complete this step. +:::warning +You have to [create tenants](/authentication/enterprise/initial-setup) before you can complete this step. ::: - + - + - + - + ```tsx import { useState } from "react"; @@ -98,16 +92,16 @@ export const AuthPage = () => { session.doesSessionExist === true || // or an active session (it'll contain the tenantId) new URLSearchParams(location.search).has("tenantId") // or we are on a link (e.g.: email verification) that contains the tenantId ) { - // Since this component (AuthPage) is rendered in the ^{appInfo.websiteBasePath} route in the main Routes component, + // Since this component (AuthPage) is rendered in the /auth route in the main Routes component, // and we are rendering this in a sub route as shown below, the third arg to getSuperTokensRoutesForReactRouterDom - // tells SuperTokens to create Routes without ^{appInfo.websiteBasePath} prefix to them, otherwise they would - // render on ^{appInfo.websiteBasePath}^{form_websiteBasePath} path. + // tells SuperTokens to create Routes without /auth prefix to them, otherwise they would + // render on /auth path. return ( {getSuperTokensRoutesForReactRouterDom( reactRouterDom, [EmailPasswordPreBuiltUI], - "^{appInfo.websiteBasePath}" + "/auth" )} ); @@ -128,8 +122,8 @@ export const AuthPage = () => { }; ``` - - + + ```tsx import { useState } from "react"; @@ -169,46 +163,46 @@ export const AuthPage = () => { }; ``` - - + + The example creates a simple UI renders which asks the user for their organisation's name. Their input serves as their tenant ID. When the user submits that form, the value stores in `localstorage`. -:::info Important -The `AuthPage` component should render to show on `^{appInfo.websiteBasePath}/*` paths of the website. +:::info[Important] +The `AuthPage` component should render to show on `/auth/*` paths of the website. The `AuthPage` replaces the call to `getSuperTokensRoutesForReactRouterDom` or `getRoutingComponent` that you may have added to your app from the quick setup section. ::: - + - + -:::info Caution +:::info[Caution] No code snippet provided here, however, if you visit the auth component, you see that the pre-built UI renders in the `"supertokensui"` `div` element on page load. The logic here needs to change to first check if the user has provided the `tenantId`. If they have, the SuperTokens UI renders as usual. If they have not, a simple UI renders which asks the user for their tenant id and saves that in `localstorage`. Switch to the React code tab here to see the implementation in React, and a similar logic applies here. ::: - + - + - + - + You need to build a UI that asks the user to enter their `tenantId` or Organisation name (which can serve as the tenant ID). The input value is then utilized in function calls, as seen below. Once you have the user's tenant ID, you can fetch their list of configured providers and render the third party login buttons accordingly: - - + + - - + + ```tsx import Multitenancy from 'supertokens-web-js/recipe/multitenancy'; @@ -231,8 +225,8 @@ async function fetchThirdPartyLoginProvidersForTenant(tenantId: string) { } ``` - - + + ```tsx import Multitenancy from 'supertokens-web-js/recipe/multitenancy'; @@ -254,31 +248,30 @@ async function fetchThirdPartyLoginProvidersForTenant(tenantId: string) { } ``` - - + + - In the code snippet above, the login methods for the `tenantId` fetch. - We then render the login UI buttons based on the configured `thirdPartyId`s in the response - + - + - ```bash -curl --location --request GET '^{appInfo.apiDomain}^{appInfo.apiBasePath}/loginmethods' +curl --location --request GET '/auth/loginmethods' ``` The response body from the API call has a `status` property in it: - `status: "OK"`: The `recipes` field contains information about which login methods are active along with the list of third party providers configured for this tenant. - `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should appear on the frontend. - + - + - + ### 2. Include the tenant ID in authentication flow @@ -288,14 +281,14 @@ To do this, set the `getTenantId` function in the `Multitenancy` recipe. In the current example, local storage provides the `tenantId`. - + - + - + -```tsx +```tsx {14,16,17,18,19,20,21,22,23,24,25,26,27,28} import React from 'react'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; @@ -309,10 +302,8 @@ SuperTokens.init({ apiBasePath: "...", websiteBasePath: "..." }, - // highlight-next-line usesDynamicLoginMethods: true, recipeList: [ - // highlight-start Multitenancy.init({ override: { functions: (oI) => { @@ -326,24 +317,21 @@ SuperTokens.init({ } } }) - // highlight-end // other recipes... ] }); ``` -:::info Important +:::info[Important] Set the `usesDynamicLoginMethods` to `true` to tell SuperTokens that the login methods are dynamic (based on the `tenantId`). On page load (of the login page), SuperTokens first fetches the configured login methods for the `tenantId`. It then displays the login UI based on the result of the API call. ::: - + - + -```tsx +```tsx {11,13,14,15,16,17,18,19,20,21,22,23,24,25} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIMultitenancy from "supertokens-auth-react-script/recipe/multitenancy"; supertokensUIInit({ appInfo: { @@ -353,10 +341,8 @@ supertokensUIInit({ apiBasePath: "...", websiteBasePath: "..." }, - // highlight-next-line usesDynamicLoginMethods: true, recipeList: [ - // highlight-start supertokensUIMultitenancy.init({ override: { functions: (oI) => { @@ -370,33 +356,32 @@ supertokensUIInit({ } } }) - // highlight-end // other recipes... ] }); ``` -:::info Important +:::info[Important] Set the `usesDynamicLoginMethods` to `true` to tell SuperTokens that the login methods are dynamic (based on the `tenantId`). On page load (of the login page), SuperTokens first fetches the configured login methods for the `tenantId`. It then displays the login UI based on the result of the API call. ::: - + - + - + - + - - + + Initialize the multi tenancy recipe with the following callback defined. You can get the value of `tenantId` from wherever you had stored it when asking the user for its value. - - + + -```tsx +```tsx {10,11,12,13,14,15,16,17,18,19,20,21,22} import SuperTokens from "supertokens-web-js"; import Multitenancy from "supertokens-web-js/recipe/multitenancy"; @@ -406,7 +391,6 @@ SuperTokens.init({ apiDomain: "...", }, recipeList: [ - // highlight-start Multitenancy.init({ override: { functions: (oI) => { @@ -420,25 +404,21 @@ SuperTokens.init({ } } }) - // highlight-end // other recipes... ] }); ``` - - + + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensMultitenancy from "supertokens-web-js-script/recipe/multitenancy"; +```tsx {7,8,9,10,11,12,13,14,15,16,17,18,19} supertokens.init({ appInfo: { appName: "...", apiDomain: "...", }, recipeList: [ - // highlight-start supertokensMultitenancy.init({ override: { functions: (oI) => { @@ -452,25 +432,23 @@ supertokens.init({ } } }) - // highlight-end // other recipes... ] }); ``` - - + + - + - + -All the steps for mobile app login are similar to the [social login steps](../../custom-ui/thirdparty-login). However, when you are calling the sign in up API, you also need to pass in the `tenantId` in the request path. An example of this appears below: +All the steps for mobile app login are similar to the [social login steps](/authentication/social/initial-setup#2-add-the-login-ui). However, when you are calling the sign in up API, you also need to pass in the `tenantId` in the request path. An example of this appears below: - ```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup' \ +curl --location --request POST '/auth/signinup' \ --header 'Content-Type: application/json' \ --data-raw '{ "thirdPartyId": "...", @@ -482,14 +460,14 @@ curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signi }' ``` - + - + - + -### 3. Redirect users based on tenant subdomain {{optional}} +### 3. Redirect users based on tenant subdomain (optional) If each tenant has access to specific sub domains in your application you need to redirect them after login. @@ -498,11 +476,11 @@ If each tenant has access to specific sub domains in your application you need t Before you perform the actual redirect step, you should restrict which sub domains they have access to. To do this configure the SDK to know which domain each `tenantId` has access to. - + - + -```tsx +```tsx {11,12,13,14,15,16,17} import SuperTokens from "supertokens-node"; import Multitenancy from "supertokens-node/recipe/multitenancy" @@ -513,7 +491,6 @@ SuperTokens.init({ websiteDomain: "..." }, recipeList: [ - // highlight-start Multitenancy.init({ getAllowedDomainsForTenantId: async (tenantId, userContext) => { // query your db to get the allowed domain for the input tenantId @@ -521,16 +498,15 @@ SuperTokens.init({ return [tenantId + ".myapp.com", "myapp.com", "www.myapp.com"] } }), - // highlight-end // other recipes... ] }) ``` - - + + -```go +```go {10,11,12,13,14,15,16} import ( "github.com/supertokens/supertokens-golang/recipe/multitenancy" "github.com/supertokens/supertokens-golang/recipe/multitenancy/multitenancymodels" @@ -540,7 +516,6 @@ import ( func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ - // highlight-start multitenancy.Init(&multitenancymodels.TypeInput{ GetAllowedDomainsForTenantId: func(tenantId string, userContext supertokens.UserContext) ([]string, error) { // query your db to get the allowed domain for the input tenantId @@ -548,14 +523,13 @@ func main() { return []string{tenantId + ".myapp.com", "myapp.com", "www.myapp.com"}, nil }, }), - // highlight-end }, }) } ``` - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -583,25 +557,25 @@ init( ) ``` - + - + The code sample tells SuperTokens to add the list of domains into the user's session claims once they login. This claim then becomes accessible on the frontend and backend to restrict user's access to the right domain(s). #### 3.2 Redirect the user to their sub domain after sign in - + On the frontend side, post sign in, by default, the frontend SDK redirects the user to the `/` route. Can change this to instead redirect them to their sub domain based on their `tenantId`. - + - + -```tsx +```tsx {11,12,13,14,15,16,17,18,19,20,21,22,23,24} import SuperTokens from "supertokens-auth-react"; import Session from "supertokens-auth-react/recipe/session"; import Multitenancy from "supertokens-auth-react/recipe/multitenancy"; @@ -612,7 +586,6 @@ SuperTokens.init({ appName: "...", websiteDomain: "...", }, - // highlight-start getRedirectionURL: async (context) => { if (context.action === "SUCCESS" && context.newSessionCreated) { let claimValue: string[] | undefined = await Session.getClaimValue({ @@ -627,20 +600,16 @@ SuperTokens.init({ } return undefined; }, - // highlight-end recipeList: [ /* Recipe init here... */ ] }); ``` - + - + -```tsx +```tsx {9,10,11,12,13,14,15,16,17,18,19,20,21,22} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; -import supertokensUIMultitenancy from "supertokens-auth-react-script/recipe/multitenancy"; supertokensUIInit({ appInfo: { @@ -648,7 +617,6 @@ supertokensUIInit({ appName: "...", websiteDomain: "...", }, - // highlight-start getRedirectionURL: async (context) => { if (context.action === "SUCCESS" && context.newSessionCreated) { let claimValue: string[] | undefined = await supertokensUISession.getClaimValue({ @@ -663,23 +631,22 @@ supertokensUIInit({ } return undefined; }, - // highlight-end recipeList: [ /* Recipe init here... */ ] }); ``` - + - + - + - + On the frontend, once the user has completed login, you can read the domain that they have access to (from their session) and redirect them accordingly. - - + + ```tsx import Session from "supertokens-web-js/recipe/session"; @@ -702,12 +669,10 @@ async function redirectToSubDomain() { } ``` - - + + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensMultitenancy from "supertokens-web-js-script/recipe/multitenancy"; async function redirectToSubDomain() { if (await supertokensSession.doesSessionExist()) { let claimValue: string[] | undefined = await supertokensSession.getClaimValue({ @@ -725,24 +690,24 @@ async function redirectToSubDomain() { } ``` - - + + - + - The `AllowedDomainsClaim` claim is auto added to the session by the backend SDK if you provide the `GetAllowedDomainsForTenantId` configuration from the previous step. - This claim contains a list of domains that this user can access, based on their tenant ID. -### 6. Share sessions across sub domains {{optional}} +### 6. Share sessions across sub domains (optional) If the user authenticates into your main website domain (`https://example.com/auth`), and redirects to a sub domain, the session recipe needs updating. It should allow sharing of sessions across sub domains. -You can do this [by setting the `sessionTokenFrontendDomain` value in the Session recipe](/docs/post-authentication/session-management/share-session-across-sub-domains). +You can do this [by setting the `sessionTokenFrontendDomain` value in the Session recipe](/post-authentication/session-management/share-session-across-sub-domains). -If the sub domains assigned to your tenants have their own backend on a separate sub domain (one per tenant), you can also enable [sharing of sessions across API domains](/docs/post-authentication/session-management/advanced-workflows/multiple-api-endpoints). +If the sub domains assigned to your tenants have their own backend on a separate sub domain (one per tenant), you can also enable [sharing of sessions across API domains](/post-authentication/session-management/advanced-workflows/multiple-api-endpoints). -### 7. Limit user access to their sub domain. {{optional}} +### 7. Limit user access to their sub domain. (optional) The frontend uses session claim validators to restrict sub domain access. Before proceeding, make sure that you define the `GetAllowedDomainsForTenantId` function mentioned above. @@ -753,11 +718,11 @@ If not, they should redirect to the right sub domain. You can achieve this by using the `hasAccessToCurrentDomain` session validator from the multi tenancy recipe. - + - + - + ```tsx import React from "react"; @@ -784,11 +749,11 @@ Session.init({ }, }) ``` -Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever a route requires protection](/docs/additional-verification/session-verification/protect-frontend-routes), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). +Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever a route requires protection](/additional-verification/session-verification/protect-frontend-routes), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: @@ -796,8 +761,6 @@ This change is in your auth route configuration. ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; -import supertokensMultitenancy from "supertokens-web-js-script/recipe/multitenancy"; supertokensUISession.init({ override: { @@ -846,18 +809,18 @@ Session.init({ }) ``` -Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever a route requires protection](../sessions/protecting-frontend-routes), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). +Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever a route requires protection](/additional-verification/session-verification/protect-frontend-routes), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). - + - + - + - + - - + + ```tsx import Session from 'supertokens-web-js/recipe/session'; @@ -884,12 +847,10 @@ Session.init({ }) ``` - - + + ```tsx -import supertokensSession from 'supertokens-web-js-script/recipe/session'; -import supertokensMultitenancy from 'supertokens-web-js-script/recipe/multitenancy'; supertokensSession.init({ override: { functions: (oI) => ({ @@ -911,22 +872,22 @@ supertokensSession.init({ }) ``` - - + + -Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever a route requires protection](../sessions/protecting-frontend-routes#verifying-the-claims-of-a-session--cust), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). +Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever a route requires protection](/additional-verification/session-verification/protect-frontend-routes#check-the-claims-of-a-session), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). - + --- ## See also - - - - - - - + + + + + + + diff --git a/docs/authentication/enterprise/important-concepts.mdx b/docs/authentication/enterprise/important-concepts.mdx index 910b6ac402..06305760bd 100644 --- a/docs/authentication/enterprise/important-concepts.mdx +++ b/docs/authentication/enterprise/important-concepts.mdx @@ -1,15 +1,10 @@ --- -hide_title: true -sidebar_position: 2 title: Important concepts description: Understand multi-tenant architecture with SuperTokens -page_type: guide -recipe: thirdparty -category: enterprise-login +sidebar: + order: 2 --- -# Important concepts - ## Overview [Multitenancy](https://supertokens.com/features/multi-tenancy) is a way to organize your application to support multiple groups of users who share a common access with to an application. @@ -68,27 +63,27 @@ Based on the above abstractions you can choose between four different setup type The default use case when you are not making use of the multi tenancy feature. -![Single tenant single app architecture](/img/single-tenant-single-app.png) +![Single tenant single app architecture](/docs/img/single-tenant-single-app.png) ### Single tenant, multi app This is where you have multiple applications running on the same SuperTokens core instance and each application has a single user pool. This could be two different apps in your organization, or two different development environments for the same app (or some combination of this). -![Single tenant multi app architecture](/img/single-tenant-multi-app.png) +![Single tenant multi app architecture](/docs/img/single-tenant-multi-app.png) ### Multi tenant, single app Different customers use the same application, but each customer has their own set of users and login methods (each customer is a unique tenant in SuperTokens). -![Multi tenant single app architecture](/img/multi-tenant-single-app.png) +![Multi tenant single app architecture](/docs/img/multi-tenant-single-app.png) ### Multi tenant, multi app Multiple applications run on the same **SuperTokens** core instance, and each application has its own set of tenants. This could be two different applications in your organization, or two different development environments for the same application (or some combination of this). -![Multi tenant multi app architecture](/img/multi-tenant-multi-app.png) +![Multi tenant multi app architecture](/docs/img/multi-tenant-multi-app.png) In a multi app, multi tenant setup: A user can be uniquely recognized by their `appId` -> `userId`. This allows the same user to share across tenants (if you want that to happen). diff --git a/docs/authentication/enterprise/initial-setup.mdx b/docs/authentication/enterprise/initial-setup.mdx index a52456a371..0c791c7591 100644 --- a/docs/authentication/enterprise/initial-setup.mdx +++ b/docs/authentication/enterprise/initial-setup.mdx @@ -1,28 +1,17 @@ --- title: Initial setup -hide_title: true -sidebar_position: 2 -toc_max_heading_level: 4 description: Create your first tenant and configure authentication on it. -page_type: tutorial -recipe: thirdparty -category: enterprise-login +sidebar: + order: 2 --- - -import CreateTenantBlock from "./_blocks/create-tenant.mdx"; -import UpdateTenantConfigBlock from "./_blocks/update-tenant-config.mdx"; -import GetTenantBlock from "./_blocks/get-tenant.mdx"; - -import AddProviderConfigurationBlock from "../social/_blocks/multi-tenant-provider-config-active-directory.mdx" - -# Initial setup - ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: -These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction). +These instructions assume that you already have gone through the main [quickstart guide](/quickstart/introduction). If you have skipped that page please follow the tutorial and return here once you're done. ## Steps @@ -35,44 +24,647 @@ The `tenantId` could be that tenant's sub domain, or a workspace URL, or anythin The configuration mapped to each tenant contains information about which login methods they enable. - + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function createNewTenant() { + let resp = await Multitenancy.createOrUpdateTenant("customer1", { + firstFactors: ["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-phone", "link-email"] + }); + + if (resp.createdNew) { + // Tenant created successfully + } else { + // Existing tenant's config was modified. + } +} +``` + +The snippet creates a new tenant with the id `"customer1"`. +It enables the email password, third party and passwordless login methods for this tenant. +You can also disable any of these by not including them in the `firstFactors` input. +If `firstFactors` is not specified, by default, the system does not enable any of the login methods. + +If you set `firstFactors` to `null` the SDK uses any of the login methods. + +The built-in Factor IDs available for `firstFactors` include: + +| Authentication Type | Factor ID | +|-------------------|-----------| +| Email password auth | `emailpassword` | +| Social login / enterprise SSO auth | `thirdparty` | +| Passwordless - Email OTP | `otp-email` | +| Passwordless - SMS OTP | `otp-phone` | +| Passwordless - Email magic link | `link-email` | +| Passwordless - SMS magic link | `link-phone` | + + + + +```go {12,13,14,15,16} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/multitenancy/multitenancymodels" +) + +func main() { + tenantId := "customer1" + emailPasswordEnabled := true + thirdPartyEnabled := true + passwordlessEnabled := true + + resp, err := multitenancy.CreateOrUpdateTenant(tenantId, multitenancymodels.TenantConfig{ + EmailPasswordEnabled: &emailPasswordEnabled, + ThirdPartyEnabled: &thirdPartyEnabled, + PasswordlessEnabled: &passwordlessEnabled, + }) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // new tenant was created + } else { + // existing tenant's config was modified. + } +} +``` + +The code snippet creates a new tenant with the id `"customer1"`. +It enables the email password, third party and passwordless login methods for this tenant. +You can also disable any of these by setting the corresponding field to `false`. + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant +from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate + +async def some_func(): + response = await create_or_update_tenant("customer1", TenantConfigCreateOrUpdate( + first_factors=["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-phone", "link-email"] + )) + + if response.status != "OK": + print("Handle error") + elif response.created_new: + print("New tenant was created") + else: + print("Existing tenant's config was updated") +``` + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant +from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate + +def some_func(): + response = create_or_update_tenant("customer1", TenantConfigCreateOrUpdate( + first_factors=["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-phone", "link-email"] + )) + + if response.status != "OK": + print("Handle error") + elif response.created_new: + print("New tenant was created") + else: + print("Existing tenant's config was updated") +``` + + + + +The code snippet creates a new tenant with the id `"customer1"`. +It enables the email password, third party and passwordless login methods for this tenant. +You can also disable any of these by setting the corresponding field to `false`. + + + + + +```bash +curl --location --request PUT 'http://localhost:3567/recipe/multitenancy/tenant/v2' \ +--header 'api-key: YOUR_API_KEY' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "tenantId": "customer1", + "firstFactors": ["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-email", "link-phone"] +}' +``` + +The request includes the `appId` for which you need to create a new tenant. +If you are using the default (`"public"`) app, you can omit the `/appid-` part of the URL. + +The snippet creates a new tenant with the id `"customer1"`. +It enables the email password, third party and passwordless login methods for this tenant. +You can also disable any of these by not including them in the `firstFactors` input. +If `firstFactors` is not specified, by default, the system does not enable any of the login methods. + +The built-in Factor IDs available for `firstFactors` include: + +| Authentication Type | Factor ID | +|-------------------|-----------| +| Email password auth | `emailpassword` | +| Social login / enterprise SSO auth | `thirdparty` | +| Passwordless - Email OTP | `otp-email` | +| Passwordless - SMS OTP | `otp-phone` | +| Passwordless - Email magic link | `link-email` | +| Passwordless - SMS magic link | `link-phone` | + + + + + +Create Tenant + +Create a new tenant by clicking on the **Add Tenant** button and specify the tenant ID. + +All Login Methods Enabled + +Once you create the tenant, turn on the Login Methods as required for the tenant. In the above example, you turn on all the Login Methods. + + + + #### Configure third party providers If you are using the `thirdparty` recipe on a tenant, you also need to set the providers that you want to use with it. -There's an extensive list of [built-in providers](/docs/authentication/social/built-in-providers-config), but you can also configure [a custom provider](/docs/authentication/enterprise/manage-tenants). +There's an extensive list of [built-in providers](/authentication/social/built-in-providers-config), but you can also configure [a custom provider](/authentication/enterprise/manage-tenants). The next code snippet shows how you can add an Active Directory login to your tenant. Update the `clientId`, `clientSecret`, and `directoryId` based on your tenant configuration. - + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "active-directory", + name: "Active Directory", + clients: [{ + clientId: "...", + clientSecret: "...", + }], + oidcDiscoveryEndpoint: "https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18,19} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "active-directory", + Name: "Active Directory", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + }, + }, + OIDCDiscoveryEndpoint: "https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="active-directory", + name="Active Directoy", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + oidc_discovery_endpoint="https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + ### 2. Provide additional configuration per tenant You can also configure a tenant to use different settings. The next sample shows you how to customize the values. - + + + + +```tsx {5,6,7,8,9,10,11} +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function createNewTenant() { + + let resp = await Multitenancy.createOrUpdateTenant("customer1", { + coreConfig: { + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2", + } + }); + + if (resp.createdNew) { + // new tenant was created + } else { + // existing tenant's config was modified. + } +} +``` + +In the above example, the system assigns different values for certain configurations for `customer1` tenant. +All other configurations inherit from the base configuration. + +Notice the `postgresql_connection_uri`. +This allows you to achieve **data isolation on a tenant level**. +This configuration is not required. +If not provided, the database stores the tenant's information as specified in the core's configuration. +It is still a different user pool though. + + + + +```go {9,10,11,12,13,14,15} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/multitenancy/multitenancymodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateTenant(tenantId, multitenancymodels.TenantConfig{ + CoreConfig: map[string]interface{}{ + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2", + }, + }) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // new tenant was created + } else { + // existing tenant's config was modified. + } +} +``` + +In the above example, the system assigns different values for certain configurations for `customer1` tenant. +All other configurations inherit from the base configuration. + +Notice the `postgresql_connection_uri`. +This allows you to achieve **data isolation on a tenant level**. +This configuration is not required. +If not provided, the database stores the tenant's information as specified in the core's configuration. +It is still a different user pool though. + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant +from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_tenant(tenant_id, TenantConfigCreateOrUpdate( + core_config={ + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2", + }, + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("new tenant created") + else: + print("existing tenant's config was modified.") +``` + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant +from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate + +tenant_id = "customer1" +result = create_or_update_tenant(tenant_id, TenantConfigCreateOrUpdate( + core_config={ + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2", + }, +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("new tenant created") +else: + print("existing tenant's config was modified.") +``` + + + + +In the above example, the system assigns different values for certain configurations for `customer1` tenant. +All other configurations inherit from the base configuration. + +Notice the `postgresql_connection_uri`. +This allows you to achieve **data isolation on a tenant level**. +This configuration is not required. +If not provided, the database stores the tenant's information as specified in the core's configuration. +It is still a different user pool though. + + + + + + +```bash +curl --location --request PUT 'http://localhost:3567/recipe/multitenancy/tenant/v2' \ +--header 'api-key: YOUR_API_KEY' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "tenantId": "customer1", + "coreConfig": { + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2" + } +}' +``` + +In the above example, the system assigns different values for certain configurations for `customer1` tenant. +All other configurations inherit from the base configuration. + +Notice the `postgresql_connection_uri`. +This allows you to achieve **data isolation on a tenant level**. +This configuration is not required. +If not provided, the database stores the tenant's information as specified in the core's configuration. +It is still a different user pool though. + + + + + +Custom tenant configuration + + +In the above example, the system assigns different values for certain configurations for `customer1` tenant. +All other configurations inherit from the base configuration. +You can edit the values by clicking on the pencil icon and then specifying a new value. + +:::warning[You cannot edit database connection settings directly from the Dashboard, and you may need to use the SDK or cURL to update them.] + +::: + + + + ### 3. View tenant details To view the configuration for a specific tenant you can use an SDK method or call the API directly. - + + + + +```tsx {5} +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function getTenant(tenantId: string) { + + let resp = await Multitenancy.getTenant(tenantId); + + if (resp === undefined) { + // tenant does not exist + } else { + let coreConfig = resp.coreConfig; + + let firstFactors = resp.firstFactors; + + let configuredThirdPartyProviders = resp.thirdParty.providers; + } +} +``` + + + + +```go {10} +import ( + "fmt" + + "github.com/supertokens/supertokens-golang/recipe/multitenancy" +) + +func main() { + tenantId := "customer1" + + tenant, err := multitenancy.GetTenant(tenantId) + + if err != nil { + // handle error + } + if tenant == nil { + // tenant does not exist + } else { + isEmailPasswordLoginEnabled := tenant.EmailPassword.Enabled; + isThirdPartyLoginEnabled := tenant.ThirdParty.Enabled; + isPasswordlessLoginEnabled := tenant.Passwordless.Enabled; + + if (isEmailPasswordLoginEnabled) { + // Tenant support email password login + } + + if (isThirdPartyLoginEnabled) { + // Tenant support third party login + configuredThirdPartyProviders := tenant.ThirdParty.Providers; + fmt.Println(configuredThirdPartyProviders); + } + + if (isPasswordlessLoginEnabled) { + // Tenant support passwordless login + } + } +} +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import get_tenant + +async def some_func(): + tenant = await get_tenant("customer1") + + if tenant is None: + print("tenant does not exist") + else: + core_config = tenant.core_config + first_factors = tenant.first_factors + providers = tenant.third_party_providers + + print(core_config) + print(first_factors) + print(providers) +``` + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import get_tenant + +tenant = get_tenant("customer1") + +if tenant is None: + print("tenant does not exist") +else: + core_config = tenant.core_config + first_factors = tenant.first_factors + providers = tenant.third_party_providers + + print(core_config) + print(first_factors) + print(providers) +``` + + + + + + + + +```bash +curl --location --request GET 'http://localhost:3567/customer1/recipe/multitenancy/tenant/v2' \ +--header 'api-key: YOUR_API_KEY' \ +--header 'Content-Type: application/json' +``` + +Notice that you add `customer1` to the path of the request. This tells the core that the tenant you want to get the information about is `customer1` (the one created before in this page). + +If the input tenant does not exist, you get back a `200` status code with the following JSON: + +```json +{"status": "TENANT_NOT_FOUND_ERROR"} +``` + +Otherwise you get a `200` status code with the following JSON output: + +```json +{ + "status": "OK", + "thirdParty": { + "providers": [...] + }, + "coreConfig": { + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2" + }, + "tenantId": "customer1", + "firstFactors": ["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-email", "link-phone"] +} +``` + + + + + +The returned `coreConfig` is the same as what you set when creating / updating the tenant. The rest of the core configurations for this tenant inherit from the app's (or the `public` tenant) configuration. The `public` tenant, for the `public` app inherits its configurations from the `config.yaml` / docker environment variables values. ### 4. Set up the user interface To allow users to authenticate using one of your previously created tenants you need to update your frontend application. -You can do this in two ways: [through a common domain](/docs/authentication/enterprise/common-domain-login), [through subdomains](/docs/authentication/enterprise/subdomain-login). +You can do this in two ways: [through a common domain](/authentication/enterprise/common-domain-login), [through subdomains](/authentication/enterprise/subdomain-login). Explore the two guides for a full list of instructions on how to implement the flows. ## See also - - - - - - - + + + + + + + diff --git a/docs/authentication/enterprise/introduction.mdx b/docs/authentication/enterprise/introduction.mdx index 4763efe0fc..1fb47ce4e6 100644 --- a/docs/authentication/enterprise/introduction.mdx +++ b/docs/authentication/enterprise/introduction.mdx @@ -1,19 +1,10 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -skip_llms_txt: true -description: >- - Explore how you can implement enterprise authentication flows with - SuperTokens. -page_type: overview -recipe: thirdparty -category: enterprise-login +description: Explore how you can implement enterprise authentication flows with SuperTokens. +sidebar: + order: 1 --- -# Enterprise login - - ## Overview **SuperTokens** covers enterprise authentication scenarios through the **multi-tenancy** feature. @@ -39,7 +30,9 @@ The application would then route the user to their specific tenant, which could ## Prerequisites - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: ## Getting started @@ -50,69 +43,34 @@ Choose between the common domain login and subdomain login methods, based on you Before you explore the guides, read through the **Important concepts** page first. It explains how multi tenancy works in more detail. - - - - Important concepts - - - Go through a reference guide that explains all the multi-tenancy related concepts that are specific to SuperTokens. - - - - - Initial setup - - - Create a new tenant and configure the login methods on it. - - - - - - Implement common domain login - - - Allow tenants to login using the same domain. - - - - - Implement subdomain login - - - Allow tenants to login using different subdomains. - - - + + +Go through a reference guide that explains all the multi-tenancy related concepts that are specific to SuperTokens. + + +Create a new tenant and configure the login methods on it. + + + +Allow tenants to login using the same domain. + + +Allow tenants to login using different subdomains. + + ## Customization To adjust the functionality to fit your use case you can explore different sections from the documentation. - - - - Manage tenants - - - Discover all the common actions that you can perform on tenants. - - - - - Manage apps - - - Discover all the common actions that you can perform on applications. - - - - - SAML - - - See how you can implement SAML login. - - - + + +Discover all the common actions that you can perform on tenants. + + +Discover all the common actions that you can perform on applications. + + +See how you can implement SAML login. + + diff --git a/docs/authentication/enterprise/legacy-saml.mdx b/docs/authentication/enterprise/legacy-saml.mdx index 14693a3c7d..932455b6d5 100644 --- a/docs/authentication/enterprise/legacy-saml.mdx +++ b/docs/authentication/enterprise/legacy-saml.mdx @@ -1,25 +1,16 @@ --- title: Legacy SAML -hide_title: true -sidebar_position: 11 -description: >- - Learn how SAML facilitates secure information exchange between authentication - servers and client applications. -page_type: guide -recipe: thirdparty -category: enterprise-login +description: Learn how SAML facilitates secure information exchange between authentication servers and client applications. +sidebar: + order: 11 --- -# Legacy SAML - - ## Overview The following guide shows you how to configure SAML using the legacy setup with SuperTokens. -:::warning no-title -Since version `11.3` of the core service you can use SuperTokens as a SAML client. -We recommend that you use the latest version with [the simplified setup](/docs/authentication/enterprise/saml). +:::warning[Since version `11.3` of the core service you can use SuperTokens as a SAML client.] +We recommend that you use the latest version with [the simplified setup](/authentication/enterprise/saml). ::: ### BoxyHQ @@ -36,7 +27,7 @@ Self hosted SuperTokens only supports PostgreSQL as a data source. The HTTP service uses NodeJS, and is embeddable within your NodeJS backend. However, because SuperTokens supports multiple backends, the focus is on deploying `SAML` Jackson as a microservice. -Flowchart of integrating a `SAML` provider with SuperTokens using `SAML` Jackson ( BoxyHQ ) +Flowchart of integrating a `SAML` provider with SuperTokens using `SAML` Jackson ( BoxyHQ ) 1. The user clicks on the login button and redirects to `SAML` Jackson's microservice at `http://localhost:5225/api/oauth/authorize` 2. `SAML` Jackson redirects the user to the `SAML` provider's login page where the user needs to enter their credentials @@ -47,20 +38,18 @@ However, because SuperTokens supports multiple backends, the focus is on deployi 7. SuperTokens' backend `SDK` creates a new user in the core associated with the end user's email. New session tokens are also created 8. A SuperTokens' session establishes between your app's backend and frontend - logging in the user. -:::info Example App +:::info[Example App] An [example app on GitHub](https://github.com/supertokens/jackson-supertokens-express) with SuperTokens + `SAML` Jackson, for React and NodeJS express apps, is available. This uses [mocksaml.com](https://mocksaml.com/) as a `SAML` provider ::: ## Before you start These instructions assume that you already are familiar with **SuperTokens** and you have configured a demo application. -If you have skipped those steps page please go through the main [quickstart guide](/docs/quickstart/introduction). +If you have skipped those steps page please go through the main [quickstart guide](/quickstart/introduction). ## Using the SuperTokens dashboard -:::caution - -This is only available with Node and Python SDKs. +:::warning[This is only available with Node and Python SDKs.] ::: @@ -88,7 +77,7 @@ docker run \ This starts the SAML Jackson server on `http://localhost:5225`. -:::important +:::note If you are using the SuperTokens managed service, Boxy HQ hosts the server for you ([contact support](mailto:support@supertokens.com) to activate your instance). @@ -96,30 +85,29 @@ If you are using the SuperTokens managed service, Boxy HQ hosts the server for y ### 3. Create a new tenant in SuperTokens (if not done already) -Create Tenant +Create Tenant ### 4. Configure the SAML provider for the tenant -Create Tenant +Create Tenant To configure SAML login with SuperTokens, ensure that you use the correct provider name in the third-party configuration. Make sure to specify provider name with one of the following: -- Microsoft Entra ID
-- Microsoft AD FS
-- Okta
-- Auth0
-- Google
-- OneLogin
-- PingOne
-- JumpCloud
-- Rippling
-- SAML
+- Microsoft Entra ID
+- Microsoft AD FS
+- Okta
+- Auth0
+- Google
+- OneLogin
+- PingOne
+- JumpCloud
+- Rippling
+- SAML
Make sure to replace `http://localhost:5225` with the correct value for where you have hosted the BoxyHQ server. If you are using the SuperTokens managed service, Boxy HQ hosts the server for you ([contact support](mailto:support@supertokens.com) to activate your instance). -:::success -You have successfully configured a new tenant in SuperTokens. The next step is to wire up the frontend SDK to show the right login UI for this tenant. The specifics of this step depend on the UX that you want to provide to your users. The "Common UX flows" section documents two common UX flows. +:::success[You have successfully configured a new tenant in SuperTokens. The next step is to wire up the frontend SDK to show the right login UI for this tenant. The specifics of this step depend on the UX that you want to provide to your users. The "Common UX flows" section documents two common UX flows.] ::: ### 5. Adding multiple SAML connections to a single tenant @@ -189,7 +177,7 @@ docker run \ This starts the SAML Jackson server on `http://localhost:5225`. -:::important +:::note If you are using the SuperTokens managed service, Boxy HQ hosts the server for you ([contact support](mailto:support@supertokens.com) to activate your instance). @@ -226,9 +214,9 @@ The output of this command provides you the `client_id` and `client_secret` for ### 5. Create a new tenant in SuperTokens (if not done already) - + - + ```tsx import Multiteancy from "supertokens-node/recipe/multitenancy"; @@ -246,10 +234,10 @@ async function createTenant() { } ``` - - + + -```go +```go {10,11,12} import ( "github.com/supertokens/supertokens-golang/recipe/multitenancy" "github.com/supertokens/supertokens-golang/recipe/multitenancy/multitenancymodels" @@ -259,11 +247,9 @@ func main() { tenantId := "customer1" thirdPartyEnabled := true - // highlight-start resp, err := multitenancy.CreateOrUpdateTenant(tenantId, multitenancymodels.TenantConfig{ ThirdPartyEnabled: &thirdPartyEnabled, }) - // highlight-end if err != nil { // handle error @@ -276,11 +262,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant @@ -299,9 +285,9 @@ async def some_func(): print("existing tenant's config was modified.") ``` - + - + ```python from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant @@ -320,22 +306,22 @@ def some_func(): print("existing tenant's config was modified.") ``` - - + + - + - + - + - + ### 6. Configure the SAML provider for the tenant - + - + ```tsx import Multitenancy from "supertokens-node/recipe/multitenancy" @@ -361,10 +347,10 @@ async function addThirdPartyConfigToTenant() { } ``` - - + + -```go +```go {9,10,11,12,13,14,15,16,17,18,19,20,21} import ( "github.com/supertokens/supertokens-golang/recipe/multitenancy" "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" @@ -373,7 +359,6 @@ import ( func main() { tenantId := "customer1" - // highlight-start resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ ThirdPartyId: "boxy-saml", Name: "", @@ -387,7 +372,6 @@ func main() { }, }, }, nil) - // highlight-end if err != nil { // handle error @@ -400,11 +384,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config @@ -433,9 +417,9 @@ async def some_func(): print("Existing SAML Login config overwritten for customer1") ``` - + - + ```python from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config @@ -463,35 +447,34 @@ else: print("Existing SAML Login config overwritten for customer1") ``` - - + + - + - + - + - + To configure SAML login with SuperTokens, ensure that you use the correct provider name in the third-party configuration. Make sure to replace `` in the code snippet above with one of the following -- Microsoft Entra ID
-- Microsoft AD FS
-- Okta
-- Auth0
-- Google
-- OneLogin
-- PingOne
-- JumpCloud
-- Rippling
-- SAML
+- Microsoft Entra ID
+- Microsoft AD FS
+- Okta
+- Auth0
+- Google
+- OneLogin
+- PingOne
+- JumpCloud
+- Rippling
+- SAML
Make sure to replace `http://localhost:5225` with the correct value for where you have hosted the BoxyHQ server. If you are using the SuperTokens managed service, Boxy HQ hosts the server for you ([contact support](mailto:support@supertokens.com) to activate your instance). -:::success -You have successfully configured a new tenant in SuperTokens. The next step is to wire up the frontend SDK to show the right login UI for this tenant. The specifics of this step depend on the UX that you want to provide to your users. The "Common UX flows" section documents two common UX flows. +:::success[You have successfully configured a new tenant in SuperTokens. The next step is to wire up the frontend SDK to show the right login UI for this tenant. The specifics of this step depend on the UX that you want to provide to your users. The "Common UX flows" section documents two common UX flows.] ::: ### 7. Adding multiple SAML connections to a single tenant @@ -507,10 +490,10 @@ For example, if a tenant has Active Directory and Okta login (both with SAML), y ## See also - - - - - - - + + + + + + + diff --git a/docs/authentication/enterprise/manage-apps.mdx b/docs/authentication/enterprise/manage-apps.mdx index f98403112a..a058957804 100644 --- a/docs/authentication/enterprise/manage-apps.mdx +++ b/docs/authentication/enterprise/manage-apps.mdx @@ -1,18 +1,10 @@ --- title: Manage apps -hide_title: true -sidebar_position: 7 description: Create and manage multiple apps within a SuperTokens integration. -page_type: guide -recipe: thirdparty -category: enterprise-login +sidebar: + order: 7 --- - - -# Manage apps - - ## Run multiple apps using the same SuperTokens core @@ -26,15 +18,15 @@ You can use this feature to deploy one SuperTokens core across multiple independ ### 1. Create a new app in the core -:::caution +:::warning This is a paid feature, even if creating an additional `dev` `env` on the managed service, or if using the `dev` license keys in case of self-hosting. The pricing is $50 / month / additional app. Please reach out to [support@SuperTokens.com](mailto:support@SuperTokens.com) if you have any questions, or if you want to create multiple `environments` and want a bulk discount. ::: To create a new app in the SuperTokens core, you can use the following cURL command: ```bash -curl --location --request PUT '^{coreInfo.uri}/recipe/multitenancy/app/v2' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request PUT '/recipe/multitenancy/app/v2' \ +--header 'api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "appId": "app1", @@ -57,8 +49,8 @@ The built-in Factor IDs that you can use for `firstFactors` are: - With SMS magic link: `link-phone` ```bash -curl --location --request PUT '^{coreInfo.uri}/recipe/multitenancy/app' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request PUT '/recipe/multitenancy/app' \ +--header 'api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "appId": "app1", @@ -74,23 +66,21 @@ curl --location --request PUT '^{coreInfo.uri}/recipe/multitenancy/app' \ - You can set core configurations for this app (see the configuration.yaml / docker environment variable options for your core). The core configurations for a new app inherit from the configurations provided in the configuration.yaml / docker environment (or the **Configuration** page for the managed deployment). - By default, all the login methods enable for a new app (specifically, the `public` tenant of the new app), but you can pass in `false` to any of the login methods specified above to disable them. -:::important -Even if a login method enables for a tenant, you still require to initialize the right recipe on the backend for sign up / in to be possible with that login method. For example, if for a tenant, you have enabled the passwordless login method, but don't use the passwordless (or a combination recipe that has passwordless) on the backend, then end users cannot sign up / in using the passwordless APIs because those APIs are not exposed via the backend SDK's middleware. +:::note[Even if a login method enables for a tenant, you still require to initialize the right recipe on the backend for sign up / in to be possible with that login method. For example, if for a tenant, you have enabled the passwordless login method, but don't use the passwordless (or a combination recipe that has passwordless) on the backend, then end users cannot sign up / in using the passwordless APIs because those APIs are not exposed via the backend SDK's middleware.] ::: ### 2. Configure the `appId` during backend SDK init Whilst one core can have multiple apps, you must use a dedicated backend (integrated with the backend SDK) per app. For example, if you have two apps, and both use a NodeJS backend, then you need to configure one app's backend to have `appId` as `app1` (as an example). The other app's backend should have `appId` as `app2`. You can specify an `appId` on the backend SDK SuperTokens.init by appending the `appId` to the `connectionUri` as shown below: - - + + -```tsx +```tsx {5} import supertokens from "supertokens-node"; supertokens.init({ supertokens: { - // highlight-next-line connectionURI: "http://localhost:3567/appid-app1", }, appInfo: { @@ -102,16 +92,15 @@ supertokens.init({ }); ``` - - + + -```go +```go {6} import "github.com/supertokens/supertokens-golang/supertokens" func main() { supertokens.Init(supertokens.TypeInput{ Supertokens: &supertokens.ConnectionInfo{ - // highlight-next-line ConnectionURI: "http://localhost:3567/appid-app1", }, }) @@ -119,27 +108,26 @@ func main() { ``` - - + + -```python +```python {6} from supertokens_python import init, InputAppInfo, SupertokensConfig init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), supertokens_config=SupertokensConfig( - # highlight-next-line connection_uri='http://localhost:3567/appid-app1', ), - framework='...', # type: ignore + framework='...', recipe_list=[ #... ] ) ``` - - + + - In the above code snippet, the backend SDK receives information that the `appId` to use for this app is `app1`. You can pick your own app ID, but whatever it is, you need to add it as shown above. - It is important to prefix the app ID with `appid-` as that enables the SuperTokens core to reliably detect the app that the query is for. @@ -151,8 +139,8 @@ init( You can only perform this via a cURL command. No helper function exists for this in the backend SDKs since the backend SDKs are per app anyway. ```bash -curl --location --request GET '^{coreInfo.uri}/recipe/multitenancy/app/list/v2' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request GET '/recipe/multitenancy/app/list/v2' \ +--header 'api-key: ' \ --header 'Content-Type: application/json' ``` @@ -176,8 +164,8 @@ You get the following JSON output: ``` ```bash -curl --location --request GET '^{coreInfo.uri}/recipe/multitenancy/app/list' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request GET '/recipe/multitenancy/app/list' \ +--header 'api-key: ' \ --header 'Content-Type: application/json' ``` @@ -213,8 +201,7 @@ You get the following JSON output: The following snippet shows you how to delete an app from a SuperTokens Core instance. This operation is irreversible and deletes all user data associated with the app. -:::important -Before you delete an app, ensure that you satisfy the following requirements: +:::note[Before you delete an app, ensure that you satisfy the following requirements:] - The request must originate from the public app and tenant - The app must not have any tenants other than the public tenant. You need to delete other tenants first. @@ -223,8 +210,8 @@ After deleting an app, make sure to update any backend services configured to us ```bash -curl --location --request POST '^{coreInfo.uri}/recipe/multitenancy/app/remove' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/recipe/multitenancy/app/remove' \ +--header 'api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "appId": "app1" @@ -235,6 +222,5 @@ curl --location --request POST '^{coreInfo.uri}/recipe/multitenancy/app/remove' - All user data, configuration, and tenant information associated with this app are permanently deleted. - The API key used must have the necessary permissions to delete apps. -:::danger -This operation cannot be undone. Make sure you have backed up any important data before proceeding. +:::danger[This operation cannot be undone. Make sure you have backed up any important data before proceeding.] ::: diff --git a/docs/authentication/enterprise/manage-tenants.mdx b/docs/authentication/enterprise/manage-tenants.mdx index c6334927d5..e56a8e15da 100644 --- a/docs/authentication/enterprise/manage-tenants.mdx +++ b/docs/authentication/enterprise/manage-tenants.mdx @@ -1,24 +1,185 @@ --- title: Tenant actions -hide_title: true -sidebar_position: 6 description: Discover different APIs that can help you work with tenants. -page_type: guide -recipe: thirdparty -category: enterprise-login +sidebar: + order: 6 --- -import CreateTenantBlock from "./_blocks/create-tenant.mdx"; -import UpdateTenantConfigBlock from "./_blocks/update-tenant-config.mdx"; -import GetTenantConfigBlock from "./_blocks/get-tenant.mdx"; +## Create a new tenant + -# Manage tenants + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; -## Create a new tenant +async function createNewTenant() { + let resp = await Multitenancy.createOrUpdateTenant("customer1", { + firstFactors: ["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-phone", "link-email"] + }); + + if (resp.createdNew) { + // Tenant created successfully + } else { + // Existing tenant's config was modified. + } +} +``` + +The snippet creates a new tenant with the id `"customer1"`. +It enables the email password, third party and passwordless login methods for this tenant. +You can also disable any of these by not including them in the `firstFactors` input. +If `firstFactors` is not specified, by default, the system does not enable any of the login methods. + +If you set `firstFactors` to `null` the SDK uses any of the login methods. + +The built-in Factor IDs available for `firstFactors` include: + +| Authentication Type | Factor ID | +|-------------------|-----------| +| Email password auth | `emailpassword` | +| Social login / enterprise SSO auth | `thirdparty` | +| Passwordless - Email OTP | `otp-email` | +| Passwordless - SMS OTP | `otp-phone` | +| Passwordless - Email magic link | `link-email` | +| Passwordless - SMS magic link | `link-phone` | + + + + +```go {12,13,14,15,16} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/multitenancy/multitenancymodels" +) + +func main() { + tenantId := "customer1" + emailPasswordEnabled := true + thirdPartyEnabled := true + passwordlessEnabled := true + + resp, err := multitenancy.CreateOrUpdateTenant(tenantId, multitenancymodels.TenantConfig{ + EmailPasswordEnabled: &emailPasswordEnabled, + ThirdPartyEnabled: &thirdPartyEnabled, + PasswordlessEnabled: &passwordlessEnabled, + }) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // new tenant was created + } else { + // existing tenant's config was modified. + } +} +``` + +The code snippet creates a new tenant with the id `"customer1"`. +It enables the email password, third party and passwordless login methods for this tenant. +You can also disable any of these by setting the corresponding field to `false`. + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant +from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate + +async def some_func(): + response = await create_or_update_tenant("customer1", TenantConfigCreateOrUpdate( + first_factors=["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-phone", "link-email"] + )) + + if response.status != "OK": + print("Handle error") + elif response.created_new: + print("New tenant was created") + else: + print("Existing tenant's config was updated") +``` + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant +from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate + +def some_func(): + response = create_or_update_tenant("customer1", TenantConfigCreateOrUpdate( + first_factors=["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-phone", "link-email"] + )) + + if response.status != "OK": + print("Handle error") + elif response.created_new: + print("New tenant was created") + else: + print("Existing tenant's config was updated") +``` + + + + +The code snippet creates a new tenant with the id `"customer1"`. +It enables the email password, third party and passwordless login methods for this tenant. +You can also disable any of these by setting the corresponding field to `false`. + + - + + +```bash +curl --location --request PUT 'http://localhost:3567/recipe/multitenancy/tenant/v2' \ +--header 'api-key: YOUR_API_KEY' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "tenantId": "customer1", + "firstFactors": ["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-email", "link-phone"] +}' +``` + +The request includes the `appId` for which you need to create a new tenant. +If you are using the default (`"public"`) app, you can omit the `/appid-` part of the URL. + +The snippet creates a new tenant with the id `"customer1"`. +It enables the email password, third party and passwordless login methods for this tenant. +You can also disable any of these by not including them in the `firstFactors` input. +If `firstFactors` is not specified, by default, the system does not enable any of the login methods. + +The built-in Factor IDs available for `firstFactors` include: + +| Authentication Type | Factor ID | +|-------------------|-----------| +| Email password auth | `emailpassword` | +| Social login / enterprise SSO auth | `thirdparty` | +| Passwordless - Email OTP | `otp-email` | +| Passwordless - SMS OTP | `otp-phone` | +| Passwordless - Email magic link | `link-email` | +| Passwordless - SMS magic link | `link-phone` | + + + + + +Create Tenant + +Create a new tenant by clicking on the **Add Tenant** button and specify the tenant ID. + +All Login Methods Enabled + +Once you create the tenant, turn on the Login Methods as required for the tenant. In the above example, you turn on all the Login Methods. + + + + --- @@ -26,7 +187,191 @@ import GetTenantConfigBlock from "./_blocks/get-tenant.mdx"; You can also configure a tenant to have different configurations per the core's `config.yaml` or docker environment variables. Below is how you can specify the configuration, when creating or modifying a tenant: - + + + + +```tsx {5,6,7,8,9,10,11} +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function createNewTenant() { + + let resp = await Multitenancy.createOrUpdateTenant("customer1", { + coreConfig: { + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2", + } + }); + + if (resp.createdNew) { + // new tenant was created + } else { + // existing tenant's config was modified. + } +} +``` + +In the above example, the system assigns different values for certain configurations for `customer1` tenant. +All other configurations inherit from the base configuration. + +Notice the `postgresql_connection_uri`. +This allows you to achieve **data isolation on a tenant level**. +This configuration is not required. +If not provided, the database stores the tenant's information as specified in the core's configuration. +It is still a different user pool though. + + + + +```go {9,10,11,12,13,14,15} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/multitenancy/multitenancymodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateTenant(tenantId, multitenancymodels.TenantConfig{ + CoreConfig: map[string]interface{}{ + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2", + }, + }) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // new tenant was created + } else { + // existing tenant's config was modified. + } +} +``` + +In the above example, the system assigns different values for certain configurations for `customer1` tenant. +All other configurations inherit from the base configuration. + +Notice the `postgresql_connection_uri`. +This allows you to achieve **data isolation on a tenant level**. +This configuration is not required. +If not provided, the database stores the tenant's information as specified in the core's configuration. +It is still a different user pool though. + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_tenant +from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_tenant(tenant_id, TenantConfigCreateOrUpdate( + core_config={ + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2", + }, + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("new tenant created") + else: + print("existing tenant's config was modified.") +``` + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_tenant +from supertokens_python.recipe.multitenancy.interfaces import TenantConfigCreateOrUpdate + +tenant_id = "customer1" +result = create_or_update_tenant(tenant_id, TenantConfigCreateOrUpdate( + core_config={ + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2", + }, +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("new tenant created") +else: + print("existing tenant's config was modified.") +``` + + + + +In the above example, the system assigns different values for certain configurations for `customer1` tenant. +All other configurations inherit from the base configuration. + +Notice the `postgresql_connection_uri`. +This allows you to achieve **data isolation on a tenant level**. +This configuration is not required. +If not provided, the database stores the tenant's information as specified in the core's configuration. +It is still a different user pool though. + + + + + + +```bash +curl --location --request PUT 'http://localhost:3567/recipe/multitenancy/tenant/v2' \ +--header 'api-key: YOUR_API_KEY' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "tenantId": "customer1", + "coreConfig": { + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2" + } +}' +``` + +In the above example, the system assigns different values for certain configurations for `customer1` tenant. +All other configurations inherit from the base configuration. + +Notice the `postgresql_connection_uri`. +This allows you to achieve **data isolation on a tenant level**. +This configuration is not required. +If not provided, the database stores the tenant's information as specified in the core's configuration. +It is still a different user pool though. + + + + + +Custom tenant configuration + + +In the above example, the system assigns different values for certain configurations for `customer1` tenant. +All other configurations inherit from the base configuration. +You can edit the values by clicking on the pencil icon and then specifying a new value. + +:::warning[You cannot edit database connection settings directly from the Dashboard, and you may need to use the SDK or cURL to update them.] + +::: + + + + --- @@ -34,25 +379,176 @@ You can also configure a tenant to have different configurations per the core's Once you have set the configs for a specific tenant, you can fetch the tenant info as shown below: - + + + + +```tsx {5} +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function getTenant(tenantId: string) { + + let resp = await Multitenancy.getTenant(tenantId); + + if (resp === undefined) { + // tenant does not exist + } else { + let coreConfig = resp.coreConfig; + + let firstFactors = resp.firstFactors; + + let configuredThirdPartyProviders = resp.thirdParty.providers; + } +} +``` + + + + +```go {10} +import ( + "fmt" + + "github.com/supertokens/supertokens-golang/recipe/multitenancy" +) + +func main() { + tenantId := "customer1" + + tenant, err := multitenancy.GetTenant(tenantId) + + if err != nil { + // handle error + } + if tenant == nil { + // tenant does not exist + } else { + isEmailPasswordLoginEnabled := tenant.EmailPassword.Enabled; + isThirdPartyLoginEnabled := tenant.ThirdParty.Enabled; + isPasswordlessLoginEnabled := tenant.Passwordless.Enabled; + + if (isEmailPasswordLoginEnabled) { + // Tenant support email password login + } + + if (isThirdPartyLoginEnabled) { + // Tenant support third party login + configuredThirdPartyProviders := tenant.ThirdParty.Providers; + fmt.Println(configuredThirdPartyProviders); + } + + if (isPasswordlessLoginEnabled) { + // Tenant support passwordless login + } + } +} +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import get_tenant + +async def some_func(): + tenant = await get_tenant("customer1") + + if tenant is None: + print("tenant does not exist") + else: + core_config = tenant.core_config + first_factors = tenant.first_factors + providers = tenant.third_party_providers + + print(core_config) + print(first_factors) + print(providers) +``` + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import get_tenant + +tenant = get_tenant("customer1") + +if tenant is None: + print("tenant does not exist") +else: + core_config = tenant.core_config + first_factors = tenant.first_factors + providers = tenant.third_party_providers + + print(core_config) + print(first_factors) + print(providers) +``` + + + + + + + + +```bash +curl --location --request GET 'http://localhost:3567/customer1/recipe/multitenancy/tenant/v2' \ +--header 'api-key: YOUR_API_KEY' \ +--header 'Content-Type: application/json' +``` + +Notice that you add `customer1` to the path of the request. This tells the core that the tenant you want to get the information about is `customer1` (the one created before in this page). + +If the input tenant does not exist, you get back a `200` status code with the following JSON: + +```json +{"status": "TENANT_NOT_FOUND_ERROR"} +``` + +Otherwise you get a `200` status code with the following JSON output: + +```json +{ + "status": "OK", + "thirdParty": { + "providers": [...] + }, + "coreConfig": { + "email_verification_token_lifetime": 7200000, + "password_reset_token_lifetime": 3600000, + "postgresql_connection_uri": "postgresql://localhost:5432/db2" + }, + "tenantId": "customer1", + "firstFactors": ["emailpassword", "thirdparty", "otp-email", "otp-phone", "link-email", "link-phone"] +} +``` + + + + + +The returned `coreConfig` is the same as what you set when creating / updating the tenant. The rest of the core configurations for this tenant inherit from the app's (or the `public` tenant) configuration. The `public` tenant, for the `public` app inherits its configurations from the `config.yaml` / docker environment variables values. --- ## List all the tenants of an app - + - + -```tsx +```tsx {5,6} import Multitenancy from "supertokens-node/recipe/multitenancy"; async function listAllTenants() { - // highlight-start let resp = await Multitenancy.listAllTenants(); let tenants = resp.tenants; - // highlight-end tenants.forEach(tenant => { let coreConfig = tenant.coreConfig; @@ -70,10 +566,10 @@ The value of `firstFactors` can be as follows: - `[]` (empty array): The tenant does not enable any login methods. - a non-empty array: The tenant enables only the login methods in the array. - - + + -```go +```go {8} import ( "fmt" @@ -81,9 +577,7 @@ import ( ) func main() { - // highlight-start resp, err := multitenancy.ListAllTenants() - // highlight-end if err != nil { // handle error @@ -116,11 +610,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import list_all_tenants @@ -144,9 +638,9 @@ async def some_func(): print(f"Configured third party providers: {configured_third_party_providers}") ``` - + - + ```python from supertokens_python.recipe.multitenancy.syncio import list_all_tenants @@ -170,16 +664,16 @@ def some_func(): print(f"Configured third party providers: {configured_third_party_providers}") ``` - - + + - + - + ```bash -curl --location --request GET '^{coreInfo.uri}/recipe/multitenancy/tenant/list/v2' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request GET '/recipe/multitenancy/tenant/list/v2' \ +--header 'api-key: ' \ --header 'Content-Type: application/json' ``` @@ -205,19 +699,19 @@ The value of `firstFactors` can be as follows: - `[]` (empty array): The tenant does not enable any login methods. - a non-empty array: The tenant enables only the login methods in the array. - + - + --- ## Add a custom third-party provider to a tenant -If you can't find a provider in [the built-in list](/docs/authentication/social/built-in-providers-config), you can add your own custom implementation. +If you can't find a provider in [the built-in list](/authentication/social/built-in-providers-config), you can add your own custom implementation. This page shows you how to do that on a per tenant basis. -:::info Note +:::info[Note] If you think that SuperTokens should support this provider by default, make sure to let the team know [on GitHub](https://github.com/supertokens/supertokens-node/issues/88). ::: @@ -226,9 +720,9 @@ Once you have created a tenant, you want to call the API / function to create a ### Using OAuth endpoints - + - + ```tsx import Multiteancy from "supertokens-node/recipe/multitenancy"; @@ -269,10 +763,10 @@ async function createTenant() { } ``` - - + + -```go +```go {9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36} import ( "github.com/supertokens/supertokens-golang/recipe/multitenancy" "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" @@ -281,7 +775,6 @@ import ( func main() { tenantId := "..." - // highlight-start resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ ThirdPartyId: "custom", Name: "Custom Provider", @@ -310,7 +803,6 @@ func main() { }, }, }, nil) - // highlight-end if err != nil { // handle error @@ -323,11 +815,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config @@ -373,9 +865,9 @@ async def some_func(): print("Existing custom provider config overwritten for tenant") ``` - + - + ```python from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config @@ -420,16 +912,16 @@ else: print("Existing custom provider config overwritten for tenant") ``` - - + + - + - + ```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "config": { @@ -461,25 +953,25 @@ curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/c }' ``` - + - + Click on **Add new provider** in the Social/Enterprise Providers section -Social/Enterprise providers +Social/Enterprise providers Select **Add Custom Provider** option -New Provider +New Provider Fill in the details as shown below and click on **Save** -OAuth2 provider +OAuth2 provider - + - + You can see all the options in the [CDI documentation](https://supertokens.com/docs/cdi). @@ -502,10 +994,10 @@ You can see all the options in the [CDI documentation](https://supertokens.com/d If the provider is Open ID Connect (OIDC) compatible, you can provide a URL for the `OIDCDiscoverEndpoint` configuration. The backend SDK automatically discovers authorization endpoint, token endpoint and the user info endpoint by querying the `/.well-known/openid-configuration`. - - + + -```tsx +```tsx {12} import Multiteancy from "supertokens-node/recipe/multitenancy"; async function createTenant() { @@ -517,9 +1009,7 @@ async function createTenant() { clientSecret: "...", scope: ["email", "profile"] }], - // highlight-start oidcDiscoveryEndpoint: "https://example.com/.well-known/openid-configuration", - // highlight-end authorizationEndpointQueryParams: { // optional "someKey1": "value1", "someKey2": null, @@ -541,10 +1031,10 @@ async function createTenant() { } ``` - - + + -```go +```go {19} import ( "github.com/supertokens/supertokens-golang/recipe/multitenancy" "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" @@ -563,9 +1053,7 @@ func main() { Scope: []string{"profile", "email"}, }, }, - // highlight-start OIDCDiscoveryEndpoint: "https://example.com/.well-known/openid-configuration", - // highlight-end AuthorizationEndpointQueryParams: map[string]interface{}{ // optional "someKey1": "value1", "someKey2": nil, @@ -590,10 +1078,10 @@ func main() { } ``` - - + + -```python +```python {16} from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig, UserInfoMap, UserFields @@ -609,9 +1097,7 @@ async def some_func(): scope=["email", "profile"], ), ], - # highlight-start oidc_discovery_endpoint="https://example.com/.well-known/openid-configuration", - # highlight-end authorization_endpoint_query_params={ "someKey1": "value1", "someKey2": None, @@ -634,13 +1120,13 @@ async def some_func(): print("Existing custom provider config overwritten for tenant") ``` - + - + ```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "config": { @@ -667,25 +1153,25 @@ curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/c }' ``` - + - + Click on **Add new provider** in the Social/Enterprise Providers section -Social/Enterprise providers +Social/Enterprise providers Select **Add Custom Provider** option -New Provider +New Provider Fill in the details as shown below and click on **Save** -OAuth2 provider +OAuth2 provider - + - + You can see all the options in the [CDI documentation](https://supertokens.com/docs/cdi). @@ -707,9 +1193,9 @@ For example, if a user signs up with email password login in the `public` tenant To associate a user with a tenant, you can call the following API: - + - + ```tsx import Multitenancy from "supertokens-node/recipe/multitenancy"; @@ -737,8 +1223,8 @@ async function addUserToTenant(recipeUserId: RecipeUserId, tenantId: string) { } ``` - - + + ```go import ( @@ -769,11 +1255,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import associate_user_to_tenant @@ -801,9 +1287,9 @@ async def some_func(): print("This means that the input user had already previously signed in with the same third party provider (e.g. Google) for the new tenant.") ``` - + - + ```python from supertokens_python.recipe.multitenancy.syncio import associate_user_to_tenant @@ -830,16 +1316,16 @@ else: print("This means that the input user had already previously signed in with the same third party provider (e.g. Google) for the new tenant.") ``` - - + + - + - + ```bash -curl --location --request POST '^{coreInfo.uri}//recipe/multitenancy/tenant/user \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '//recipe/multitenancy/tenant/user \ +--header 'api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "recipeUserId": "..." @@ -853,9 +1339,9 @@ In the above code, `recipeUserId` is associated with the tenant with ID `TENANT_ - `"PHONE_NUMBER_ALREADY_EXISTS_ERROR"`: This means that the input user is a passwordless user and the new tenant already has a user with the same phone number, for passwordless login. - `"THIRD_PARTY_USER_ALREADY_EXISTS_ERROR"`: This means that the input user had already previously signed in with the same third-party provider (for example, Google) for the new tenant. - + - + --- @@ -863,9 +1349,9 @@ In the above code, `recipeUserId` is associated with the tenant with ID `TENANT_ You can even remove a user's access from a tenant using the API call shown below. In fact, you can remove a user from all tenants that they have access to, and the user and their metadata remain in the system. However, they cannot log in to any tenant. To remove a user from a tenant, call the following API: - + - + ```tsx import Multitenancy from "supertokens-node/recipe/multitenancy"; @@ -882,8 +1368,8 @@ async function removeUserFromTeannt(recipeUserId: RecipeUserId, tenantId: string } ``` - - + + ```go import ( @@ -907,11 +1393,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.multitenancy.asyncio import disassociate_user_from_tenant @@ -926,9 +1412,9 @@ async def some_func(): print("User was never a part of the tenant anyway") ``` - + - + ```python from supertokens_python.recipe.multitenancy.syncio import disassociate_user_from_tenant @@ -943,38 +1429,36 @@ def some_func(): print("User was never a part of the tenant anyway") ``` - - + + - + - + ```bash -curl --location --request POST '^{coreInfo.uri}//recipe/multitenancy/tenant/user/remove \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '//recipe/multitenancy/tenant/user/remove \ +--header 'api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "recipeUserId": "..." }' ``` - + - + -:::important -- Users can only share access across tenants and not across apps. +:::note[- Users can only share access across tenants and not across apps.] - If your app has two tenants, that are in different database locations, then you cannot share users between them. ::: ## See also - - - - - - - + + + + + + diff --git a/docs/authentication/enterprise/meta.ts b/docs/authentication/enterprise/meta.ts new file mode 100644 index 0000000000..3cef53a82d --- /dev/null +++ b/docs/authentication/enterprise/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Enterprise Login", + "icon": "building-2", + "order": 5 +}); diff --git a/docs/authentication/enterprise/saml.mdx b/docs/authentication/enterprise/saml.mdx index 5750f01c68..d40eb8496b 100644 --- a/docs/authentication/enterprise/saml.mdx +++ b/docs/authentication/enterprise/saml.mdx @@ -1,16 +1,11 @@ --- title: SAML -hide_title: true -sidebar_position: 10 -toc_max_heading_level: 4 description: Add SAML authentication to your application -page_type: tutorial -recipe: thirdparty -category: enterprise-login +sidebar: + badge: New + order: 10 --- -# SAML Setup - ## Overview The following guide shows you how to configure SAML with your SuperTokens integration. @@ -30,14 +25,15 @@ This URL is to a website controlled by the `SAML` provider and asks the end user ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: -These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction). +These instructions assume that you already have gone through the main [quickstart guide](/quickstart/introduction). If you have skipped that page please follow the tutorial and return here once you're done. -:::warning no-title -You need to use a SuperTokens core that is at least on version `11.3`. +:::warning[You need to use a SuperTokens core that is at least on version `11.3`.] The feature is only available with the `Node.js` SDK. Support for `Python` and `Golang` is in active development. ::: @@ -84,9 +80,8 @@ SuperTokens.init({ Use the metadata XML obtained in step 1 to create a SAML client. The `redirectURIs` should point to your application's callback URL where users will be redirected after authentication. -:::info no-title -This step assumes that you previously have created a SuperTokens tenant. -If you have not, please follow the [initial setup guide](/docs/authentication/enterprise/initial-setup). +:::info[This step assumes that you previously have created a SuperTokens tenant.] +If you have not, please follow the [initial setup guide](/authentication/enterprise/initial-setup). ::: ```typescript @@ -129,8 +124,8 @@ async function createSamlClient() { After creating the SAML client, you need to configure your Identity Provider with your application's Service Provider (SP) details. On the IDP side, configure the following properties: -- **Entity ID**: Should match the `saml_sp_entity_id` value used in your [tenant configuration](/docs/authentication/enterprise/manage-tenants#update-a-tenant). The default value is `https://saml.supertokens.com`. -- **ACS URL** (Assertion Consumer Service URL): `/auth/saml/callback` +- **Entity ID**: Should match the `saml_sp_entity_id` value used in your [tenant configuration](/authentication/enterprise/manage-tenants#update-a-tenant). The default value is `https://saml.supertokens.com`. +- **ACS URL** (Assertion Consumer Service URL): `/auth/`<TENANT_ID>`saml/callback` ### 5. Add the ThirdParty provider @@ -182,9 +177,9 @@ SuperTokens.init({ ## See also - - - - - - + + + + + + diff --git a/docs/authentication/enterprise/subdomain-login.mdx b/docs/authentication/enterprise/subdomain-login.mdx index d51162388f..d04c835de7 100644 --- a/docs/authentication/enterprise/subdomain-login.mdx +++ b/docs/authentication/enterprise/subdomain-login.mdx @@ -1,23 +1,16 @@ --- title: Implement subdomain login -hide_title: true -sidebar_position: 4 description: Authenticate users across different tenants through different subdomains. -page_type: guide -recipe: thirdparty -category: enterprise-login +sidebar: + order: 4 --- - -# Subdomain login - ## Overview This guide shows you how to authenticate users through different subdomains. The authentication method that displayed on each page varies based on tenant configuration. -:::important -Throughout this page, assume that the tenant ID for a tenant is equal to their sub domain. If the sub domain assigned to a tenant is `customer1.example.com`, then their `tenantId` is `customer1`. +:::note[Throughout this page, assume that the tenant ID for a tenant is equal to their sub domain. If the sub domain assigned to a tenant is `customer1.example.com`, then their `tenantId` is `customer1`.] An example app for this setup with the **pre-built UI** is available on [the GitHub example directory](https://github.com/supertokens/supertokens-auth-react/tree/master/examples/with-one-login-per-subdomain). The app is setup to have three tenants: - `tenant1.example.com`: Login with `emailpassword` + Google sign in @@ -27,21 +20,23 @@ An example app for this setup with the **pre-built UI** is available on [the Git ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: The tutorial assumes that you already have a working application integrated with **SuperTokens**. -If you have not, please check the [Quickstart Guide](/docs/quickstart/introduction). +If you have not, please check the [Quickstart Guide](/quickstart/introduction). Your application also needs you to create the tenants it requires. -View the [previous tutorial](/docs/authentication/enterprise/initial-setup) for more information on how to do this. +View the [previous tutorial](/authentication/enterprise/initial-setup) for more information on how to do this. ## Steps ### 1. Change CORS setting and `websiteDomain` -:::warning no-title -You have to [create tenants](/docs/authentication/enterprise/initial-setup) before you can complete this step. +:::warning +You have to [create tenants](/authentication/enterprise/initial-setup) before you can complete this step. ::: #### 1.1 CORS setup @@ -60,18 +55,17 @@ See the Email Delivery section in the docs for how to override the `sendEmail` f ### 2. Load login methods dynamically on the frontend based on the `tenantId` - + Modify the `SuperTokens.init` to do the following: 1. Set the `usesDynamicLoginMethods` to true. This tells the frontend SDK that the login page relies on the `tenantId` and to fetch the tenant configuration from the backend before showing any login UI. 2. Initialize the `Multitenancy` recipe and provide `getTenantId` configuration function. - - - + + -```tsx +```tsx {16,19,20,21,22,23,24,25,26,27,28,29,30,31} import React from 'react'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; @@ -81,18 +75,15 @@ import Multitenancy from "supertokens-auth-react/recipe/multitenancy"; SuperTokens.init({ appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, - // highlight-start usesDynamicLoginMethods: true, - // highlight-end recipeList: [ // Other recipes.. - // highlight-start Multitenancy.init({ override: { functions: (oI) => { @@ -106,35 +97,28 @@ SuperTokens.init({ } }, }) - // highlight-end ] }); ``` - + - + -```tsx +```tsx {10,14,15,16,17,18,19,20,21,22,23,24,25,26} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; -import supertokensUIMultitenancy from "supertokens-auth-react-script/recipe/multitenancy"; supertokensUIInit({ appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, - // highlight-start usesDynamicLoginMethods: true, - // highlight-end recipeList: [ // Other recipes... supertokensUISession.init(), - // highlight-start supertokensUIMultitenancy.init({ override: { functions: (oI) => { @@ -148,26 +132,25 @@ supertokensUIInit({ } }, }) - // highlight-end ] }); ``` - + - + - + - + You can fetch the list of user's login methods based on their tenant ID (which you can derive from the current sub domain value) as shown below. - - + + - - + + ```tsx import Multitenancy from 'supertokens-web-js/recipe/multitenancy'; @@ -190,8 +173,8 @@ async function fetchThirdPartyLoginProvidersForTenant(tenantId: string) { } ``` - - + + ```tsx import Multitenancy from 'supertokens-web-js/recipe/multitenancy'; @@ -213,35 +196,35 @@ async function fetchThirdPartyLoginProvidersForTenant(tenantId: string) { } ``` - - + + + + - + - - ```bash -curl --location --request GET '^{appInfo.apiDomain}^{appInfo.apiBasePath}/loginmethods' +curl --location --request GET '/auth/loginmethods' ``` The response body from the API call has a `status` property in it: - `status: "OK"`: The `recipes` field contains information about which login methods are active along with the list of third party providers configured for this tenant. - `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. - - - + + + You also need to initialize the multi tenancy recipe with the following callback defined. You can get the value of `tenantId` from the sub domain as shown below. - - + + -```tsx +```tsx {10,11,12,13,14,15,16,17,18,19,20,21,22} import SuperTokens from "supertokens-web-js"; import Multitenancy from "supertokens-web-js/recipe/multitenancy"; @@ -251,7 +234,6 @@ SuperTokens.init({ apiDomain: "...", }, recipeList: [ - // highlight-start Multitenancy.init({ override: { functions: (oI) => { @@ -265,25 +247,21 @@ SuperTokens.init({ } }, }) - // highlight-end // other recipes... ] }); ``` - - + + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensMultitenancy from "supertokens-web-js-script/recipe/multitenancy"; +```tsx {7,8,9,10,11,12,13,14,15,16,17,18,19} supertokens.init({ appInfo: { appName: "...", apiDomain: "...", }, recipeList: [ - // highlight-start supertokensMultitenancy.init({ override: { functions: (oI) => { @@ -297,26 +275,25 @@ supertokens.init({ } }, }) - // highlight-end // other recipes... ] }); ``` - - + + - + - + -After you have shown the login methods and the user tries to sign in, follow all the steps for mobile app login similar to the [social login steps](../../custom-ui/thirdparty-login). When calling the sign in up API, also pass in the `tenantId` in the request path. An example of this appears below: +After you have shown the login methods and the user tries to sign in, follow all the steps for mobile app login similar to the [social login steps](/authentication/social/initial-setup#2-add-the-login-ui). When calling the sign in up API, also pass in the `tenantId` in the request path. An example of this appears below: + - ```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup' \ +curl --location --request POST '/auth/signinup' \ --header 'Content-Type: application/json' \ --data-raw '{ "thirdPartyId": "...", @@ -328,14 +305,13 @@ curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signi }' ``` - - - + - + + ### 3. Restrict subdomain access @@ -344,11 +320,11 @@ Restrict which sub domains the user has access to. To do this configure the SDK to know which domain each `tenantId` has access to. - + - + -```tsx +```tsx {11,12,13,14,15,16,17} import SuperTokens from "supertokens-node"; import Multitenancy from "supertokens-node/recipe/multitenancy" @@ -359,7 +335,6 @@ SuperTokens.init({ websiteDomain: "..." }, recipeList: [ - // highlight-start Multitenancy.init({ getAllowedDomainsForTenantId: async (tenantId, userContext) => { // query your db to get the allowed domain for the input tenantId @@ -367,16 +342,15 @@ SuperTokens.init({ return [tenantId + ".myapp.com", "myapp.com", "www.myapp.com"] } }), - // highlight-end // other recipes... ] }) ``` - - + + -```go +```go {10,11,12,13,14,15,16} import ( "github.com/supertokens/supertokens-golang/recipe/multitenancy" "github.com/supertokens/supertokens-golang/recipe/multitenancy/multitenancymodels" @@ -386,7 +360,6 @@ import ( func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ - // highlight-start multitenancy.Init(&multitenancymodels.TypeInput{ GetAllowedDomainsForTenantId: func(tenantId string, userContext supertokens.UserContext) ([]string, error) { // query your db to get the allowed domain for the input tenantId @@ -394,14 +367,13 @@ func main() { return []string{tenantId + ".myapp.com", "myapp.com", "www.myapp.com"}, nil }, }), - // highlight-end }, }) } ``` - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -429,28 +401,27 @@ init( ) ``` - + - + The configuration above tells SuperTokens to add the list of domains returned by you into the user's session claims once they login. This way the SDK accesses the claim on the frontend and backend to limit a user only to the right subdomains. -### 4. Share sessions across sub domains {{optional}} +### 4. Share sessions across sub domains (optional) If you need to allow users to have the same session across multiple subdomains you have to update the configuration. -Set the [`sessionTokenFrontendDomain` value ](/docs/post-authentication/session-management/share-session-across-sub-domains) in the `Session` recipe to enable this behavior. -If the sub domain and the main website domain have different backends (on different sub domains), then you can also enable [sharing of sessions across API domains](/docs/post-authentication/session-management/advanced-workflows/multiple-api-endpoints). +Set the [`sessionTokenFrontendDomain` value ](/post-authentication/session-management/share-session-across-sub-domains) in the `Session` recipe to enable this behavior. +If the sub domain and the main website domain have different backends (on different sub domains), then you can also enable [sharing of sessions across API domains](/post-authentication/session-management/advanced-workflows/multiple-api-endpoints). -:::note -Even if they visit the main domain (logged in via `a.example.com`, and visit `example.com`), the frontend app there can detect if the user has a session or not. +:::note[Even if they visit the main domain (logged in via `a.example.com`, and visit `example.com`), the frontend app there can detect if the user has a session or not.] This is not a security issue because access restricts users based on their domain allow list as shown below. ::: ### 5. Limit user access to their sub domain. -Use [session claim validators](/docs/additional-verification/session-verification/claim-validation#using-session-claims) on the frontend to restrict sub domain access. +Use [session claim validators](/additional-verification/session-verification/claim-validation#using-session-claims) on the frontend to restrict sub domain access. Before proceeding, ensure that you have defined the `GetAllowedDomainsForTenantId` function mentioned above. This adds the list of allowed domains into the user's access token payload. @@ -459,11 +430,11 @@ If not, redirect them to the right sub domain. This is possible by using the `hasAccessToCurrentDomain` session validator from the multi tenancy recipe. - + - + - + ```tsx import React from "react"; @@ -490,11 +461,11 @@ Session.init({ }, }) ``` -Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever you check protect a route](/docs/additional-verification/session-verification/protect-frontend-routes), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). +Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever you check protect a route](/additional-verification/session-verification/protect-frontend-routes), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). - + - + Make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: @@ -502,8 +473,6 @@ This change is in your auth route configuration. ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; -import supertokensMultitenancy from "supertokens-web-js-script/recipe/multitenancy"; supertokensUISession.init({ override: { @@ -552,18 +521,18 @@ Session.init({ }) ``` -Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever you check protect a route](../sessions/protecting-frontend-routes), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). +Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever you check protect a route](/additional-verification/session-verification/protect-frontend-routes), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). - + - + - + - + - - + + ```tsx import Session from 'supertokens-web-js/recipe/session'; @@ -591,12 +560,10 @@ Session.init({ ``` - - + + ```tsx -import supertokensSession from 'supertokens-web-js-script/recipe/session'; -import supertokensMultitenancy from 'supertokens-web-js-script/recipe/multitenancy'; supertokensSession.init({ override: { functions: (oI) => ({ @@ -618,21 +585,21 @@ supertokensSession.init({ }) ``` - - + + -Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever you check protect a route](../sessions/protecting-frontend-routes#verifying-the-claims-of-a-session--cust), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). +Above, in `Session.init` on the frontend, add the `hasAccessToCurrentDomain` claim validator to the global validators. This means that [whenever you check protect a route](/additional-verification/session-verification/protect-frontend-routes#check-the-claims-of-a-session), it checks if `hasAccessToCurrentDomain` has passed. If not, SuperTokens redirects the user to their right sub domain (via the values set in the `AllowedDomainsClaim` session claim). - + --- ## See also - - - - - - + + + + + + diff --git a/docs/authentication/enterprise/tenant-discovery.mdx b/docs/authentication/enterprise/tenant-discovery.mdx index f413ca0442..634a28b114 100644 --- a/docs/authentication/enterprise/tenant-discovery.mdx +++ b/docs/authentication/enterprise/tenant-discovery.mdx @@ -1,13 +1,11 @@ --- title: Tenant discovery -hide_title: true -sidebar_position: 5 description: Automatically discover and route users to appropriate tenants based on their email domains -page_type: tutorial +sidebar: + badge: New + order: 5 --- -# Tenant discovery - ## Overview This tutorial shows you how to add tenant discovery functionality to your SuperTokens authentication flows. @@ -98,7 +96,7 @@ Hence, you don't need to change anything else to make it work. Email authentication form @@ -109,8 +107,7 @@ If you want to customize the user interface experience the plugin also provides You can use the tenant selection interface accessible at `/tenant-discovery/select`. This page displays all available tenants and allows users to choose their organization before proceeding with authentication. -:::info -Keep in mind that you also need to enable the `tenant list` endpoint in your backend plugin configuration. +:::info[Keep in mind that you also need to enable the `tenant list` endpoint in your backend plugin configuration.] ::: #### @@ -209,10 +206,10 @@ function CustomTenantDiscovery() { Besides tenant discovery, you can also explore other enterprise authentication features: - - - - - - - + + + + + + + diff --git a/docs/authentication/enterprise/tenant-management-plugin.mdx b/docs/authentication/enterprise/tenant-management-plugin.mdx index bce3f96f2f..80133f97c8 100644 --- a/docs/authentication/enterprise/tenant-management-plugin.mdx +++ b/docs/authentication/enterprise/tenant-management-plugin.mdx @@ -1,13 +1,11 @@ --- title: Tenant management -hide_title: true -sidebar_position: 6 description: Use the tenant management plugin for an out-of-the-box admin experience -page_type: tutorial +sidebar: + badge: New + order: 6 --- -# Tenant management plugin - ## Overview This tutorial shows you how to add comprehensive tenant management functionality to your SuperTokens authentication flows. @@ -269,10 +267,10 @@ SuperTokens.init({ Besides tenant management, you can also explore other enterprise authentication features: - - - - - - - + + + + + + + diff --git a/docs/authentication/m2m/_category_.json b/docs/authentication/m2m/_category_.json deleted file mode 100644 index 274c8ee4f0..0000000000 --- a/docs/authentication/m2m/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Machine to Machine", - "position": 7 -} diff --git a/docs/authentication/m2m/client-credentials.mdx b/docs/authentication/m2m/client-credentials.mdx index 6bd7df5667..90841ea01e 100644 --- a/docs/authentication/m2m/client-credentials.mdx +++ b/docs/authentication/m2m/client-credentials.mdx @@ -1,36 +1,33 @@ --- title: Client Credentials Flow -hide_title: true -sidebar_position: 2 -toc_max_heading_level: 4 -description: >- - Configure OAuth2 client credentials flow for microservices authentication and - access token verification. -page_type: tutorial -recipe: oauth2 -category: machine-to-machine +description: Configure OAuth2 client credentials flow for microservices authentication and access token verification. +sidebar: + order: 2 --- - -import CreateOAuth2ClientRequest from "../unified-login/_blocks/create-oauth2-client-request-m2m.mdx"; - -# Client credentials authentication - ## Overview In the **Client Credentials Flow** the authentication sequence works in the following way: + + + + + + + + + + -## `Service A` uses credentials to get an **OAuth2 Access Token** -## [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server) returns the **OAuth2 Access Token** -## `Service A` uses the **OAuth2 Access Token** to communicate with `Service B` -## `Service B` validates the **OAuth2 Access Token** -## If the token is valid `Service B` returns the requested resource + + + -Machine to Machine Authentication +Machine to Machine Authentication Before going into the actual instructions, start by imagining a real life example that you can reference along the way. This makes it easier to understand what is happening. @@ -45,9 +42,11 @@ Proceed to the actual steps. ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: -These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction). +These instructions assume that you already have gone through the main [quickstart guide](/quickstart/introduction). If you have skipped that page, please follow the tutorial and return here once you're done. @@ -61,12 +60,228 @@ You should be able to use the OAuth2 recipes in your applications. ### 2. Create the OAuth2 Clients -For each of your **`microservices`** you need to create a separate [**OAuth2 client**](/docs/authentication/unified-login/oauth2-basics#client). +For each of your **`microservices`** you need to create a separate [**OAuth2 client**](/authentication/unified-login/oauth2-basics#client). This can occur by directly calling the **SuperTokens Core** API. - + + + +```bash +curl --location --request POST '/recipe/oauth/clients' \ + --header 'api-key: ' \ + --header 'Content-Type: application/json; charset=utf-8' \ + --data ' + { + "clientName": "", + "grantTypes": ["client_credentials"], + "scope": " ", + "audience": [""], + } +' +``` + + + + + ```tsx + const BASE_URL = ''; + const API_KEY = ''; + + const url = `${BASE_URL}/recipe/oauth/clients`; + const options = { + method: 'POST', + headers: { + 'api-key': API_KEY, + 'Content-Type': 'application/json; charset=utf-8', + }, + body: JSON.stringify({ + clientName: "", + grantTypes: ["client_credentials"], + scope: " ", + audience: [""], + }) + }; + + fetch(url, options) + .then(response => response.json()) + .then(json => console.log(json)) + .catch(err => console.error(err)); +``` + + + + + ```go + + import ( + "fmt" + "net/http" + "strings" + "io" + ) + + func main() { + baseUrl := "" + apiKey := "" + url := fmt.Sprintf("%s/recipe/oauth/clients", baseUrl) + payload := `{ + "clientName": "", + "grantTypes": ["client_credentials"], + "scope": " ", + "audience": [""], + }` + + req, _ := http.NewRequest("POST", url, strings.NewReader(payload)) + + req.Header.Add("accept", "application/json") + req.Header.Add("api-key", apiKey) + req.Header.Add("content-type", "application/json") + + res, _ := http.DefaultClient.Do(req) + + defer res.Body.Close() + body, _ := io.ReadAll(res.Body) + + fmt.Println(string(body)) + } + ``` + + + + + ```python + import requests + from typing import Dict, Any + + BASE_URL = "" + API_KEY = "" + + url = f"{BASE_URL}/recipe/oauth/clients" + + payload: Dict[str, Any] ={ + "clientName": "", + "grantTypes": ["client_credentials"], + "scope": "custom_scope_1> ", + "audience": [""], + } + + headers = { + "api-key": API_KEY, + "Content-Type": "application/json", + } + + response = requests.post(url, json=payload, headers=headers) + + print(response.json()) + ``` + + + + + + Creates an OAuth2 client + + + + +**Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. -:::info Custom Example + + + + + + ## Request + + ### Body Schema + +| Name | Type | Description | Required | Default Value | +|--------------------------------------------|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------| +| `clientName` | `string` | A human-readable name of the client used for identification. | Yes | - | +| `grantTypes` | `array` of `GrantType` | The grant types that the Client uses. | Yes | - | +| `redirectUris` | `array` of `string` | List of URIs where the Authorization Server redirects after authorization. Can include mobile/desktop deep links. Must be exact URLs without wildcards. | Yes | - | | `scope` | `string` | Space-separated string of scopes the Client will request. Include `offline_access` to enable OAuth2 Refresh Token usage. | Yes | - | +| `scope` | `string` | String containing a space-separated list of scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use when requesting access tokens. Include the `offline_access` scope to exchange OAuth2 Refresh Tokens for OAuth2 Access Tokens | No | "" | +| `responseTypes` | `array` of `ResponseType` | The types of responses your client expects from the **Authorization Server** | No | - | +| `tokenEndpointAuthMethod` | `enum`(`"client_secret_basic"`, `"client_secret_post"`, `"private_key_jwt"`, `"none"`) | The requested client authentication method | No | `client_secret_basic` | +| `authorizationCodeGrantAccessTokenLifespan` | `Time Duration` | OAuth2 Access Token lifespan when using the Authorization Code grant flow. | No | `"1h"` | +| `authorizationCodeGrantIdTokenLifespan` | `Time Duration` | OAuth2 ID Token lifespan when using the Authorization Code grant flow. | No | `"1h"` | +| `authorizationCodeGrantRefreshTokenLifespan`| `Time Duration` | OAuth2 Refresh Token lifespan when using the Authorization Code grant flow. | If `refreshTokenGrantRefreshTokenLifespan` is also set | `"30d"` | +| `refreshTokenGrantRefreshTokenLifespan` | `Time Duration` | OAuth2 Refresh Token lifespan when using the Refresh Token grant flow. Must match `authorizationCodeGrantRefreshTokenLifespan`. | If `authorizationCodeGrantRefreshTokenLifespan` is also set | `"30d"` | +| `clientCredentialsGrantAccessTokenLifespan` | `Time Duration` | OAuth2 Access Token lifespan when using the Client Credentials grant flow. | No | `"1h"` | +| `enableRefreshTokenRotation` | `boolean` | Indicates that the refresh token is a one-time use. Set it to `false` to disable refresh token rotation. | No | `true` | + + +#### GrantType + +- `authorization_code`: allows exchanging the Authorization Code for an OAuth2 Access Token. +- `refresh_token`: allows exchanging the OAuth2 Refresh Token for an OAuth2 Access Token. +- `client_credentials`: allows the client to directly request an OAuth2 Access Token by authenticating itself with the Authorization Server using its own client credentials. + +#### TokenEndpointAuthMethod + +- `client_secret_basic`: uses the HTTP Basic Authentication scheme to authenticate the client. +- `client_secret_post`: uses the HTTP `POST` Authentication scheme to authenticate the client. +- `private_key_jwt`: uses JSON Web Tokens (JWT) to authenticate the client. +- `none`: indicates that the process of obtaining an OAuth2 Access Token does not use the client secret. Used for public clients (native apps or mobile apps). + +#### ResponseType + +- `code`: Indicates that the Client receives an Authorization Code that it exchanges for an OAuth2 Access Token. +- `id_token`: Indicates that the Client expects an ID Token. + +#### Time Duration + +A string value that signifies time duration in milliseconds, seconds, minutes, or hours: `"2000ms"`, `"60s"`, `"30m"`, `"1h"`. + +### Example + +```bash +curl -X POST /recipe/oauth/clients \ + -H "Content-Type: application/json" \ + -H "api-key: " \ + -d '{ + "clientName": "", + "responseTypes": ["code"], + "grantTypes": ["authorization_code", "refresh_token"], + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + }' +``` + +## Response + +### 200 + +The client has been successfully created. + +### Response schema + +| Property | Type | Description | +|-------------|----------------------------------|-----------------------------------------------| +| `clientName` | `string` | The name of the client. | +| `clientId` | `string` | Unique identifier for the client. | +| `clientSecret` | `string` | The secret is part of the create request as plain text, and then never again. The secret remains in hashed format and is not recoverable once lost. | +| `redirectUris` | `array` of `string` | The URLs used for redirection. | +| `audience` | `array` of `string` | Value used to identify for whom a token is issued. The created client can generate access token only for the specified audiences. | +| `scope` | `array` of `string` | A space separated string of scopes that the Client requests access to. | + +#### Example + +```json +{ + "clientName": "", + "clientId": "", + "redirectUris": ["https:///oauth/callback"], + "audience": [""], + "scope": ["offline_access "], +} +``` + + + + + +:::info[Custom Example] To create a client for the **Task Service**, use the following attributes: @@ -83,19 +298,18 @@ This allows the **Task Service** to perform all types of actions against both of ::: -:::caution -You have to save the create response because this is not persisted internally for security reasons. +:::warning[You have to save the create response because this is not persisted internally for security reasons.] The information is necessary for the next steps. ::: ### 3. Set Up your Authorization Service -In your [**Authorization Server**](/docs/authentication/unified-login/oauth2-basics#authorization-server) backend, initialize the **OAuth2Provider** recipe. +In your [**Authorization Server**](/authentication/unified-login/oauth2-basics#authorization-server) backend, initialize the **OAuth2Provider** recipe. - + - + Update the `supertokens.init` call to include the new recipe. @@ -119,22 +333,20 @@ supertokens.init({ }); ``` - - - + -:::caution + -At the moment, there is no support for creating OAuth2 providers in the Go SDK. -You can use the [legacy method](/docs/microservice_auth/legacy/implementation-guide) to authenticate microservices based on your language. +:::warning[At the moment, there is no support for creating OAuth2 providers in the Go SDK.] +You can use the [legacy method](/authentication/m2m/legacy-flow) to authenticate microservices based on your language. ::: - + - + -```python +```python from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import oauth2provider @@ -155,19 +367,18 @@ init( ) ``` - + - + ### 4. Generate access tokens - -You can directly call the [**Authorization Server**](/docs/authentication/unified-login/oauth2-basics#authorization-server) to generate Access Tokens. +You can directly call the [**Authorization Server**](/authentication/unified-login/oauth2-basics#authorization-server) to generate Access Tokens. Check the following code snippet to see how you can do that: ```bash -curl -X POST ^{appInfo.apiDomain}^{appInfo.apiBasePath}/oauth/token \ +curl -X POST /auth/oauth/token \ -H "Content-Type: application/json" \ -d '{ "client_id": "", @@ -180,7 +391,7 @@ curl -X POST ^{appInfo.apiDomain}^{appInfo.apiBasePath}/oauth/token \ You should limit the scopes that you are requesting to the ones necessary to perform the desired action. -:::info Custom Example +:::info[Custom Example] If the **Task Service** wants to create an event on the **Calendar Service**, a token with the following attributes needs generation: @@ -224,16 +435,16 @@ It ensures that the validation occurs for the correct token type: - `1` represents an **OAuth2 Access Token** - `2` represents an **OAuth2 ID Token**. - + - + For NodeJS you can use [`jose`](https://github.com/panva/jose) to verify the token. ```tsx import * as jose from "jose"; -const JWKS = jose.createRemoteJWKSet(new URL('^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json')) +const JWKS = jose.createRemoteJWKSet(new URL('/auth/jwt/jwks.json')) async function validateClientCredentialsToken(jwt: string) { const requiredScope = ""; @@ -255,9 +466,9 @@ async function validateClientCredentialsToken(jwt: string) { } ``` - + - + You can use the [`jwx`](https://github.com/lestrrat-go/jwx) library to verify the token. @@ -271,8 +482,8 @@ import ( ) func ValidateToken(token string) bool { - apiDomain := "^{appInfo.apiDomain}" - apiBasePath := "^{appInfo.apiBasePath}" + apiDomain := "" + apiBasePath := "/auth" requiredScope := "" jwksURL := fmt.Sprintf("%s%sjwt/jwks.json", apiDomain, apiBasePath) @@ -311,20 +522,20 @@ func ValidateToken(token string) bool { } ``` - + - + You can use the [PyJWT](https://github.com/jpadilla/pyjwt) library to verify the token. -```python +```python from typing import Optional, List import jwt from jwt import PyJWKClient def validate_token(token: str) -> bool: - api_domain = "^{appInfo.apiDomain}" - api_base_path = "^{appInfo.apiBasePath}" + api_domain = "" + api_base_path = "/auth" audience = "" required_scope = "" @@ -354,9 +565,9 @@ def validate_token(token: str) -> bool: return False ``` - + - + You can use the [Firebase JWT](https://github.com/firebase/php-jwt) library to verify the token. @@ -367,8 +578,8 @@ use Firebase\JWT\JWT; use Firebase\JWT\Key; function validateToken($jwt) { - $apiDomain = "^{appInfo.apiDomain}"; - $apiBasePath = "^{appInfo.apiBasePath}"; + $apiDomain = ""; + $apiBasePath = "/auth"; $jwksUrl = $apiDomain . $apiBasePath . '/jwt/jwks.json'; $requiredScope = ""; $audience = ""; @@ -389,9 +600,9 @@ function validateToken($jwt) { } ``` - + - + You can use the [Auth0 JWT](https://github.com/auth0/java-jwt) library to verify the token. @@ -411,7 +622,7 @@ import java.util.Scanner; public class JWTVerifier { - private static final String JWKS_URL = "^{appInfo.apiDomain}^{appInfo.apiBasePath}jwt/jwks.json"; + private static final String JWKS_URL = "/authjwt/jwks.json"; private static final String AUDIENCE = ""; private static Map fetchJWKS() throws Exception { @@ -449,9 +660,9 @@ public class JWTVerifier { } ``` - + - + You can use the [IdentityModel](https://github.com/IdentityModel/IdentityModel) library to verify the token. @@ -511,11 +722,11 @@ class ClientCredentialsTokenValidator } ``` - + - + -:::info Custom Example +:::info[Custom Example] If the **Task Service** uses the previously generated token to create a calendar event, the **Calendar Service** needs to check the following: - Set the `stt` claim to `1` @@ -534,9 +745,9 @@ This is necessary because two types of tokens are in use: Hence, a way to distinguish between these two and prevent errors is necessary. - + - + ```tsx import supertokens from "supertokens-node"; @@ -580,7 +791,7 @@ async function verifySession(req: Request, res: Response, next: NextFunction) { } const JWKS = jose.createRemoteJWKSet( - new URL("^{appInfo.apiDomain}^{appInfo.apiBasePath}jwt/jwks.json"), + new URL("/authjwt/jwks.json"), ); // This is a basic example on how to validate an OAuth2 Token @@ -610,9 +821,9 @@ app.get("/protected", verifySession, async (req, res) => { }); ``` - + - + ```python from supertokens_python.recipe.session.syncio import get_session @@ -689,17 +900,15 @@ def validate_token(token: str, required_scope: str) -> bool: ``` - - - + -:::caution + -At the moment, there is no support for creating OAuth2 providers in the Go SDK. +:::warning[At the moment, there is no support for creating OAuth2 providers in the Go SDK.] ::: - + - + diff --git a/docs/authentication/m2m/introduction.mdx b/docs/authentication/m2m/introduction.mdx index 3b28728a7f..25e41b3583 100644 --- a/docs/authentication/m2m/introduction.mdx +++ b/docs/authentication/m2m/introduction.mdx @@ -1,19 +1,10 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -skip_llms_txt: true -description: >- - Authenticate microservices using SuperTokens with the OAuth2 Client - Credentials Flow. -page_type: overview -recipe: oauth2 -category: machine-to-machine +description: Authenticate microservices using SuperTokens with the OAuth2 Client Credentials Flow. +sidebar: + order: 1 --- - -# Machine to machine authentication - ## Overview The recommended way to authenticate microservices with **SuperTokens** is by using the **OAuth2** specification. @@ -21,14 +12,16 @@ You have to create an **OAuth2 Provider** and use the **OAuth2 Client Credential ## Prerequisites - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: Before you can dive deeper in the functionality there are a few things to keep in mind: - The feature is available with the **SuperTokens Managed Service**. It is not included in the **Self-Hosted** version. - You can use it with the `Node.js` or the `Python` backend SDKs. -If you do not meet the previous requirements you can use the [legacy flow](/docs/authentication/m2m/legacy-flow). +If you do not meet the previous requirements you can use the [legacy flow](/authentication/m2m/legacy-flow). ## Getting started @@ -39,31 +32,14 @@ The **Legacy Flow** guide is here for backwards compatibility and it is going to Before you explore a guide, read through the **OAuth2 Basics** page first. It explains concepts used in each tutorial. - - - - OAuth2 Basics
-
- - Go through a quick summary of the OAuth2 specifications to get accustomed with the language used in the quickstart guides. - -
- - - Client Credentials Flow - - - Implement a common authentication service that all your microservices can use. - - - - - Legacy Flow - - - Legacy info - - -
- - + + +Go through a quick summary of the OAuth2 specifications to get accustomed with the language used in the quickstart guides. + + +Implement a common authentication service that all your microservices can use. + + +Legacy info + + diff --git a/docs/authentication/m2m/legacy-flow.mdx b/docs/authentication/m2m/legacy-flow.mdx index 9c4b1b81dd..0272bb80b4 100644 --- a/docs/authentication/m2m/legacy-flow.mdx +++ b/docs/authentication/m2m/legacy-flow.mdx @@ -1,19 +1,10 @@ --- title: Legacy Flow -hide_title: true -sidebar_position: 3 -toc_max_heading_level: 4 -description: >- - Guide for implementing JWT-based authentication between microservices using - SuperTokens Core. -page_type: tutorial -recipe: oauth2 -category: machine-to-machine +description: Guide for implementing JWT-based authentication between microservices using SuperTokens Core. +sidebar: + order: 3 --- - -# Legacy flow - ## Overview This custom flow makes use of the **SuperTokens Core** without adhering to the **OAuth2** standard. @@ -27,7 +18,7 @@ The authentication sequence works in the following way: ## Microservice `M2` verifies the JWT and completes the action if the JWT is valid -Microservice auth flow diagram +Microservice auth flow diagram The first step is to create a JWT from the microservice that sends the request (refer to this microservice as `M1`). Other microservices verify this JWT when `M1` sends them a request. @@ -71,17 +62,17 @@ This type of restriction can occur by deploying multiple cores connected to thei ### 1. Create a JWT - + - + First, initialize the `JWT` recipe in the `supertokens.init` function call: - + - + -```tsx +```tsx {15} import supertokens from "supertokens-node" import jwt from "supertokens-node/recipe/jwt" @@ -96,16 +87,15 @@ supertokens.init({ apiKey: "..." // provide the core's API key if configured }, recipeList: [ - // highlight-next-line jwt.init() ] }) ``` - - + + -```go +```go {18} import ( "github.com/supertokens/supertokens-golang/recipe/jwt" "github.com/supertokens/supertokens-golang/supertokens" @@ -123,17 +113,16 @@ func main() { APIKey: "...", // provide the core's API key if configured }, RecipeList: []supertokens.Recipe{ - // highlight-next-line jwt.Init(nil), }, }) } ``` - - + + -```python +```python {16} from supertokens_python import InputAppInfo, SupertokensConfig, init from supertokens_python.recipe import jwt @@ -149,24 +138,22 @@ init( ), framework='django', recipe_list=[ - # highlight-next-line jwt.init(), ], ) ``` - - + + -:::important -- The value of `apiDomain` should be the domain part of the JWKS URL used to verify the JWT (from `M2`). This should ideally be the domain of the microservice that has all the other SuperTokens' recipes initialized in them. +:::note[- The value of `apiDomain` should be the domain part of the JWKS URL used to verify the JWT (from `M2`). This should ideally be the domain of the microservice that has all the other SuperTokens' recipes initialized in them.] - If this microservice does not initialize any other recipe, the values of `appName` and `websiteDomain` don't matter. ::: After this, you can use the JWT recipe to create your own JWT whenever required: - - + + ```tsx import jwt from "supertokens-node/recipe/jwt" @@ -184,8 +171,8 @@ async function createJWT(payload: any) { } ``` - - + + ```go import ( @@ -208,11 +195,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.jwt import asyncio @@ -232,8 +219,8 @@ async def create_jwt(): raise Exception("Unable to create JWT. Should never come here.") ``` - - + + ```python from supertokens_python.recipe.jwt.interfaces import CreateJwtOkResult @@ -251,23 +238,21 @@ else: raise Exception("Unable to create JWT. Should never come here.") ``` - - + + - - + + -:::note -By default, the lifetime of the JWT is a 100 years. You can pass a second argument to the `createJWT` function indicating a custom lifetime (in seconds) for the JWT. +:::note[By default, the lifetime of the JWT is a 100 years. You can pass a second argument to the `createJWT` function indicating a custom lifetime (in seconds) for the JWT.] ::: -:::note -By default, the JWT uses a static key for signing, not subject to the key rotation normally applied to access tokens. You can pass `false` as the third argument to the `createJWT` function to use the dynamic keys. +:::note[By default, the JWT uses a static key for signing, not subject to the key rotation normally applied to access tokens. You can pass `false` as the third argument to the `createJWT` function to use the dynamic keys.] ::: - + - + You can send a `HTTP` request to the core as follows: @@ -301,9 +286,9 @@ An example response is as follows: ``` - + - + ### 2. Store the JWT @@ -321,7 +306,6 @@ curl --location --request POST 'https://microservice_location/path' \ ### 3. Verify JWTs - When a target microservice receives a JWT, it must first verify it before proceeding to serve the request. The process involves two steps: - A standard verification of the JWT @@ -329,12 +313,12 @@ When a target microservice receives a JWT, it must first verify it before procee #### Using JWKS endpoint - - + + ##### Get JWKS endpoint -The JWKS endpoint is `^{appInfo.apiDomain}/^{appInfo.apiBasePath}/jwt/jwks.json`. Here the `apiDomain` and `apiBasePath` are values pointing to the server in which you have initialized SuperTokens using the backend SDK. +The JWKS endpoint is `//auth/jwt/jwks.json`. Here the `apiDomain` and `apiBasePath` are values pointing to the server in which you have initialized SuperTokens using the backend SDK. ##### Verify the JWT @@ -345,7 +329,7 @@ import JsonWebToken, { JwtHeader, SigningKeyCallback } from 'jsonwebtoken'; import jwksClient from 'jwks-rsa'; var client = jwksClient({ - jwksUri: '^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json' + jwksUri: '/auth/jwt/jwks.json' }); function getKey(header: JwtHeader, callback: SigningKeyCallback) { @@ -362,8 +346,8 @@ JsonWebToken.verify(jwt, getKey, {}, function (err, decoded) { }); ``` - - + + Refer to this [GitHub gist](https://gist.github.com/rishabhpoddar/ea31502923ec9a53136371f2b6317ffa) for a code reference of how use `PyJWK` to do JWT verification. The gist contains two files: - `jwt_verification.py` (which you can copy/paste into your application). You have to modify the `JWKS_URI` in this file to point to your SuperTokens core instance (replacing the `try.supertokens.com` part of the URL). This file is for `sync` python apps, and you can modify it to work with `async` apps as well. @@ -371,8 +355,8 @@ Refer to this [GitHub gist](https://gist.github.com/rishabhpoddar/ea31502923ec9a - This function takes care of caching public keys in memory + auto `refetching` if the public keys have changed (which happens automatically every 24 hours with SuperTokens). This does not cause any user logouts, and is just a security feature. - `views.py`: This is an example `GET` API which extracts the JWT token from the authorization header in the request and calls the `verify_jwt` function from the other file. - - + + Refer to this [GitHub gist](https://gist.github.com/rishabhpoddar/8c26ed237add1a5b86481e72032abf8d) for a code reference of how use the Golang `jwt` lib to do session verification. The gist contains two files: - `verifyToken.go` (which you can copy/paste into your application). You have to modify the `coreUrl` in this file to point to your SuperTokens core instance (replacing the `try.supertokens.com` part of the URL). @@ -380,19 +364,19 @@ Refer to this [GitHub gist](https://gist.github.com/rishabhpoddar/8c26ed237add1a - This function takes care of caching public keys in memory + auto `refetching` if the public keys have changed (which happens automatically every 24 hours with SuperTokens). This does not cause any user logouts, and is just a security feature. - `main.go`: This is an example of how to verify a JWT using the golang JWT verification lib along with a helper function to get the JWKs keys. - - + + #### Using public key string - - + + Some JWT verification libraries require you to provide the JWT secret / public key for verification. You can obtain the JWT secret from SuperTokens in the following way: - First, query the `JWKS.json` endpoint: ```bash - curl --location --request GET '^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json' + curl --location --request GET '/auth/jwt/jwks.json' { "keys": [ @@ -416,8 +400,7 @@ Some JWT verification libraries require you to provide the JWT secret / public k } ``` - :::important - The above shows an example output which returns two keys. There could be more keys returned based on the configured key rotation setting in the core. If you notice, each key's `kid` starts with a `s-..` or a `d-..`. The `s-..` key is a static key that never changes, whereas `d-...` keys are dynamic keys that keep changing. If you are `hardcoding` public keys somewhere, you always want to pick the `s-..` key. + :::note[The above shows an example output which returns two keys. There could be more keys returned based on the configured key rotation setting in the core. If you notice, each key's `kid` starts with a `s-..` or a `d-..`. The `s-..` key is a static key that never changes, whereas `d-...` keys are dynamic keys that keep changing. If you are `hardcoding` public keys somewhere, you always want to pick the `s-..` key.] ::: - Next, run the NodeJS script below to convert the above output to a `PEM` file format. @@ -434,7 +417,6 @@ Some JWT verification libraries require you to provide the JWT secret / public k "use": "sig" }; - // @ts-ignore let certString = jwkToPem(jwk); ``` @@ -463,36 +445,34 @@ Some JWT verification libraries require you to provide the JWT secret / public k }); ``` - - + + -:::caution -Not applicable. Please use method 1 instead. +:::warning[Not applicable. Please use method 1 instead.] ::: - - + + -:::caution -Not applicable. Please use method 1 instead. +:::warning[Not applicable. Please use method 1 instead.] ::: - - + + #### Claim verification The second step is to get the JWT payload and check that it has the `"source": "microservice"` claim: - - + + -```tsx +```tsx {17,18,19,20,21,22} import JsonWebToken, { JwtHeader, SigningKeyCallback } from 'jsonwebtoken'; import jwksClient from 'jwks-rsa'; var client = jwksClient({ - jwksUri: '^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json' + jwksUri: '/auth/jwt/jwks.json' }); function getKey(header: JwtHeader, callback: SigningKeyCallback) { @@ -504,29 +484,27 @@ function getKey(header: JwtHeader, callback: SigningKeyCallback) { let jwt = "..."; JsonWebToken.verify(jwt, getKey, {}, function (err, decoded) { - // highlight-start let decodedJWT = decoded; if (decodedJWT === undefined || typeof decodedJWT === "string" || decodedJWT.source === undefined || decodedJWT.source !== "microservice") { // return a 401 unauthorised error } else { // handle API request... } - // highlight-end }); ``` - - + + Referring once again to this [GitHub gist](https://gist.github.com/rishabhpoddar/ea31502923ec9a53136371f2b6317ffa), in `views.py`, between lines 20 and 28, the value of a certain claim in the decoded JWT payload undergoes a check. You can do something similar and check for the `source` claim whose value must be `microservice`. If it is, then all's good, else you can return a 401. - - + + Referring once again to this [GitHub gist](https://gist.github.com/rishabhpoddar/8c26ed237add1a5b86481e72032abf8d), in `main.go`, between lines 32 and 44, the value of a certain claim in the decoded JWT payload undergoes a check. You can do something similar and check for the `source` claim whose value must be `microservice`. If it is, then all's good, else you can return a 401. - - + + #### M2M and frontend session verification for the same API You may have a setup wherein the same API receives calls from the frontend as well as from other microservices. The frontend session works differently than m2m sessions, therefore both forms of token inputs must be accounted for. @@ -535,10 +513,10 @@ The approach here would be to first attempt frontend session verification, and i The [`getSession` function](https://supertokens.com/docs/session/common-customizations/sessions/session-verification-in-api/get-session) serves for frontend session verification. - - + + -```tsx +```tsx {22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44} import express from "express"; import Session from "supertokens-node/recipe/session"; import JsonWebToken, { JwtHeader, SigningKeyCallback } from 'jsonwebtoken'; @@ -548,7 +526,7 @@ let app = express(); var client = jwksClient({ - jwksUri: '^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json' + jwksUri: '/auth/jwt/jwks.json' }); function getKey(header: JwtHeader, callback: SigningKeyCallback) { @@ -560,7 +538,6 @@ function getKey(header: JwtHeader, callback: SigningKeyCallback) { app.post("/like-comment", async (req, res, next) => { - // highlight-start try { let session = await Session.getSession(req, res, { sessionRequired: false }) @@ -584,7 +561,6 @@ app.post("/like-comment", async (req, res, next) => { } catch (err) { next(err); } - // highlight-end }); ``` @@ -592,8 +568,8 @@ app.post("/like-comment", async (req, res, next) => { - If the `getSession` function returns `undefined`, it means that the session is not from the frontend and a microservice auth verification can occur using the JWT verification method shown previously in this page. - If that fails too, send back a `401` response. - - + + ```python from typing import Optional, cast @@ -609,7 +585,7 @@ async def like_comment(request: HttpRequest): if session is not None: user_id = session.get_user_id() else: - jwt: Optional[str] = cast(Optional[str], request.headers.get("Authorization")) # type: ignore + jwt: Optional[str] = cast(Optional[str], request.headers.get("Authorization")) if jwt is None: # return a 401 unauthorised error... pass @@ -625,8 +601,8 @@ async def like_comment(request: HttpRequest): - If the `getSession` function returns `None`, it means that the session is not from the frontend and a microservice auth verification can occur using the JWT verification method shown previously in this page. - If that fails too, send back a `401` response. - - + + ```go import ( @@ -689,5 +665,5 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { - If the `getSession` function returns `nil`, it means that the session is not from the frontend and a microservice auth verification can occur using the JWT verification method shown previously in this page. - If that fails too, send back a `401` response. - - + + diff --git a/docs/authentication/m2m/meta.ts b/docs/authentication/m2m/meta.ts new file mode 100644 index 0000000000..1072b58fbc --- /dev/null +++ b/docs/authentication/m2m/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Machine to Machine", + "icon": "bot", + "order": 7 +}); diff --git a/docs/authentication/meta.ts b/docs/authentication/meta.ts new file mode 100644 index 0000000000..5fce662d65 --- /dev/null +++ b/docs/authentication/meta.ts @@ -0,0 +1,8 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Authentication", + "icon": "key-round", + "order": 3, + "collapsed": true +}); diff --git a/docs/authentication/overview.mdx b/docs/authentication/overview.mdx index 64773e0707..367ed546f9 100644 --- a/docs/authentication/overview.mdx +++ b/docs/authentication/overview.mdx @@ -1,125 +1,57 @@ --- title: Overview -sidebar_position: 1 -pagination_next: null -pagination_prev: null -hide_table_of_contents: true -description: >- - Explore various user authentication methods with SuperTokens, including - email/password, social login, and more. -page_type: overview -category: authentication +description: Explore various user authentication methods with SuperTokens, including email/password, social login, and more. +sidebar: + order: 1 --- - -# Overview - Discover all the ways in which you can authenticate your users with **SuperTokens**. ## Authentication Methods - - - - Email/Password - - - Basic authentication using email and password. - - - - - Passwordless - - - Authentication through magic links or one-time codes. - - - - - - Social Login - - - Login flow that uses third-party providers for authentication. - - - - - Passkeys - - - Passwordless authentication using biometrics, security keys, or device-based credentials. - - - - - - Enterprise Login - - - Instructions on how to configure your application to support multiple tenants and enterprise authentication methods. - - - - - Unified Login - - - Details on how to create a common authentication experience for all your products. - - - - - - Machine to Machine Authentication - - - Guides on authenticating microservices using SuperTokens. - - - + + +Basic authentication using email and password. + + +Authentication through magic links or one-time codes. + + +Login flow that uses third-party providers for authentication. + + +Passwordless authentication using biometrics, security keys, or device-based credentials. + + +Instructions on how to configure your application to support multiple tenants and enterprise authentication methods. + + +Details on how to create a common authentication experience for all your products. + + +Guides on authenticating microservices using SuperTokens. + + ## Additional Resources For information on other features exposed by SuperTokens, please refer to the following resources: - - - - Multi-Factor Authentication - - - Set up additional verification layers in your sign-in process. - - - - - Attack Protection Suite - - - Enable additional security features that shield your app. - - - - - - Self Hosting - - - Deploy SuperTokens in your own infrastructure. - - - - - - Migration Guide - - - Learn how to migrate from an existing authentication provider. - - + + +Set up additional verification layers in your sign-in process. + + +Enable additional security features that shield your app. + + +Deploy SuperTokens in your own infrastructure. + + + +Learn how to migrate from an existing authentication provider. + - + diff --git a/docs/authentication/passkeys/_category_.json b/docs/authentication/passkeys/_category_.json deleted file mode 100644 index 71a1f5055d..0000000000 --- a/docs/authentication/passkeys/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Passkeys", - "position": 7 -} diff --git a/docs/authentication/passkeys/customization.mdx b/docs/authentication/passkeys/customization.mdx index fe0a2fc0c7..450102105c 100644 --- a/docs/authentication/passkeys/customization.mdx +++ b/docs/authentication/passkeys/customization.mdx @@ -1,15 +1,9 @@ --- title: Customization -hide_title: true -sidebar_position: 4 -page_type: guide -recipe: webauthn -category: passkeys +sidebar: + order: 4 --- - -# Customization - ## Overview Like the other **SuperTokens** authentication recipes, you can customize the `WebAuthn` flow through different configuration options and overrides. @@ -19,9 +13,9 @@ The following page describes the options that you can change and the different s ## Backend recipe configuration - + - + ```ts import supertokens from "supertokens-node"; @@ -67,24 +61,22 @@ The backend recipe accepts the following properties during initialization: | `getRelyingPartyId` | Sets the domain name associated with the WebAuthn credentials. This helps ensure that only your domain uses the credentials. | The `apiDomain` value that you have set in `appConfig` | | `getRelyingPartyName` | Sets a human-readable name for your application. The name appears to users during the WebAuthn registration process. | The `appName` value that you have set in `appConfig` | | `getOrigin` | Configures the origin URL that WebAuthn credentials bind to. This should match your application's domain and protocol. | Origin of the request | -| `emailDelivery` | Configures how the system builds and sends verification emails to users. Read the [email delivery page](/docs/platform-configuration/email-delivery) for more information. | Default email service | +| `emailDelivery` | Configures how the system builds and sends verification emails to users. Read the [email delivery page](/platform-configuration/email-delivery) for more information. | Default email service | | `validateEmailAddress` | Adds custom validation logic for email addresses. | Basic email format validation | All the properties are optional. - + - + -:::caution - -At the moment there is no support for using passkeys authentication in the Go SDK. +:::warning[At the moment there is no support for using passkeys authentication in the Go SDK.] ::: - + - + ```python from typing import Optional @@ -139,14 +131,14 @@ The backend recipe accepts the following properties during initialization: | `get_relying_party_id` | Sets the domain name associated with the WebAuthn credentials. This helps ensure that only your domain uses the credentials. | The `api_domain` value that you have set in `app_config` | | `get_relying_party_name` | Sets a human-readable name for your application. The name appears to users during the WebAuthn registration process. | The `app_name` value that you have set in `app_config` | | `get_origin` | Configures the origin URL that WebAuthn credentials bind to. This should match your application's domain and protocol. | Origin of the request | -| `email_delivery` | Configures how the system builds and sends verification emails to users. Read the [email delivery page](/docs/platform-configuration/email-delivery) for more information. | Default email service | +| `email_delivery` | Configures how the system builds and sends verification emails to users. Read the [email delivery page](/platform-configuration/email-delivery) for more information. | Default email service | | `validate_email_address` | Adds custom validation logic for email addresses. | Basic email format validation | All the properties are optional. - + - + --- @@ -157,9 +149,9 @@ The frontend SDK uses the [`navigator.credentials.created`](https://developer.mo To change the options used to generate credentials, you need to override the `registerOptions` function. - + - + ```ts import supertokens from "supertokens-node"; @@ -227,19 +219,17 @@ supertokens.init({ | `displayName` | `string` | The display name of the user. | The user's `email` property | - - - + -:::caution + -At the moment there is no support for using passkeys authentication in the Go SDK. +:::warning[At the moment there is no support for using passkeys authentication in the Go SDK.] ::: - + - + ```python from typing import List, Optional, cast @@ -339,9 +329,9 @@ init( | `display_name` | `str` | The display name of the user. | The user's `email` property | - + - + --- @@ -354,9 +344,9 @@ The server generates the options for signing the challenge through the backend S To change those, you need to override the `signInOptions` function. - + - + ```ts import supertokens from "supertokens-node"; @@ -412,19 +402,17 @@ supertokens.init({ | `timeout` | `number` | The time in milliseconds that the user has to complete the credential validation process. | `6000` | | `userVerification` | `"discouraged" \| "preferred" \| "required"` | The parameter controls whether user verification (like `PIN` or biometrics) is necessary. | `preferred` | - + - + -:::caution - -At the moment there is no support for using passkeys authentication in the Go SDK. +:::warning[At the moment there is no support for using passkeys authentication in the Go SDK.] ::: - + - + ```python from typing import Any @@ -495,8 +483,6 @@ init( | `timeout` | `int` | The time in milliseconds that the user has to complete the credential validation process. | `6000` | | `user_verification` | `"discouraged" \| "preferred" \| "required"` | The parameter controls whether user verification (like `PIN` or biometrics) is necessary. | `preferred` | - - - - + + diff --git a/docs/authentication/passkeys/important-concepts.mdx b/docs/authentication/passkeys/important-concepts.mdx index f3d4dd7034..d2bdc3c0ee 100644 --- a/docs/authentication/passkeys/important-concepts.mdx +++ b/docs/authentication/passkeys/important-concepts.mdx @@ -1,14 +1,9 @@ --- title: Important concepts -hide_title: true -sidebar_position: 2 -page_type: guide -recipe: webauthn -category: passkeys +sidebar: + order: 2 --- -# Important concepts - ## Overview Use this page to get a high-level overview of the key concepts involved in the WebAuthn documentation. @@ -34,57 +29,49 @@ This makes it convenient and recoverable in case of device loss. Aside from the ease of use, passkeys are integrated into operating systems and browsers, and, support a wide range of devices. - ### Additional terms - - -## Credentials - + + The technical term for the cryptographic key pairs used in **WebAuthn**. They represent the raw cryptographic material and, unlike **passkeys**, are device-specific and not synced. Additionally, sometimes, multiple credentials can be part of a single passkey. -:::info Note +:::info[Note] This documentation uses **passkey** and **credential** interchangeably, even though subtle technical differences exist. ::: - -## Authenticator - + + A device or software that implements the **WebAuthn** authentication. This can be: - **Platform Authenticator**: Built-in biometric sensors like TouchID, FaceID, or Windows Hello. - **Roaming Authenticator**: External security devices like YubiKeys or Google Titan keys. - -## Registration - + + The process where a user registers their **authenticator** with your application. During this process: 1. The server generates a challenge for the **authenticator** to sign. 2. The **authenticator** creates a new credential. 3. The system saves the public key and any additional metadata for future authentication. - -## Authentication - + + The process where a user proves their identity, using their **authenticator**, by responding to a **server challenge**. Using their private key, they sign the **challenge** and then send the result to the server. The server then verifies the signature with the stored public key.
- -## Attestation - +
+ **Attestation** represents information about the **authenticator device** itself. You can use it to verify the authenticity and the security level of the **authenticator**.
- -## User verification - +
+ **User verification** is the method used to verify the user's presence. This can be: - Biometric verification (fingerprint, face scan). - `PIN` entry. - Physical button press on a security key. - +
## Authentication flows @@ -94,31 +81,43 @@ This section explains how each component communicates during different authentic ### Login - -## The frontend SDK requests registration options from the backend. + The options are then returned based on the response from the **SuperTokens** core service. -## The **authenticator** uses the response to sign a challenge with your **passkey**. -## The result of the **authenticator** operation gets validated by the **SuperTokens** core service. -## The authentication UI updates, based on the result of the validation process. + + + + + + + + + -![Sign in form UI for passkeys login](/img/webauthn-signin.png) +![Sign in form UI for passkeys login](/docs/img/webauthn-signin.png) ### Sign up + -## The user enters their email address in frontend authentication UI -## The frontend SDK uses the email to request **registration** options from the backend. + + The options are then returned based on the response from the **SuperTokens** core service. -## The **authenticator** uses the response to sign a **challenge** with your **passkey**. -## The result of the **authenticator** operation gets validated on by the **SuperTokens** core service. -## The authentication UI updates, based on the result of the validation process. + + + + + + + + + -![Passkeys sign up flow](/img/webauthn-signup.png) +![Passkeys sign up flow](/docs/img/webauthn-signup.png) ### Account recovery @@ -126,15 +125,17 @@ Account recovery should use an email. In it, the user receives a link that directs them to a page where they can register a new credential. + -## The frontend initiates the recovery flow by communicating with the backend SDK -## The backend checks if the email exists and then sends a recovery email. + + The email includes a security token obtained from the **SuperTokens** core. -## When the user accesses the recovery link, they get directed to the frontend application. + + The security token gets validated by the backend SDK. If successful, the SDK begins the process of registering a new credential. From here, the flow matches the one described in the previous sections. - + -![Sign in form UI for passkeys login](/img/webauthn-recover-account.png) +![Sign in form UI for passkeys login](/docs/img/webauthn-recover-account.png) diff --git a/docs/authentication/passkeys/initial-setup.mdx b/docs/authentication/passkeys/initial-setup.mdx index 0bcc43cc63..b78114f99e 100644 --- a/docs/authentication/passkeys/initial-setup.mdx +++ b/docs/authentication/passkeys/initial-setup.mdx @@ -1,17 +1,9 @@ --- title: Initial Setup -hide_title: true -sidebar_position: 3 -page_type: tutorial -recipe: webauthn -category: passkeys +sidebar: + order: 3 --- - -import ReactRouterCallout from "/docs/_blocks/react-router-callout.mdx"; - -# Quickstart - ## Overview This page shows you how to add the **Passkeys** authentication method to your project. @@ -19,36 +11,34 @@ The tutorial creates a login flow, rendered by either the **Prebuilt UI** compon ## Before you start -These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction). +These instructions assume that you already have gone through the main [quickstart guide](/quickstart/introduction). If you have skipped that page please follow the tutorial and return here once you're done. -:::info SDK Support +:::info[SDK Support] WebAuthn (Passkeys) authentication is available in the **Node.js SDK** and **Python SDK**. ::: - ## Steps ### 1. Initialize the frontend SDK - + - + - - + + #### 1.1 Add the `WebAuthn` recipe in your main configuration file. -```tsx +```tsx {4,14} import React from 'react'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; -// highlight-next-line import WebAuthn from "supertokens-auth-react/recipe/webauthn"; import Session from "supertokens-auth-react/recipe/session"; @@ -59,9 +49,7 @@ SuperTokens.init({ appName: "...", }, recipeList: [ - // highlight-start WebAuthn.init(), - // highlight-end Session.init() ] }); @@ -73,9 +61,9 @@ In order for the **pre-built UI** to render inside your application, you have to The **React SDK** uses [**React Router**](https://reactrouter.com/en/main) under the hood to achieve this. Based on whether you already use this package or not in your project, there are two different ways of configuring the routes. - - -```tsx + + +```tsx {9,21} import React from 'react'; import { BrowserRouter, @@ -84,7 +72,6 @@ import { Link } from "react-router-dom"; -// highlight-next-line import { WebauthnPreBuiltUI } from 'supertokens-auth-react/recipe/webauthn/prebuiltui'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; @@ -96,8 +83,7 @@ class App extends React.Component { - {/*This renders the login UI on the ^{appInfo.websiteBasePath} route*/} - // highlight-next-line + {/*This renders the login UI on the /auth route*/} {getSuperTokensRoutesForReactRouterDom(reactRouterDom, [WebauthnPreBuiltUI])} {/*Your app routes*/} @@ -108,26 +94,57 @@ class App extends React.Component { } ``` - - - - + :::note[If you are using `useRoutes`, `createBrowserRouter` or have routes defined in a different file, you need to adjust the code sample.] +Please see [this issue](https://github.com/supertokens/supertokens-auth-react/issues/581#issuecomment-1246998493) for further details. ```tsx import React from 'react'; + +import { BrowserRouter, useRoutes } from "react-router-dom"; +import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; +import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; +import * as reactRouterDom from "react-router-dom"; + +function AppRoutes() { + const authRoutes = getSuperTokensRoutesForReactRouterDom( + reactRouterDom, + [/* Add your UI recipes here e.g. EmailPasswordPrebuiltUI, PasswordlessPrebuiltUI, ThirdPartyPrebuiltUI */] + ); + + const routes = useRoutes([ + ...authRoutes.map(route => route.props), + // Include the rest of your app routes + ]); + + return routes; +} + +function App() { + return ( + + + + + + ); +} +``` +::: + + + +```tsx {3,8,9,10,11,12} +import React from 'react'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; -// highlight-next-line import { WebauthnPreBuiltUI } from 'supertokens-auth-react/recipe/webauthn/prebuiltui'; import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; class App extends React.Component { render() { - // highlight-start if (canHandleRoute([WebauthnPreBuiltUI])) { - // This renders the login UI on the ^{appInfo.websiteBasePath} route + // This renders the login UI on the /auth route return getRoutingComponent([WebauthnPreBuiltUI]) } - // highlight-end return ( {/*Your app*/} @@ -135,17 +152,14 @@ class App extends React.Component { } } ``` - - - - + + + + Add the `WebAuthn` recipe in your `AuthComponent`. - ```tsx title="/app/auth/auth.component.ts" - import {init as supertokensUIInit} from "supertokens-auth-react-script"; - import supertokensUIWebAuthn from "supertokens-auth-react-script/recipe/webauthn"; - import supertokensUISession from "supertokens-auth-react-script/recipe/session"; + ```tsx title="/app/auth/auth.component.ts" {42} import { Component, OnDestroy, AfterViewInit, Renderer2, Inject } from "@angular/core"; import { DOCUMENT } from "@angular/common"; @@ -161,7 +175,7 @@ Add the `WebAuthn` recipe in your `AuthComponent`. ) { } ngAfterViewInit() { - this.loadScript('^{prebuiltUIVersion}'); + this.loadScript('https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js'); } ngOnDestroy() { @@ -180,16 +194,14 @@ Add the `WebAuthn` recipe in your `AuthComponent`. script.onload = () => { supertokensUIInit({ appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", }, recipeList: [ -// highlight-start supertokensUIWebAuthn.init(), -// highlight-end supertokensUISession.init(), ], }); @@ -200,16 +212,13 @@ Add the `WebAuthn` recipe in your `AuthComponent`. ``` - - + + Add the `WebAuthn` recipe in your `AuthView` file. - ```tsx - import {init as supertokensUIInit} from "supertokens-auth-react-script"; - import supertokensUIWebAuthn from "supertokens-auth-react-script/recipe/webauthn"; - import supertokensUISession from "supertokens-auth-react-script/recipe/session"; + ```tsx {20} + ``` You can initialize the SDK. ```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensWebAuthn from 'supertokens-web-js-script/recipe/webauthn' supertokens.init({ appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", appName: "...", }, recipeList: [ @@ -330,36 +334,34 @@ supertokens.init({ }); ``` - - - + - + - + - + - + - + + ```tsx import SuperTokens from 'supertokens-react-native'; SuperTokens.init({ - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", }); ``` - - - + + ```kotlin @@ -370,18 +372,17 @@ class MainApplication: Application() { override fun onCreate() { super.onCreate() - SuperTokens.Builder(this, "^{appInfo.apiDomain}") - .apiBasePath("^{appInfo.apiBasePath}") + SuperTokens.Builder(this, "") + .apiBasePath("/auth") .build() } } ``` - - - + + ```swift @@ -393,8 +394,8 @@ fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { do { try SuperTokens.initialize( - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}" + apiDomain: "", + apiBasePath: "/auth" ) } catch SuperTokensError.initError(let message) { // TODO: Handle initialization error @@ -409,44 +410,44 @@ fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; void main() { SuperTokens.init( - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", ); } ``` - + - + - + - + ### 2. Add the passkeys UI #### 2.1 Add the sign up form - + - + Create a form in which the user can input their email address. When the user submits the form, call the `registerCredentialWithSignUp` method like in the next code snippet. Under the hood, the method communicates with the backend SDK to fetch the registration options. Once the backend responds, it uses the browser's APIs to begin the registration process. -For a more detailed overview of the sign up flow check the [Important Concepts page](/docs/authentication/passkeys/important-concepts#signup). +For a more detailed overview of the sign up flow check the [Important Concepts page](/authentication/passkeys/important-concepts#signup). ```ts import { registerCredentialWithSignUp } from "supertokens-web-js/recipe/webauthn"; @@ -500,9 +501,9 @@ async function signUp(email: string) { } ``` - + - + @@ -515,7 +516,7 @@ async function signUp(email: string) { Save the response to use it in the next step. ```bash - curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/webauthn/register/options' \ + curl --location --request POST '/auth/webauthn/register/options' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "email": "johndoe@gmail.com", @@ -523,8 +524,7 @@ async function signUp(email: string) { }' ``` - :::caution - The returned result matches the format required by the **browser's WebAuthn API**. + :::warning[The returned result matches the format required by the **browser's WebAuthn API**.] You will have to map the properties to the correct format based on the requirements of your platform. ::: @@ -542,7 +542,7 @@ async function signUp(email: string) { Using the newly generate credential, call the sign up API to save the new authentication method. ```bash - curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/webauthn/signup' \ + curl --location --request POST '/auth/webauthn/signup' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "webauthnGeneratedOptionsId": "opt_123...", @@ -561,16 +561,16 @@ async function signUp(email: string) { - + - + #### 2.2 Add the login form - + - + Add a button that can trigger the sign in flow. This is all that you need in terms of UI. @@ -578,7 +578,7 @@ When the user clicks it, call the `authenticateCredentialWithSignIn` method to h The function uses the backend registration options to trigger the challenge signing action through the browser API. Then, it forwards the result to the backend for validation. -For a more detailed overview of the login flow check the [Important Concepts page](/docs/authentication/passkeys/important-concepts#login). +For a more detailed overview of the login flow check the [Important Concepts page](/authentication/passkeys/important-concepts#login). ```ts import { authenticateCredentialWithSignIn } from "supertokens-web-js/recipe/webauthn"; @@ -620,9 +620,9 @@ async function signIn(email: string) { } } ``` - + - + @@ -632,7 +632,7 @@ async function signIn(email: string) { When the user taps the sign in button, call the backend API to fetch the sign in options. ```bash - curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/webauthn/signin/options' \ + curl --location --request POST '/auth/webauthn/signin/options' \ --header 'Content-Type: application/json; charset=utf-8' ``` @@ -646,7 +646,7 @@ async function signIn(email: string) { Send the signed challenge to the backend for validation. ```bash - curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/webauthn/signin' \ + curl --location --request POST '/auth/webauthn/signin' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "webauthnGeneratedOptionsId": "opt_123...", @@ -665,35 +665,35 @@ async function signIn(email: string) { - + - + - + - + ### 2. Initialize the backend SDK - + - + ### 3. Initialize the backend SDK - + Initialize the backend SDK and include the **WebAuthn** `recipe`. -The init call includes [configuration details](/docs/references/backend-sdks/reference#sdk-configuration) for your app. +The init call includes [configuration details](/references/backend-sdks/reference#sdk-configuration) for your app. It specifies how the backend connects to the **SuperTokens Core**, as well as the **Recipes** used in your setup. The recipe exposes the required endpoints that get accessed by the frontend code, and communicates with the **SuperTokens Core** to complete the authentication flow. -You can [configure different aspects](/docs/authentication/passkeys/customization) of the recipe's behavior but, for the completion of this guide, use the default values. +You can [configure different aspects](/authentication/passkeys/customization) of the recipe's behavior but, for the completion of this guide, use the default values. After you confirm that the flow works as expected you can explore more advanced customisations options. - + - + ```ts @@ -724,20 +724,18 @@ supertokens.init({ ] }); ``` - - + - -:::caution + -At the moment there is no support for using passkeys authentication in the Go SDK. +:::warning[At the moment there is no support for using passkeys authentication in the Go SDK.] ::: - + - + ```python from supertokens_python import InputAppInfo, SupertokensConfig, init @@ -766,50 +764,30 @@ init( ) ``` - + - + - + ## Next steps Having completed the main setup, you can explore more advanced topics related to the **WebAuthn** recipe. - - - - Backend Recipe Configuration - - - Read through the configuration options for the backend recipe. - - - - - Customize Credentials Generation - - - See how you can adjust the process that generates credentials. - - - - - Customize Credentials Validation - - - Discover how to customize the validation process. - - - - - Email Delivery - - - Customize the email sending process. - - - - - - + + +Read through the configuration options for the backend recipe. + + +See how you can adjust the process that generates credentials. + + +Discover how to customize the validation process. + + +Customize the email sending process. + + + + + diff --git a/docs/authentication/passkeys/introduction.mdx b/docs/authentication/passkeys/introduction.mdx index 14fd03d3b6..cb38bed877 100644 --- a/docs/authentication/passkeys/introduction.mdx +++ b/docs/authentication/passkeys/introduction.mdx @@ -1,21 +1,15 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -skip_llms_txt: true -page_type: overview -recipe: webauthn -category: passkeys +sidebar: + order: 1 --- -# Passkeys authentication - ## Overview **Passkeys** is a passwordless authentication method that follows the **WebAuthn**, Web Authentication, specification. The standard allows users to log in using biometric authentication, security keys, or device-based credentials, replacing traditional username and password combinations. -Sign in form UI for passkeys login +Sign in form UI for passkeys login ## Prerequisites @@ -23,56 +17,30 @@ To implement the feature you need to make sure that your users have compatible d ## Getting started -Before going into the actual quickstart guide, read through the [**Important Concepts** page](/docs/authentication/passkeys/important-concepts). +Before going into the actual quickstart guide, read through the [**Important Concepts** page](/authentication/passkeys/important-concepts). It provides a high-level overview of the terms and concepts used in the passkeys authentication flow. - - - - Important Concepts - - - Go through a quick summary of the WebAuthn specifications to get accustomed with the language used in the guides. - - - - - Initial Setup - - - Implement an authentication flow that uses passkeys to login users. - - - + + +Go through a quick summary of the WebAuthn specifications to get accustomed with the language used in the guides. + + +Implement an authentication flow that uses passkeys to login users. + + ## Customization To adjust the functionality to fit your use case you can explore different sections from the documentation. - - - - Backend Recipe Configuration - - - Read through all the options that you can set during the initialization step. - - - - - Credential Generation - - - See how you can adjust the process that generates credentials. - - - - - Credential Validation - - - Discover how to customize the validation process. - - - - + + +Read through all the options that you can set during the initialization step. + + +See how you can adjust the process that generates credentials. + + +Discover how to customize the validation process. + + diff --git a/docs/authentication/passkeys/meta.ts b/docs/authentication/passkeys/meta.ts new file mode 100644 index 0000000000..d887125591 --- /dev/null +++ b/docs/authentication/passkeys/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Passkeys", + "icon": "fingerprint", + "order": 7 +}); diff --git a/docs/authentication/passwordless/_blocks/backend-sdk-init.mdx b/docs/authentication/passwordless/_blocks/backend-sdk-init.mdx deleted file mode 100644 index b18eb32ef7..0000000000 --- a/docs/authentication/passwordless/_blocks/backend-sdk-init.mdx +++ /dev/null @@ -1,146 +0,0 @@ - -You need to initialize the **Backend SDK** alongside the code that starts your server. -The init call includes [configuration details](/docs/references/backend-sdks/reference#sdk-configuration) for your app. It specifies how the backend connects to the **SuperTokens Core**, as well as the **Recipes** used in your setup. - -For the **Passwordless** recipe, you also need to specify the `flowType` and `contactMethod`. -Click one of the options from the next form and the code snippet updates. - - - - - - - -```tsx title="Backend SDK Init" showAppTypeSelect -import supertokens from "supertokens-node"; -import Session from "supertokens-node/recipe/session"; -// highlight-next-line -import Passwordless from "supertokens-node/recipe/passwordless"; - -supertokens.init({ - // Replace this with the framework you are using - framework: "express", - supertokens: { - // We use try.supertokens for demo purposes. - // At the end of the tutorial we will show you how to create - // your own SuperTokens core instance and then update your config. - connectionURI: "https://try.supertokens.io^{derived.appIdPathname}", - // apiKey: - }, - appInfo: { - // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", - }, - recipeList: [ - // highlight-start - Passwordless.init({ - flowType: "^{recipes.passwordless.flowType}", - contactMethod: "^{recipes.passwordless.contactMethod}" - }), - // highlight-end - Session.init() - ] -}); -``` - - - - - - - - - - - -```python title="Backend SDK Init" showAppTypeSelect -from supertokens_python import init, InputAppInfo, SupertokensConfig -from supertokens_python.recipe import passwordless, session -# highlight-next-line -^{derived.pythonContactMethodImport} - -init( - app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" - ), - supertokens_config=SupertokensConfig( - # We use try.supertokens for demo purposes. - # At the end of the tutorial we will show you how to create - # your own SuperTokens core instance and then update your config. - connection_uri="https://try.supertokens.io^{derived.appIdPathname}", - # api_key: - ), - framework='fastapi', - recipe_list=[ - session.init(), # initializes session features - passwordless.init( - flow_type="^{recipes.passwordless.flowType}", - contact_config=^{derived.pythonContactMethodMethod}() - ) - ], - mode='asgi' # use wsgi if you are running using gunicorn -) -``` - - - - - - - - - -```go title="Backend SDK Init" showAppTypeSelect -import ( - "github.com/supertokens/supertokens-golang/recipe/session" - "github.com/supertokens/supertokens-golang/recipe/passwordless" - "github.com/supertokens/supertokens-golang/recipe/passwordless/plessmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - apiBasePath := "^{appInfo.apiBasePath}" - websiteBasePath := "^{appInfo.websiteBasePath}" - err := supertokens.Init(supertokens.TypeInput{ - Supertokens: &supertokens.ConnectionInfo{ - // We use try.supertokens for demo purposes. - // At the end of the tutorial we will show you how to create - // your own SuperTokens core instance and then update your config. - ConnectionURI: "https://try.supertokens.io^{derived.appIdPathname}", - // APIKey: - }, - AppInfo: supertokens.AppInfo{ - AppName: "^{appInfo.appName}", - APIDomain: "^{appInfo.apiDomain}", - WebsiteDomain: "^{appInfo.websiteDomain}", - APIBasePath: &apiBasePath, - WebsiteBasePath: &websiteBasePath, - }, - RecipeList: []supertokens.Recipe{ - passwordless.Init(plessmodels.TypeInput{ - FlowType: "^{recipes.passwordless.flowType}", - ^{derived.goPasswordlessContactMethodMethod} - }), - session.Init(nil), // initializes session features - }, - }) - - if err != nil { - panic(err.Error()) - } -} -``` - - - - - - diff --git a/docs/authentication/passwordless/_blocks/frontend-custom-ui-magic-link-ui.mdx b/docs/authentication/passwordless/_blocks/frontend-custom-ui-magic-link-ui.mdx deleted file mode 100644 index 47bbdbc1d2..0000000000 --- a/docs/authentication/passwordless/_blocks/frontend-custom-ui-magic-link-ui.mdx +++ /dev/null @@ -1,493 +0,0 @@ - -The following section shows you what aspects you need to cover to implement the UI for a `Magic Link` flow. -The same flow applies during either sign up or sign in. -This guide shows you how to determine if the system creates a new user in the next steps. - -#### 2.1 Sending the Magic link - -You need to add a form that asks the user for their email address or phone number. -When the user submits the form, you need to call the following API to create and send them a **Magic Link**. - -:::info - -You configure the contact method on the next page, where you discuss the process of adding the `SDK` to your backend app. - -::: - - - - - - - - - -```tsx -import { createCode } from "supertokens-web-js/recipe/passwordless"; - -async function sendMagicLink(email: string) { - try { - let response = await createCode({ - email - }); - /** - * For phone number, use this: - - let response = await createCode({ - phoneNumber: "+1234567890" - }); - - */ - - if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { - // the reason string is a user friendly message - // about what went wrong. It can also contain a support code which users - // can tell you so you know why their sign in / up was not allowed. - window.alert(response.reason) - } else { - // Magic link sent successfully. - window.alert("Please check your email for the magic link"); - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you, - // or if the input email / phone number is not valid. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - -```tsx -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; -async function sendMagicLink(email: string) { - try { - let response = await supertokensPasswordless.createCode({ - email - }); - /** - * For phone number, use this: - - let response = await supertokens^{recipeNameCapitalLetters}.createCode({ - phoneNumber: "+1234567890" - }); - - */ - - if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { - // the reason string is a user friendly message - // about what went wrong. It can also contain a support code which users - // can tell you so you know why their sign in / up was not allowed. - window.alert(response.reason) - } else { - // Magic link sent successfully. - window.alert("Please check your email for the magic link"); - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you, - // or if the input email / phone number is not valid. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - - - - - - -For email based login - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup/code' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "email": "johndoe@gmail.com" -}' -``` - -For phone number based login -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup/code' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "phoneNumber": "+1234567890" -}' -``` - - -The response body from the API call has a `status` property in it: -- `status: "OK"`: This means that the magic link was successfully sent. -- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend, or if the input email or password failed the backend validation logic. -- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during multi-factor authentication (MFA). The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. - -The response from the API call is the following object (in case of `status: "OK"`): -```json -{ - status: "OK"; - deviceId: string; - preAuthSessionId: string; - flowType: "USER_INPUT_CODE" | "MAGIC_LINK" | "USER_INPUT_CODE_AND_MAGIC_LINK"; - fetchResponse: Response; // raw fetch response from the API call -} -``` - -You want to save the `deviceId` and `preAuthSessionId` on the frontend storage. These are useful to: -- Resend a new magic link. -- Detect if the user has already sent a magic link before or if this is an entirely new login attempt. This distinction can be important if you have different UI for these two states. For example, if this info already exists, you do not want to show the user an input box to enter their email / phone, and instead want to show them the resend link button. - - - - - -#### 2.2 Resending a magic link - -After sending the initial magic link to the user, you may want to display a resend button to them. -When the user clicks on this button, you should call the following API - - - - - - - -```tsx -import { resendCode, clearLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; - -async function resendMagicLink() { - try { - let response = await resendCode(); - - if (response.status === "RESTART_FLOW_ERROR") { - // this can happen if the user has already successfully logged in into - // another device whilst also trying to login to this one. - - // we clear the login attempt info that was added when the createCode function - // was called - so that if the user does a page reload, they will now see the - // enter email / phone UI again. - await clearLoginAttemptInfo(); - window.alert("Login failed. Please try again"); - window.location.assign("/auth") - } else { - // Magic link resent successfully. - window.alert("Please check your email for the magic link"); - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - -```tsx -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; -async function resendMagicLink() { - try { - let response = await supertokensPasswordless.resendCode(); - - if (response.status === "RESTART_FLOW_ERROR") { - // this can happen if the user has already successfully logged in into - // another device whilst also trying to login to this one. - - // we clear the login attempt info that was added when the createCode function - // was called - so that if the user does a page reload, they will now see the - // enter email / phone UI again. - await supertokensPasswordless.clearLoginAttemptInfo(); - window.alert("Login failed. Please try again"); - window.location.assign("/auth") - } else { - // Magic link resent successfully. - window.alert("Please check your email for the magic link"); - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - - - - - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup/code/resend' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "deviceId": "...", - "preAuthSessionId": "...." -}' -``` - - -The response body from the API call has a `status` property in it: -- `status: "OK"`: This means that the magic link was successfully sent. -- `status: "RESTART_FLOW_ERROR"`: This can happen if the user has already successfully logged in into another device whilst also trying to login to this one. You want to take the user back to the login screen where they can enter their email / phone number again. Be sure to remove the stored `deviceId` and `preAuthSessionId` from the frontend storage. -- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend. - - - - - -#### How to detect if the user is on step 2.1 or step 2.2? - -If you are building the UI for both of the previous steps on the same page you might run into an issue when the user refreshes the page. -To prevent this you need a way to know which UI to show. - - - - - - - -```tsx -import { getLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; - -async function hasInitialMagicLinkBeenSent() { - return await getLoginAttemptInfo() !== undefined; -} -``` - - - - -```tsx -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; -async function hasInitialMagicLinkBeenSent() { - return await supertokensPasswordless.getLoginAttemptInfo() !== undefined; -} -``` - - - - -If `hasInitialMagicLinkBeenSent` returns `true`, it means that the user has already sent the initial magic link to themselves, and you can show the resend link UI. Else show a form asking them to enter their email / phone number. - - - - - -Since you save the `preAuthSessionId` and `deviceId` after sending the initial magic link, you can know if the user is on either **step 3.1** or **step 3.2**. Check if these tokens are on the device. - -If they aren't, you should follow **step 3.1**, else follow **step 3.2**. - -:::important -You need to clear these tokens if: -- the user navigates away from the **step 3.2** page -- you get a `RESTART_FLOW_ERROR` at any point in time from an API call -- the user has successfully logged in. -::: - - - - - -#### 2.3 Consuming the magic link - -When a user clicks on a magic link, you first need to know if the action came from the same browser/device as the one that started the flow. -To do this you ca use this code sample. - - - - - - - -```tsx -import { getLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; - -async function isThisSameBrowserAndDevice() { - return await getLoginAttemptInfo() !== undefined; -} -``` - - - - -```tsx -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; -async function isThisSameBrowserAndDevice() { - return await supertokensPasswordless.getLoginAttemptInfo() !== undefined; -} -``` - - - - - - - - -Since you save the `preAuthSessionId` and `deviceId`, you can check if they exist on the app. If they do, then it's the same device that the user has opened the link on, else it's a different device. - - - - - -:::important - -Add a intermediate step if the user came from a different device. - -::: - -If the user clicked on a link from a different device, you need to show some kind of an intermediate UI. -This is to protect against email clients opening the magic link on their servers and consuming the link. - -The page should require additional user interaction before consuming the magic link. -For example, you could show a button with the following text: `Click here to login into this device`. -On click, you can consume the magic link to log the user into that device. - -With this understanding of how to avoid potential errors, proceed with the actual instructions on how to authenticate with the magic link. - - - - - - - -```tsx -import { consumeCode, clearLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; - -async function handleMagicLinkClicked() { - try { - let response = await consumeCode(); - - if (response.status === "OK") { - // we clear the login attempt info that was added when the createCode function - // was called since the login was successful. - await clearLoginAttemptInfo(); - if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { - // user sign up success - } else { - // user sign in success - } - window.location.assign("/home") - } else { - // this can happen if the magic link has expired or is invalid - // or if it was denied due to security reasons in case of automatic account linking - - // we clear the login attempt info that was added when the createCode function - // was called - so that if the user does a page reload, they will now see the - // enter email / phone UI again. - await clearLoginAttemptInfo(); - window.alert("Login failed. Please try again"); - window.location.assign("/auth") - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - -```tsx -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; -async function handleMagicLinkClicked() { - try { - let response = await supertokensPasswordless.consumeCode(); - - if (response.status === "OK") { - // we clear the login attempt info that was added when the createCode function - // was called since the login was successful. - await supertokensPasswordless.clearLoginAttemptInfo(); - if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { - // user sign up success - } else { - // user sign in success - } - window.location.assign("/home") - } else { - // this can happen if the magic link has expired or is invalid - // or if it was denied due to security reasons in case of automatic account linking - - // we clear the login attempt info that was added when the createCode function - // was called - so that if the user does a page reload, they will now see the - // enter email / phone UI again. - await supertokensPasswordless.clearLoginAttemptInfo(); - window.alert("Login failed. Please try again"); - window.location.assign("/auth") - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - - - - - -You need to remove the `linkCode` and `preAuthSessionId` from the Magic link. For example, if the Magic link is - -```text -https://example.com/auth/verify?preAuthSessionId=PyIwyA6VjdjNF5ggMV960rs3QXupRP2PEg2KcN5oi8s=#s4hxpBPnRC3xwBsCkFU228lh_CWe5HUBMRPowajsrgs= -``` - -Then the `preAuthSessionId` is the value of the query parameter `preAuthSessionId` (`PyIwyA6VjdjNF5ggMV960rs3QXupRP2PEg2KcN5oi8s=` in the example), and the `linkCode` is the part after the `#` (`s4hxpBPnRC3xwBsCkFU228lh_CWe5HUBMRPowajsrgs=` in the example). - -We can then use these to call the consume API - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup/code/consume' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "linkCode": "s4hxpBPnRC3xwBsCkFU228lh_CWe5HUBMRPowajsrgs=", - "preAuthSessionId": "PyIwyA6VjdjNF5ggMV960rs3QXupRP2PEg2KcN5oi8s=" -}' -``` - - -:::info Multi Tenancy -For a multi-tenancy setup, the `` value can fetch from the `tenantId` query parameter from the magic link. If it's not there in the link, you can use the value `"public"` (which is the default tenant). -::: - -The response body from the API call has a `status` property in it: -- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. -- `status: "INCORRECT_USER_INPUT_CODE_ERROR" | "EXPIRED_USER_INPUT_CODE_ERROR" | "RESTART_FLOW_ERROR"`: These responses indicate that the Magic link was invalid or expired. -- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend. -- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during multi-factor authentication (MFA). The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. - - - - diff --git a/docs/authentication/passwordless/_blocks/frontend-custom-ui-otp-ui.mdx b/docs/authentication/passwordless/_blocks/frontend-custom-ui-otp-ui.mdx deleted file mode 100644 index 3487b9ad64..0000000000 --- a/docs/authentication/passwordless/_blocks/frontend-custom-ui-otp-ui.mdx +++ /dev/null @@ -1,444 +0,0 @@ - -The following section shows you what aspects you need to cover to implement the UI for a `OTP`, One-Time Password, flow. -The same flow applies during either sign up or sign in. -This guide shows you how to determine if you create a new user in the next steps. - -#### 2.1 Creating and sending the OTP - -You have to add a form that asks the user for their email address or phone number. -When the users submit the form you have to call the following API to create and send them an OTP. - - - - - - - -```tsx -import { createCode } from "supertokens-web-js/recipe/passwordless"; - -async function sendOTP(email: string) { - try { - let response = await createCode({ - email - }); - /** - * For phone number, use this: - - let response = await createPasswordlessCode({ - phoneNumber: "+1234567890" - }); - - */ - - if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { - // the reason string is a user friendly message - // about what went wrong. It can also contain a support code which users - // can tell you so you know why their sign in / up was not allowed. - window.alert(response.reason) - } else { - // OTP sent successfully. - window.alert("Please check your email for an OTP"); - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you, - // or if the input email / phone number is not valid. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - -```tsx -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; -async function sendOTP(email: string) { - try { - let response = await supertokensPasswordless.createCode({ - email - }); - /** - * For phone number, use this: - - let response = await supertokens^{recipeNameCapitalLetters}.createCode({ - phoneNumber: "+1234567890" - }); - - */ - - if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { - // the reason string is a user friendly message - // about what went wrong. It can also contain a support code which users - // can tell you so you know why their sign in / up was not allowed. - window.alert(response.reason) - } else { - // OTP sent successfully. - window.alert("Please check your email for an OTP"); - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you, - // or if the input email / phone number is not valid. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - - - - - - -For email based login - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup/code' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "email": "johndoe@gmail.com" -}' -``` - -For phone number based login -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup/code' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "phoneNumber": "+1234567890" -}' -``` - - -The response body from the API call has a `status` property in it: -- `status: "OK"`: This means that the OTP was successfully sent. -- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend, or if the input email or password failed the backend validation logic. -- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. - -The response from the API call is the following object (in case of `status: "OK"`): -```json -{ - status: "OK"; - deviceId: string; - preAuthSessionId: string; - flowType: "USER_INPUT_CODE" | "MAGIC_LINK" | "USER_INPUT_CODE_AND_MAGIC_LINK"; - fetchResponse: Response; // raw fetch response from the API call -} -``` - -You want to save the `deviceId` and `preAuthSessionId` on the frontend storage. These are useful to: -- Resend a new OTP. -- Detect if the user has already sent an OTP before or if this is an entirely new login attempt. This distinction can be important if you have different UI for these two states. For example, if this info already exists, you do not want to show the user an input box to enter their email / phone, and instead want to show them the enter OTP form with a resend button. -- Verify the user's input OTP. - - - - - -#### 2.2 Resending a OTP - -After you send the OTP to the user, you may want to display a resend button to them. -When the user clicks on this button, you should call the following API - - - - - - - -```tsx -import { resendCode, clearLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; - -async function resendOTP() { - try { - let response = await resendCode(); - - if (response.status === "RESTART_FLOW_ERROR") { - // this can happen if the user has already successfully logged in into - // another device whilst also trying to login to this one. - - // we clear the login attempt info that was added when the createCode function - // was called - so that if the user does a page reload, they will now see the - // enter email / phone UI again. - await clearLoginAttemptInfo(); - window.alert("Login failed. Please try again"); - window.location.assign("/auth") - } else { - // OTP resent successfully. - window.alert("Please check your email for the OTP"); - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - -```tsx -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; -async function resendOTP() { - try { - let response = await supertokensPasswordless.resendCode(); - - if (response.status === "RESTART_FLOW_ERROR") { - // this can happen if the user has already successfully logged in into - // another device whilst also trying to login to this one. - - // we clear the login attempt info that was added when the createCode function - // was called - so that if the user does a page reload, they will now see the - // enter email / phone UI again. - await supertokensPasswordless.clearLoginAttemptInfo(); - window.alert("Login failed. Please try again"); - window.location.assign("/auth") - } else { - // OTP resent successfully. - window.alert("Please check your email for the OTP"); - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - - - - - - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup/code/resend' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "deviceId": "...", - "preAuthSessionId": "...." -}' -``` - - -The response body from the API call has a `status` property in it: -- `status: "OK"`: This means that the OTP was successfully sent. -- `status: "RESTART_FLOW_ERROR"`: This can happen if the user has already successfully logged in into another device whilst also trying to login to this one. You want to take the user back to the login screen where they can enter their email / phone number again. Be sure to remove the stored `deviceId` and `preAuthSessionId` from the frontend storage. -- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend. - - - - - -#### How to detect if the user is on step 3.1 or step 3.2? - -If you are building the UI for both of the previous steps on the same page you might run into an issue when the user refreshes the page. -To prevent this you need a way to know which UI to show. - - - - - - - -```tsx -import { getLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; - -async function hasInitialOTPBeenSent() { - return await getLoginAttemptInfo() !== undefined; -} -``` - - - - -```tsx -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; -async function hasInitialOTPBeenSent() { - return await supertokensPasswordless.getLoginAttemptInfo() !== undefined; -} -``` - - - - -If `hasInitialOTPBeenSent` returns `true`, it means that the user has already sent the initial OTP to themselves, and you can show the enter OTP form + resend OTP button 3.2. Else show a form asking them to enter their email / phone number 3.1. - - - - - -Since you save the `preAuthSessionId` and `deviceId` after you send the initial OTP, you can determine if the user is in step 3.1 or 3.2. -Check if you stored these tokens on the device. - -If they aren't, you should follow 3.1, else follow 3.2. - -:::important -You need to clear these tokens if: -- the user navigates away from the 3.2 page -- you get a `RESTART_FLOW_ERROR` at any point in time from an API call -- the user has successfully logged in. -::: - - - - - -#### 2.3 Verifying the OTP - -When the user enters an OTP you have to call the following API to verify it - - - - - - - -```tsx -import { consumeCode, clearLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; - -async function handleOTPInput(otp: string) { - try { - let response = await consumeCode({ - userInputCode: otp - }); - - if (response.status === "OK") { - // we clear the login attempt info that was added when the createCode function - // was called since the login was successful. - await clearLoginAttemptInfo(); - if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { - // user sign up success - } else { - // user sign in success - } - window.location.assign("/home") - } else if (response.status === "INCORRECT_USER_INPUT_CODE_ERROR") { - // the user entered an invalid OTP - window.alert("Wrong OTP! Please try again. Number of attempts left: " + (response.maximumCodeInputAttempts - response.failedCodeInputAttemptCount)); - } else if (response.status === "EXPIRED_USER_INPUT_CODE_ERROR") { - // it can come here if the entered OTP was correct, but has expired because - // it was generated too long ago. - window.alert("Old OTP entered. Please regenerate a new one and try again"); - } else { - // this can happen if the user tried an incorrect OTP too many times. - // or if it was denied due to security reasons in case of automatic account linking - - // we clear the login attempt info that was added when the createCode function - // was called - so that if the user does a page reload, they will now see the - // enter email / phone UI again. - await clearLoginAttemptInfo(); - window.alert("Login failed. Please try again"); - window.location.assign("/auth") - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - -```tsx -import supertokensPasswordless from "supertokens-web-js-script/recipe/passwordless"; -async function handleOTPInput(otp: string) { - try { - let response = await supertokensPasswordless.consumeCode({ - userInputCode: otp - }); - - if (response.status === "OK") { - // we clear the login attempt info that was added when the createCode function - // was called since the login was successful. - await supertokensPasswordless.clearLoginAttemptInfo(); - if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { - // user sign up success - } else { - // user sign in success - } - window.location.assign("/home") - } else if (response.status === "INCORRECT_USER_INPUT_CODE_ERROR") { - // the user entered an invalid OTP - window.alert("Wrong OTP! Please try again. Number of attempts left: " + (response.maximumCodeInputAttempts - response.failedCodeInputAttemptCount)); - } else if (response.status === "EXPIRED_USER_INPUT_CODE_ERROR") { - // it can come here if the entered OTP was correct, but has expired because - // it was generated too long ago. - window.alert("Old OTP entered. Please regenerate a new one and try again"); - } else { - // this can happen if the user tried an incorrect OTP too many times. - // or if it was denied due to security reasons in case of automatic account linking - - // we clear the login attempt info that was added when the createCode function - // was called - so that if the user does a page reload, they will now see the - // enter email / phone UI again. - await supertokensPasswordless.clearLoginAttemptInfo(); - window.alert("Login failed. Please try again"); - window.location.assign("/auth") - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - - - - - - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup/code/consume' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "deviceId": "...", - "preAuthSessionId": "...", - "userInputCode": "" -}' -``` - - -The response body from the API call has a `status` property in it: -- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. -- `status: "INCORRECT_USER_INPUT_CODE_ERROR"`: The entered OTP is invalid. The response contains information about the maximum number of retries and the number of failed attempts. -- `status: "EXPIRED_USER_INPUT_CODE_ERROR"`: The entered OTP is too old. You should ask the user to resend a new OTP and try again. -- `status: "RESTART_FLOW_ERROR"`: These responses that the user tried invalid OTPs too many times. -- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend. -- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. - - - - - diff --git a/docs/authentication/passwordless/_category_.json b/docs/authentication/passwordless/_category_.json deleted file mode 100644 index 5fa7d0559c..0000000000 --- a/docs/authentication/passwordless/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Passwordless", - "position": 2 -} diff --git a/docs/authentication/passwordless/allow-list-flow.mdx b/docs/authentication/passwordless/allow-list-flow.mdx index 18692342b7..2f8a50bacb 100644 --- a/docs/authentication/passwordless/allow-list-flow.mdx +++ b/docs/authentication/passwordless/allow-list-flow.mdx @@ -1,18 +1,10 @@ --- title: Implement allow list based sign up -hide_title: true -description: >- - Discover how to implement an allow list based sign up flow with the - passwordless recipe. -sidebar_position: 11 -page_type: guide -recipe: passwordless -category: passwordless +description: Discover how to implement an allow list based sign up flow with the passwordless recipe. +sidebar: + order: 11 --- - -# Passwordless login via allow list - ## Overview In this flow, you create a list of emails or phone numbers that are allowed to sign up. @@ -21,12 +13,12 @@ Based on that users can go through the passwordless flow. ## Before you start This guide assumes that you already have a working application integrated with **SuperTokens**. -If you have not, please check the [Quickstart Guide](/docs/quickstart/introduction). +If you have not, please check the [Quickstart Guide](/quickstart/introduction). ### Prerequisites This guide uses the `UserMetadata` recipe to store the allow list. -You need to [enable it](/docs/post-authentication/user-management/user-metadata) in the SDK initialization step. +You need to [enable it](/post-authentication/user-management/user-metadata) in the SDK initialization step. ## Steps @@ -39,8 +31,8 @@ This may seem like a strange use case of the user metadata recipe provided, but The following code samples show you how to save the allow list in the user metadata. - - + + ```tsx import UserMetadata from "supertokens-node/recipe/usermetadata" @@ -76,8 +68,8 @@ async function isPhoneNumberAllowed(phoneNumber: string) { } ``` - - + + ```go import "github.com/supertokens/supertokens-golang/recipe/usermetadata" @@ -153,8 +145,8 @@ func isPhoneNumberAllowed(phoneNumber string) (bool, error) { } ``` - - + + ```python from typing import List @@ -192,12 +184,11 @@ async def is_phone_number_allowed(phone_number: str): return phone_number in allow_list ``` - - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] For a multi tenant setup, you can even store an allow list per tenant. This would allow you to limit sign ups for different emails / phone numbers for different tenants. If you are doing this, then you would also need to pass in the tenantID to the functions above, which you can obtain from the input to the `API overrides` shown below. ::: @@ -209,17 +200,14 @@ Update the backend SDK API function to only allow sign up requests from users th To do this you need to use the check functions from the previous code snippet. - - + + ```tsx import Passwordless from "supertokens-node/recipe/passwordless"; import supertokens from "supertokens-node"; -declare let isEmailAllowed: (email: string) => Promise // typecheck-only, removed from output -declare let isPhoneNumberAllowed: (email: string) => Promise // typecheck-only, removed from output Passwordless.init({ - contactMethod: "EMAIL", flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // typecheck-only, removed from output override: { apis: (originalImplementation) => { return { @@ -262,8 +250,8 @@ Passwordless.init({ }) ``` - - + + ```go import ( @@ -339,8 +327,8 @@ func main() { } ``` - - + + ```python from typing import Any, Dict, Optional, Union @@ -443,10 +431,10 @@ def override_passwordless_apis(original_implementation: APIInterface): init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ passwordless.init( - contact_config="", # type: ignore # typecheck-only, removed from output + contact_config="", # typecheck-only, removed from output flow_type="USER_INPUT_CODE", override=passwordless.InputOverrideConfig( apis=override_passwordless_apis, @@ -456,18 +444,18 @@ init( ) ``` - - + + --- ## See also - - - - - - - + + + + + + + diff --git a/docs/authentication/passwordless/configure-email-and-sms-behavior.mdx b/docs/authentication/passwordless/configure-email-and-sms-behavior.mdx index 0a6ea9d899..17f3f9161d 100644 --- a/docs/authentication/passwordless/configure-email-and-sms-behavior.mdx +++ b/docs/authentication/passwordless/configure-email-and-sms-behavior.mdx @@ -1,35 +1,25 @@ --- title: Configure email and SMS behavior -hide_title: true -sidebar_position: 7 description: Customize how the email and SMS are sent in your frontend application. -page_type: guide -recipe: passwordless -category: passwordless +sidebar: + order: 7 --- - -# Configure email and SMS behavior - - - - ## Changing email / SMS resend time interval -:::caution no-title +:::warning These instructions are only applicable if you are using the pre-built UI. ::: - You can set `resendEmailOrSMSGapInSeconds` to establish a minimum delay before the frontend allows the user to click the "Resend" button. -This limit is only enforced on the client-side. For API rate-limiting please check out the [deployment section](/docs/deployment/rate-limits). +This limit is only enforced on the client-side. For API rate-limiting please check out the [deployment section](/deployment/rate-limits). - - + + -```tsx +```tsx {14,15,16,17} import SuperTokens from "supertokens-auth-react"; import Passwordless from "supertokens-auth-react/recipe/passwordless"; import Session from "supertokens-auth-react/recipe/session"; @@ -43,27 +33,22 @@ SuperTokens.init({ recipeList: [ Passwordless.init({ contactMethod: "EMAIL_OR_PHONE", // This example will work with any contactMethod. - // highlight-start signInUpFeature: { // The default value is 15 seconds resendEmailOrSMSGapInSeconds: 60, } - // highlight-end }), Session.init({ /* ... */ }) ] }); ``` - + - + -```tsx +```tsx {12,13,14,15} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -74,28 +59,26 @@ supertokensUIInit({ recipeList: [ supertokensUIPasswordless.init({ contactMethod: "EMAIL_OR_PHONE", // This example will work with any contactMethod. - // highlight-start signInUpFeature: { // The default value is 15 seconds resendEmailOrSMSGapInSeconds: 60, } - // highlight-end }), supertokensUISession.init({ /* ... */ }) ] }); ``` - + - + --- ## Setting default country for phone inputs -:::caution no-title +:::warning These instructions are only applicable if you are using the pre-built UI. ::: @@ -117,10 +100,10 @@ By default, there is no default country selected. This means that users have to If you would like to set a default country (for all users), then you should use the `defaultCountry` configuration: - - + + -```tsx +```tsx {14,15,16,17,18,19} import SuperTokens from "supertokens-auth-react"; import Passwordless from "supertokens-auth-react/recipe/passwordless"; import Session from "supertokens-auth-react/recipe/session"; @@ -134,29 +117,24 @@ SuperTokens.init({ recipeList: [ Passwordless.init({ contactMethod: "PHONE", - // highlight-start signInUpFeature: { /* * Must be a two-letter ISO country code (e.g.: "US") */ defaultCountry: "HU", } - // highlight-end }), Session.init({ /* ... */ }) ] }); ``` - + - + -```tsx +```tsx {12,13,14,15,16,17} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -167,22 +145,20 @@ supertokensUIInit({ recipeList: [ supertokensUIPasswordless.init({ contactMethod: "PHONE", - // highlight-start signInUpFeature: { /* * Must be a two-letter ISO country code (e.g.: "US") */ defaultCountry: "HU", } - // highlight-end }), supertokensUISession.init({ /* ... */ }) ] }); ``` - - + + - + + -```tsx +```tsx {14,15,16,17,18,19} import SuperTokens from "supertokens-auth-react"; import Passwordless from "supertokens-auth-react/recipe/passwordless"; import Session from "supertokens-auth-react/recipe/session"; @@ -210,29 +186,24 @@ SuperTokens.init({ recipeList: [ Passwordless.init({ contactMethod: "EMAIL_OR_PHONE", - // highlight-start signInUpFeature: { /* * Must be a two-letter ISO country code (e.g.: "US") */ defaultCountry: "HU", } - // highlight-end }), Session.init({ /* ... */ }) ] }); ``` - + - + -```tsx +```tsx {12,13,14,15,16,17} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -243,22 +214,20 @@ supertokensUIInit({ recipeList: [ supertokensUIPasswordless.init({ contactMethod: "EMAIL_OR_PHONE", - // highlight-start signInUpFeature: { /* * Must be a two-letter ISO country code (e.g.: "US") */ defaultCountry: "HU", } - // highlight-end }), supertokensUISession.init({ /* ... */ }) ] }); ``` - - + + @@ -268,13 +237,11 @@ supertokensUIInit({ ## See also - - - - - - - - - - + + + + + + + + diff --git a/docs/authentication/passwordless/customize-the-magic-link.mdx b/docs/authentication/passwordless/customize-the-magic-link.mdx index ab75b47f7f..710810c818 100644 --- a/docs/authentication/passwordless/customize-the-magic-link.mdx +++ b/docs/authentication/passwordless/customize-the-magic-link.mdx @@ -1,25 +1,20 @@ --- title: Customize the Magic Link -hide_title: true -sidebar_position: 3 description: See how to change the magic link or how to generate it manually -page_type: guide -recipe: passwordless -category: passwordless +sidebar: + order: 3 --- -# Customize the magic link - ## Change the magic link URL ### Override the email delivery backend function You can change the URL of Magic Links by providing overriding the email delivery configuration on the backend. - - + + -```tsx +```tsx {17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33} import SuperTokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; import Session from "supertokens-node/recipe/session"; @@ -36,9 +31,7 @@ SuperTokens.init({ // This example works with the "USER_INPUT_CODE_AND_MAGIC_LINK" and "MAGIC_LINK" flows. flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", - // highlight-start emailDelivery: { - // highlight-start override: (originalImplementation) => { return { ...originalImplementation, @@ -46,7 +39,7 @@ SuperTokens.init({ return originalImplementation.sendEmail({ ...input, urlWithLinkCode: input.urlWithLinkCode?.replace( - // This is: `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/verify` + // This is: `/auth/verify` "http://localhost:3000/auth/verify", "http://your.domain.com/your/path" ) @@ -55,16 +48,15 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init({ /* ... */ }) ] }); ``` - - + + -```go +```go {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29} import ( "strings" @@ -79,11 +71,10 @@ func main() { RecipeList: []supertokens.Recipe{ passwordless.Init(plessmodels.TypeInput{ EmailDelivery: &emaildelivery.TypeInput{ - // highlight-start Override: func(originalImplementation emaildelivery.EmailDeliveryInterface) emaildelivery.EmailDeliveryInterface { ogSendEmail := *originalImplementation.SendEmail (*originalImplementation.SendEmail) = func(input emaildelivery.EmailType, userContext supertokens.UserContext) error { - // By default: `^{appInfo.websiteDomain}/^{appInfo.websiteBasePath}/verify` + // By default: `//auth/verify` newUrl := strings.Replace( *input.PasswordlessLogin.UrlWithLinkCode, "http://localhost:3000/auth/verify", @@ -95,7 +86,6 @@ func main() { } return originalImplementation }, - // highlight-end }, }), }, @@ -103,10 +93,10 @@ func main() { } ``` - - + + -```python +```python {10,11,12,13,14,15} from supertokens_python import init, InputAppInfo from supertokens_python.recipe.passwordless.types import EmailDeliveryOverrideInput, EmailTemplateVars from supertokens_python.recipe import passwordless @@ -116,45 +106,41 @@ from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConf def custom_email_deliver(original_implementation: EmailDeliveryOverrideInput) -> EmailDeliveryOverrideInput: original_send_email = original_implementation.send_email - # highlight-start async def send_email(template_vars: EmailTemplateVars, user_context: Dict[str, Any]) -> None: assert template_vars.url_with_link_code is not None - # By default: `^{appInfo.websiteDomain}/^{appInfo.websiteBasePath}/verify` + # By default: `//auth/verify` template_vars.url_with_link_code = template_vars.url_with_link_code.replace( "http://localhost:3000/auth/verify", "http://localhost:3000/custom/path") return await original_send_email(template_vars, user_context) - # highlight-end original_implementation.send_email = send_email return original_implementation init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ passwordless.init( - contact_config="", # type: ignore # REMOVE_FROM_OUTPUT - flow_type="USER_INPUT_CODE", # REMOVE_FROM_OUTPUT email_delivery=EmailDeliveryConfig(override=custom_email_deliver) ) ] ) ``` - - + + ### Change the frontend page - + - + - - + + -When the user clicks the magic link, you need to render the `LinkClicked` component that exported by the SDK on that page. By default, this already happens on the `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/verify` path. To change this, you need to: +When the user clicks the magic link, you need to render the `LinkClicked` component that exported by the SDK on that page. By default, this already happens on the `/auth/verify` path. To change this, you need to: #### 1. Disable the default UI for the link clicked screen: ```tsx @@ -177,15 +163,14 @@ function CustomLinkClickedScreen () { } ``` - + - + When the user clicks the magic link, you need to build your own UI on that page to handle the link clicked. You also need to disable the pre-built UI provided by the SDK for the link clicked screen as shown below: ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless"; supertokensUIPasswordless.init({ contactMethod: "EMAIL", // This example will work with any contactMethod @@ -195,18 +180,18 @@ supertokensUIPasswordless.init({ }); ``` - + - + - - + + -:::info Caution +:::info[Caution] Not applicable since you do not use the pre-built UI ::: - + --- @@ -215,8 +200,8 @@ Not applicable since you do not use the pre-built UI You can use the backend SDK to generate magic links as shown below: - - + + ```tsx import Passwordless from "supertokens-node/recipe/passwordless"; @@ -228,8 +213,8 @@ async function createMagicLink(email: string) { } ``` - - + + ```go import ( @@ -251,13 +236,13 @@ func main() { } ``` - - + + - + - + ```python from supertokens_python.recipe.passwordless.asyncio import create_magic_link @@ -267,9 +252,9 @@ async def create_link(email: str): print(magic_link) ``` - + - + ```python from supertokens_python.recipe.passwordless.syncio import create_magic_link @@ -280,14 +265,14 @@ def create_link(email: str): print(magic_link) ``` - + - + - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] Notice that you pass the `"public"` `tenantId` to the function call above - which is the default `tenantId`. @@ -303,33 +288,23 @@ Note that the generated link uses the configured `websiteDomain` from the `appIn You can change how long a user can use an OTP or a Magic Link to log in by changing the `passwordless_code_lifetime` core configuration value. You configure this value in milliseconds and it defaults to `900000` (15 minutes). -:::caution - -Each new OTP / magic link generated, either by opening a new browser or by clicking on the "Resend" button, has a lifetime according to the `passwordless_code_lifetime` setting. +:::warning[Each new OTP / magic link generated, either by opening a new browser or by clicking on the "Resend" button, has a lifetime according to the `passwordless_code_lifetime` setting.] ::: - - + + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-start -e PASSWORDLESS_CODE_LIFETIME=60000 \ - // highlight-end -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -338,9 +313,9 @@ docker run \ passwordless_code_lifetime: 60000 ``` - + - + - Open the [SaaS Dashboard](https://supertokens.com/dashboard), select the relevant **Managed** deployment, and open **Configuration**. - In the **Passwordless** configuration card, change the value. Configuration changes are saved automatically. @@ -348,19 +323,19 @@ passwordless_code_lifetime: 60000 ```yaml passwordless_code_lifetime: 60000 ``` - + --- ## See also - - - - - - - - - + + + + + + + + + diff --git a/docs/authentication/passwordless/customize-the-otp.mdx b/docs/authentication/passwordless/customize-the-otp.mdx index f425ef5ba4..7702309a8e 100644 --- a/docs/authentication/passwordless/customize-the-otp.mdx +++ b/docs/authentication/passwordless/customize-the-otp.mdx @@ -1,25 +1,18 @@ --- title: Customize the One-Time Password (OTP) -hide_title: true -sidebar_position: 3 description: Configure OTP by changing the format or by modifying the token duration -page_type: guide -recipe: passwordless -category: passwordless +sidebar: + order: 3 --- - -# Customize the one-time password - - ## Change the OTP format By default, the generated OTP is 6 digits long and is numbers only. You can change this to be any length you like and have any character set by providing the `getCustomUserInputCode` function. - - + + -```tsx +```tsx {16,17,18,19} import SuperTokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; @@ -35,18 +28,16 @@ SuperTokens.init({ // This example works with the "USER_INPUT_CODE_AND_MAGIC_LINK" and "USER_INPUT_CODE" flows. flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", - // highlight-start getCustomUserInputCode: async (userCtx) => { // TODO: return "123abcd"; }, - // highlight-end }) ] }); ``` - - + + ```go import ( @@ -69,10 +60,10 @@ func main() { } ``` - - + + -```python +```python {15} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import passwordless from typing import Dict, Any @@ -82,21 +73,19 @@ async def get_custom_user_input_code(tenant_id: str, user_context: Dict[str, Any init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ passwordless.init( - contact_config=..., # type: ignore - flow_type="...", # type: ignore - # highlight-start + contact_config=..., + flow_type="...", get_custom_user_input_code=get_custom_user_input_code - # highlight-end ) ] ) ``` - - + + --- @@ -104,28 +93,20 @@ init( You can change how many times a user can attempt to enter an OTP before they have to enter their email / phone number again (thereby force generating a new OTP). By default, this value is `5` attempts, and you can modify it by changing the `passwordless_max_code_input_attempts` core configuration: - + - + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-start -e PASSWORDLESS_MAX_CODE_INPUT_ATTEMPTS=3 \ - // highlight-end -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -134,9 +115,9 @@ docker run \ passwordless_max_code_input_attempts: 3 ``` - + - + - Open the [SaaS Dashboard](https://supertokens.com/dashboard), select the relevant **Managed** deployment, and open **Configuration**. - In the **Passwordless** configuration card, change the value. Configuration changes are saved automatically. @@ -144,7 +125,7 @@ passwordless_max_code_input_attempts: 3 ```yaml passwordless_max_code_input_attempts: 3 ``` - + --- @@ -154,33 +135,23 @@ passwordless_max_code_input_attempts: 3 You can change how long a user can use an OTP or a Magic Link to log in by changing the `passwordless_code_lifetime` core configuration value. This value defaults to `900000` milliseconds (15 minutes). -:::caution - -Each new OTP / magic link generated, either by opening a new browser or by clicking on the "Resend" button, has a lifetime per the `passwordless_code_lifetime` setting. +:::warning[Each new OTP / magic link generated, either by opening a new browser or by clicking on the "Resend" button, has a lifetime per the `passwordless_code_lifetime` setting.] ::: - - + + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-start -e PASSWORDLESS_CODE_LIFETIME=60000 \ - // highlight-end -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -189,9 +160,9 @@ docker run \ passwordless_code_lifetime: 60000 ``` - + - + - Open the [SaaS Dashboard](https://supertokens.com/dashboard), select the relevant **Managed** deployment, and open **Configuration**. - In the **Passwordless** configuration card, change the value. Configuration changes are saved automatically. @@ -199,19 +170,19 @@ passwordless_code_lifetime: 60000 ```yaml passwordless_code_lifetime: 60000 ``` - + --- ## See also - - - - - - - - - + + + + + + + + + diff --git a/docs/authentication/passwordless/hooks-and-overrides.mdx b/docs/authentication/passwordless/hooks-and-overrides.mdx index 9180c3afdb..2ce48e4e9c 100644 --- a/docs/authentication/passwordless/hooks-and-overrides.mdx +++ b/docs/authentication/passwordless/hooks-and-overrides.mdx @@ -1,39 +1,30 @@ --- title: Hooks and overrides -hide_title: true -sidebar_position: 5 -description: >- - Add custom logic in the authentication flow by overriding the SuperTokens - APIs. -page_type: guide -recipe: passwordless -category: passwordless +description: Add custom logic in the authentication flow by overriding the SuperTokens APIs. +sidebar: + order: 5 --- - -# Hooks and overrides - - **SuperTokens** exposes a set of constructs that allow you to trigger different actions during the authentication lifecycle or to even fully customize the logic based on your use case. The following sections describe how you can adjust the `passwordless` recipe to your needs. -Explore the [references pages](/docs/references) for a more in depth guide on hooks and overrides. +Explore the [references pages](/references) for a more in depth guide on hooks and overrides. ## Frontend hook - + - + This method gets fired, after certain events in the `passwordles` authentication flow. Use it to fire different types of events immediately and introduce custom logic based on your use case. - + - + -```tsx +```tsx {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30} import SuperTokens from "supertokens-auth-react"; import Passwordless from "supertokens-auth-react/recipe/passwordless"; import Session from "supertokens-auth-react/recipe/session"; @@ -48,7 +39,6 @@ SuperTokens.init({ Passwordless.init({ contactMethod: "EMAIL_OR_PHONE", - // highlight-start onHandleEvent: async (context) => { if (context.action === "PASSWORDLESS_RESTART_FLOW") { // TODO: @@ -65,23 +55,19 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init() ] }); ``` - + - + -```tsx +```tsx {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -93,7 +79,6 @@ supertokensUIInit({ supertokensUIPasswordless.init({ contactMethod: "EMAIL_OR_PHONE", - // highlight-start onHandleEvent: async (context) => { if (context.action === "PASSWORDLESS_RESTART_FLOW") { // TODO: @@ -110,7 +95,6 @@ supertokensUIInit({ } } } - // highlight-end }), supertokensUISession.init() ] @@ -118,29 +102,29 @@ supertokensUIInit({ ``` - + - + - + - + -:::caution Not applicable +:::warning[Not applicable] This section is not applicable for custom UI since you are calling the consume code API yourself anyway. You can perform any actions post sign in / up based on the result of the API call. ::: - + ## Backend override Overriding the `consumeCode` function allows you to introduce your own logic for the authentication process. Use it to persist different types of data or trigger actions. - - + + -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41} import SuperTokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; import Session from "supertokens-node/recipe/session"; @@ -156,7 +140,6 @@ SuperTokens.init({ contactMethod: "EMAIL", // This example will work with any contactMethod flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType - // highlight-start override: { functions: (originalImplementation) => { return { @@ -183,16 +166,15 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init({ /* ... */ }) ] }); ``` - - + + -```go +```go {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47} import ( "fmt" @@ -206,7 +188,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ passwordless.Init(plessmodels.TypeInput{ - // highlight-start Override: &plessmodels.OverrideStruct{ Functions: func(originalImplementation plessmodels.RecipeInterface) plessmodels.RecipeInterface { // create a copy of the original function @@ -241,17 +222,16 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,68,69,70} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session, passwordless from supertokens_python.recipe.passwordless.interfaces import ( @@ -262,7 +242,6 @@ from typing import Dict, Any, Union, Optional from supertokens_python.recipe.session.interfaces import SessionContainer -# highlight-start def override_passwordless_functions( original_implementation: RecipeInterface, ) -> RecipeInterface: @@ -310,43 +289,39 @@ def override_passwordless_functions( return original_implementation -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ passwordless.init( contact_config=passwordless.ContactConfig( contact_method="EMAIL", # This example will work with any contactMethod ), flow_type="USER_INPUT_CODE_AND_MAGIC_LINK", # This example will work with any flowType - # highlight-start override=passwordless.InputOverrideConfig( functions=override_passwordless_functions ), - # highlight-end ), session.init(), ], ) ``` - - + + --- ## See also - - - - - - - - - - + + + + + + + + + + diff --git a/docs/authentication/passwordless/initial-setup.mdx b/docs/authentication/passwordless/initial-setup.mdx index 64d6e890c2..48acb221a6 100644 --- a/docs/authentication/passwordless/initial-setup.mdx +++ b/docs/authentication/passwordless/initial-setup.mdx @@ -1,22 +1,10 @@ --- title: Initial Setup -hide_title: true -sidebar_position: 2 -description: >- - Add Passwordless authentication to your project using Prebuilt or Custom UI - components. -page_type: tutorial -recipe: passwordless -category: passwordless +description: Add Passwordless authentication to your project using Prebuilt or Custom UI components. +sidebar: + order: 2 --- -import ReactRouterCallout from "/docs/_blocks/react-router-callout.mdx"; -import FrontendCustomUIMagicLinkUI from "./_blocks/frontend-custom-ui-magic-link-ui.mdx" -import FrontendCustomUIOtpUI from "./_blocks/frontend-custom-ui-otp-ui.mdx" -import BackendSDKInit from "./_blocks/backend-sdk-init.mdx" - -# Initial setup - ## Overview This page shows you how to add the **Passwordless** `recipe` to your project. @@ -24,9 +12,9 @@ The tutorial creates a login flow, rendered by either the **Prebuilt UI** compon ## Before you start -:::important +:::note -These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction). +These instructions assume that you already have gone through the main [quickstart guide](/quickstart/introduction). If you have skipped that page please follow the tutorial and return here once you're done. ::: @@ -39,50 +27,46 @@ Before going into the actual steps lets first talk about two terms that influenc ## Steps - + - + ### 1. Initialize the frontend SDK - - + + #### 1.1 Add the `Passwordless` recipe in your main configuration file. - + -```tsx +```tsx {4,17,18,19} import React from 'react'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; -// highlight-start import Passwordless from "supertokens-auth-react/recipe/passwordless"; -// highlight-end import Session from "supertokens-auth-react/recipe/session"; SuperTokens.init({ appInfo: { // learn more about this on https://supertokens.com/docs/references/frontend-sdks/reference#sdk-configuration - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", }, recipeList: [ -// highlight-start Passwordless.init({ - contactMethod: "^{recipes.passwordless.contactMethod}" + contactMethod: "EMAIL" }), -// highlight-end Session.init() ] }); ``` - + #### 1.2 Include the pre-built UI components in your application. @@ -90,9 +74,9 @@ To render the **Pre-Built UI** inside your application, you need to specify whic The **React SDK** uses [**React Router**](https://reactrouter.com/en/main) under the hood to achieve this. Based on whether you already use this package or not in your project, there are two different ways of configuring the routes. - - -```tsx + + +```tsx {9,21} import React from 'react'; import { BrowserRouter, @@ -101,7 +85,6 @@ import { Link } from "react-router-dom"; -// highlight-next-line import { PasswordlessPreBuiltUI } from 'supertokens-auth-react/recipe/passwordless/prebuiltui'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; @@ -113,8 +96,7 @@ class App extends React.Component { - {/*This renders the login UI on the ^{appInfo.websiteBasePath} route*/} - // highlight-next-line + {/*This renders the login UI on the /auth route*/} {getSuperTokensRoutesForReactRouterDom(reactRouterDom, [PasswordlessPreBuiltUI])} {/*Your app routes*/} @@ -125,12 +107,46 @@ class App extends React.Component { } ``` - + :::note[If you are using `useRoutes`, `createBrowserRouter` or have routes defined in a different file, you need to adjust the code sample.] +Please see [this issue](https://github.com/supertokens/supertokens-auth-react/issues/581#issuecomment-1246998493) for further details. +```tsx +import React from 'react'; - - +import { BrowserRouter, useRoutes } from "react-router-dom"; +import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; +import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; +import * as reactRouterDom from "react-router-dom"; -```tsx +function AppRoutes() { + const authRoutes = getSuperTokensRoutesForReactRouterDom( + reactRouterDom, + [/* Add your UI recipes here e.g. EmailPasswordPrebuiltUI, PasswordlessPrebuiltUI, ThirdPartyPrebuiltUI */] + ); + + const routes = useRoutes([ + ...authRoutes.map(route => route.props), + // Include the rest of your app routes + ]); + + return routes; +} + +function App() { + return ( + + + + + + ); +} +``` +::: + + + + +```tsx {8,9,10,11} import React from 'react'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; import { PasswordlessPreBuiltUI } from 'supertokens-auth-react/recipe/passwordless/prebuiltui'; @@ -138,12 +154,10 @@ import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; class App extends React.Component { render() { - // highlight-start if (canHandleRoute([PasswordlessPreBuiltUI])) { - // This renders the login UI on the ^{appInfo.websiteBasePath} route + // This renders the login UI on the /auth route return getRoutingComponent([PasswordlessPreBuiltUI]) } - // highlight-end return ( {/*Your app*/} @@ -152,21 +166,18 @@ class App extends React.Component { } ``` - - + + - - + + - - + + Add the `Passwordless` recipe in your `AuthComponent`. - + - ```tsx title="/app/auth/auth.component.ts" - import {init as supertokensUIInit} from "supertokens-auth-react-script"; - import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless"; - import supertokensUISession from "supertokens-auth-react-script/recipe/session"; + ```tsx title="/app/auth/auth.component.ts" {43,44,45} import { Component, OnDestroy, AfterViewInit, Renderer2, Inject } from "@angular/core"; import { DOCUMENT } from "@angular/common"; @@ -182,7 +193,7 @@ Add the `Passwordless` recipe in your `AuthComponent`. ) { } ngAfterViewInit() { - this.loadScript('^{prebuiltUIVersion}'); + this.loadScript('https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js'); } ngOnDestroy() { @@ -202,18 +213,16 @@ Add the `Passwordless` recipe in your `AuthComponent`. supertokensUIInit({ appInfo: { // learn more about this on https://supertokens.com/docs/references/frontend-sdks/reference#sdk-configuration - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", }, recipeList: [ -// highlight-start supertokensUIPasswordless.init({ - contactMethod: "^{recipes.passwordless.contactMethod}" + contactMethod: "EMAIL" }), -// highlight-end supertokensUISession.init(), ], }); @@ -223,21 +232,18 @@ Add the `Passwordless` recipe in your `AuthComponent`. } ``` - + - - + + - + - + Add the `Passwordless` recipe in your `AuthView` file. - + - ```tsx - import {init as supertokensUIInit} from "supertokens-auth-react-script"; - import supertokensUIPasswordless from "supertokens-auth-react-script/recipe/passwordless"; - import supertokensUISession from "supertokens-auth-react-script/recipe/session"; + ```tsx {21,22,23} + ``` You can initialize the SDK - + ```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensPasswordless from 'supertokens-web-js-script/recipe/passwordless' supertokens.init({ appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", appName: "...", }, recipeList: [ @@ -368,33 +509,32 @@ supertokens.init({ }); ``` - + - - - + - + - + - + + ```tsx import SuperTokens from 'supertokens-react-native'; SuperTokens.init({ - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", }); ``` - + - + Add the `SuperTokens.init` function call at the start of your application. @@ -407,18 +547,17 @@ class MainApplication: Application() { override fun onCreate() { super.onCreate() - SuperTokens.Builder(this, "^{appInfo.apiDomain}") - .apiBasePath("^{appInfo.apiBasePath}") + SuperTokens.Builder(this, "") + .apiBasePath("/auth") .build() } } ``` - - - + + ```swift @@ -430,8 +569,8 @@ fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { do { try SuperTokens.initialize( - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}" + apiDomain: "", + apiBasePath: "/auth" ) } catch SuperTokensError.initError(let message) { // TODO: Handle initialization error @@ -446,53 +585,963 @@ fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; void main() { SuperTokens.init( - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", ); } ``` - + - + - + - + ### 2. Add the login UI - + - + + +The following section shows you what aspects you need to cover to implement the UI for a `Magic Link` flow. +The same flow applies during either sign up or sign in. +This guide shows you how to determine if the system creates a new user in the next steps. + +#### 2.1 Sending the Magic link + +You need to add a form that asks the user for their email address or phone number. +When the user submits the form, you need to call the following API to create and send them a **Magic Link**. + +:::info[You configure the contact method on the next page, where you discuss the process of adding the `SDK` to your backend app.] + +::: + + + + + + + + + +```tsx +import { createCode } from "supertokens-web-js/recipe/passwordless"; + +async function sendMagicLink(email: string) { + try { + let response = await createCode({ + email + }); + /** + * For phone number, use this: + + let response = await createCode({ + phoneNumber: "+1234567890" + }); + + */ + + if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in / up was not allowed. + window.alert(response.reason) + } else { + // Magic link sent successfully. + window.alert("Please check your email for the magic link"); + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you, + // or if the input email / phone number is not valid. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + +```tsx +async function sendMagicLink(email: string) { + try { + let response = await supertokensPasswordless.createCode({ + email + }); + /** + * For phone number, use this: + + let response = await supertokens.createCode({ + phoneNumber: "+1234567890" + }); + + */ + + if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in / up was not allowed. + window.alert(response.reason) + } else { + // Magic link sent successfully. + window.alert("Please check your email for the magic link"); + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you, + // or if the input email / phone number is not valid. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + + + + + + +For email based login + +```bash +curl --location --request POST '/auth/signinup/code' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "email": "johndoe@gmail.com" +}' +``` + +For phone number based login +```bash +curl --location --request POST '/auth/signinup/code' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "phoneNumber": "+1234567890" +}' +``` - - +The response body from the API call has a `status` property in it: +- `status: "OK"`: This means that the magic link was successfully sent. +- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend, or if the input email or password failed the backend validation logic. +- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during multi-factor authentication (MFA). The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. - +The response from the API call is the following object (in case of `status: "OK"`): +```json +{ + status: "OK"; + deviceId: string; + preAuthSessionId: string; + flowType: "USER_INPUT_CODE" | "MAGIC_LINK" | "USER_INPUT_CODE_AND_MAGIC_LINK"; + fetchResponse: Response; // raw fetch response from the API call +} +``` + +You want to save the `deviceId` and `preAuthSessionId` on the frontend storage. These are useful to: +- Resend a new magic link. +- Detect if the user has already sent a magic link before or if this is an entirely new login attempt. This distinction can be important if you have different UI for these two states. For example, if this info already exists, you do not want to show the user an input box to enter their email / phone, and instead want to show them the resend link button. + + + + + +#### 2.2 Resending a magic link + +After sending the initial magic link to the user, you may want to display a resend button to them. +When the user clicks on this button, you should call the following API + + + + + + + +```tsx +import { resendCode, clearLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; + +async function resendMagicLink() { + try { + let response = await resendCode(); + + if (response.status === "RESTART_FLOW_ERROR") { + // this can happen if the user has already successfully logged in into + // another device whilst also trying to login to this one. + + // we clear the login attempt info that was added when the createCode function + // was called - so that if the user does a page reload, they will now see the + // enter email / phone UI again. + await clearLoginAttemptInfo(); + window.alert("Login failed. Please try again"); + window.location.assign("/auth") + } else { + // Magic link resent successfully. + window.alert("Please check your email for the magic link"); + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` - + + - +```tsx +async function resendMagicLink() { + try { + let response = await supertokensPasswordless.resendCode(); + + if (response.status === "RESTART_FLOW_ERROR") { + // this can happen if the user has already successfully logged in into + // another device whilst also trying to login to this one. + + // we clear the login attempt info that was added when the createCode function + // was called - so that if the user does a page reload, they will now see the + // enter email / phone UI again. + await supertokensPasswordless.clearLoginAttemptInfo(); + window.alert("Login failed. Please try again"); + window.location.assign("/auth") + } else { + // Magic link resent successfully. + window.alert("Please check your email for the magic link"); + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + + + + + +```bash +curl --location --request POST '/auth/signinup/code/resend' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "deviceId": "...", + "preAuthSessionId": "...." +}' +``` + + +The response body from the API call has a `status` property in it: +- `status: "OK"`: This means that the magic link was successfully sent. +- `status: "RESTART_FLOW_ERROR"`: This can happen if the user has already successfully logged in into another device whilst also trying to login to this one. You want to take the user back to the login screen where they can enter their email / phone number again. Be sure to remove the stored `deviceId` and `preAuthSessionId` from the frontend storage. +- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend. + + + + + +#### How to detect if the user is on step 2.1 or step 2.2? + +If you are building the UI for both of the previous steps on the same page you might run into an issue when the user refreshes the page. +To prevent this you need a way to know which UI to show. + + + + + + + +```tsx +import { getLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; + +async function hasInitialMagicLinkBeenSent() { + return await getLoginAttemptInfo() !== undefined; +} +``` + + + + +```tsx +async function hasInitialMagicLinkBeenSent() { + return await supertokensPasswordless.getLoginAttemptInfo() !== undefined; +} +``` + + + + +If `hasInitialMagicLinkBeenSent` returns `true`, it means that the user has already sent the initial magic link to themselves, and you can show the resend link UI. Else show a form asking them to enter their email / phone number. + + + + + +Since you save the `preAuthSessionId` and `deviceId` after sending the initial magic link, you can know if the user is on either **step 3.1** or **step 3.2**. Check if these tokens are on the device. + +If they aren't, you should follow **step 3.1**, else follow **step 3.2**. + +:::note[You need to clear these tokens if:] +- the user navigates away from the **step 3.2** page +- you get a `RESTART_FLOW_ERROR` at any point in time from an API call +- the user has successfully logged in. +::: + + + + + +#### 2.3 Consuming the magic link + +When a user clicks on a magic link, you first need to know if the action came from the same browser/device as the one that started the flow. +To do this you ca use this code sample. + + + + + + + +```tsx +import { getLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; + +async function isThisSameBrowserAndDevice() { + return await getLoginAttemptInfo() !== undefined; +} +``` + + + + +```tsx +async function isThisSameBrowserAndDevice() { + return await supertokensPasswordless.getLoginAttemptInfo() !== undefined; +} +``` + + + + + + + + +Since you save the `preAuthSessionId` and `deviceId`, you can check if they exist on the app. If they do, then it's the same device that the user has opened the link on, else it's a different device. + + + + + +:::note[Add a intermediate step if the user came from a different device.] + +::: + +If the user clicked on a link from a different device, you need to show some kind of an intermediate UI. +This is to protect against email clients opening the magic link on their servers and consuming the link. + +The page should require additional user interaction before consuming the magic link. +For example, you could show a button with the following text: `Click here to login into this device`. +On click, you can consume the magic link to log the user into that device. + +With this understanding of how to avoid potential errors, proceed with the actual instructions on how to authenticate with the magic link. + + + + + + + +```tsx +import { consumeCode, clearLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; + +async function handleMagicLinkClicked() { + try { + let response = await consumeCode(); + + if (response.status === "OK") { + // we clear the login attempt info that was added when the createCode function + // was called since the login was successful. + await clearLoginAttemptInfo(); + if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { + // user sign up success + } else { + // user sign in success + } + window.location.assign("/home") + } else { + // this can happen if the magic link has expired or is invalid + // or if it was denied due to security reasons in case of automatic account linking + + // we clear the login attempt info that was added when the createCode function + // was called - so that if the user does a page reload, they will now see the + // enter email / phone UI again. + await clearLoginAttemptInfo(); + window.alert("Login failed. Please try again"); + window.location.assign("/auth") + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + +```tsx +async function handleMagicLinkClicked() { + try { + let response = await supertokensPasswordless.consumeCode(); + + if (response.status === "OK") { + // we clear the login attempt info that was added when the createCode function + // was called since the login was successful. + await supertokensPasswordless.clearLoginAttemptInfo(); + if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { + // user sign up success + } else { + // user sign in success + } + window.location.assign("/home") + } else { + // this can happen if the magic link has expired or is invalid + // or if it was denied due to security reasons in case of automatic account linking + + // we clear the login attempt info that was added when the createCode function + // was called - so that if the user does a page reload, they will now see the + // enter email / phone UI again. + await supertokensPasswordless.clearLoginAttemptInfo(); + window.alert("Login failed. Please try again"); + window.location.assign("/auth") + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + + + + + +You need to remove the `linkCode` and `preAuthSessionId` from the Magic link. For example, if the Magic link is + +```text +https://example.com/auth/verify?preAuthSessionId=PyIwyA6VjdjNF5ggMV960rs3QXupRP2PEg2KcN5oi8s=#s4hxpBPnRC3xwBsCkFU228lh_CWe5HUBMRPowajsrgs= +``` + +Then the `preAuthSessionId` is the value of the query parameter `preAuthSessionId` (`PyIwyA6VjdjNF5ggMV960rs3QXupRP2PEg2KcN5oi8s=` in the example), and the `linkCode` is the part after the `#` (`s4hxpBPnRC3xwBsCkFU228lh_CWe5HUBMRPowajsrgs=` in the example). + +We can then use these to call the consume API + +```bash +curl --location --request POST '/auth/signinup/code/consume' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "linkCode": "s4hxpBPnRC3xwBsCkFU228lh_CWe5HUBMRPowajsrgs=", + "preAuthSessionId": "PyIwyA6VjdjNF5ggMV960rs3QXupRP2PEg2KcN5oi8s=" +}' +``` + + +:::info[Multi Tenancy] +For a multi-tenancy setup, the `` value can fetch from the `tenantId` query parameter from the magic link. If it's not there in the link, you can use the value `"public"` (which is the default tenant). +::: + +The response body from the API call has a `status` property in it: +- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. +- `status: "INCORRECT_USER_INPUT_CODE_ERROR" | "EXPIRED_USER_INPUT_CODE_ERROR" | "RESTART_FLOW_ERROR"`: These responses indicate that the Magic link was invalid or expired. +- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend. +- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during multi-factor authentication (MFA). The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. + + + + + + + + + +The following section shows you what aspects you need to cover to implement the UI for a `OTP`, One-Time Password, flow. +The same flow applies during either sign up or sign in. +This guide shows you how to determine if you create a new user in the next steps. + +#### 2.1 Creating and sending the OTP + +You have to add a form that asks the user for their email address or phone number. +When the users submit the form you have to call the following API to create and send them an OTP. + + + + + + + +```tsx +import { createCode } from "supertokens-web-js/recipe/passwordless"; + +async function sendOTP(email: string) { + try { + let response = await createCode({ + email + }); + /** + * For phone number, use this: + + let response = await createPasswordlessCode({ + phoneNumber: "+1234567890" + }); + + */ + + if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in / up was not allowed. + window.alert(response.reason) + } else { + // OTP sent successfully. + window.alert("Please check your email for an OTP"); + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you, + // or if the input email / phone number is not valid. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + +```tsx +async function sendOTP(email: string) { + try { + let response = await supertokensPasswordless.createCode({ + email + }); + /** + * For phone number, use this: + + let response = await supertokens.createCode({ + phoneNumber: "+1234567890" + }); + + */ + + if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in / up was not allowed. + window.alert(response.reason) + } else { + // OTP sent successfully. + window.alert("Please check your email for an OTP"); + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you, + // or if the input email / phone number is not valid. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + + + + + + +For email based login + +```bash +curl --location --request POST '/auth/signinup/code' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "email": "johndoe@gmail.com" +}' +``` + +For phone number based login +```bash +curl --location --request POST '/auth/signinup/code' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "phoneNumber": "+1234567890" +}' +``` + + +The response body from the API call has a `status` property in it: +- `status: "OK"`: This means that the OTP was successfully sent. +- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend, or if the input email or password failed the backend validation logic. +- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. + +The response from the API call is the following object (in case of `status: "OK"`): +```json +{ + status: "OK"; + deviceId: string; + preAuthSessionId: string; + flowType: "USER_INPUT_CODE" | "MAGIC_LINK" | "USER_INPUT_CODE_AND_MAGIC_LINK"; + fetchResponse: Response; // raw fetch response from the API call +} +``` + +You want to save the `deviceId` and `preAuthSessionId` on the frontend storage. These are useful to: +- Resend a new OTP. +- Detect if the user has already sent an OTP before or if this is an entirely new login attempt. This distinction can be important if you have different UI for these two states. For example, if this info already exists, you do not want to show the user an input box to enter their email / phone, and instead want to show them the enter OTP form with a resend button. +- Verify the user's input OTP. + + + + + +#### 2.2 Resending a OTP + +After you send the OTP to the user, you may want to display a resend button to them. +When the user clicks on this button, you should call the following API + + + + + + + +```tsx +import { resendCode, clearLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; + +async function resendOTP() { + try { + let response = await resendCode(); + + if (response.status === "RESTART_FLOW_ERROR") { + // this can happen if the user has already successfully logged in into + // another device whilst also trying to login to this one. + + // we clear the login attempt info that was added when the createCode function + // was called - so that if the user does a page reload, they will now see the + // enter email / phone UI again. + await clearLoginAttemptInfo(); + window.alert("Login failed. Please try again"); + window.location.assign("/auth") + } else { + // OTP resent successfully. + window.alert("Please check your email for the OTP"); + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + +```tsx +async function resendOTP() { + try { + let response = await supertokensPasswordless.resendCode(); + + if (response.status === "RESTART_FLOW_ERROR") { + // this can happen if the user has already successfully logged in into + // another device whilst also trying to login to this one. + + // we clear the login attempt info that was added when the createCode function + // was called - so that if the user does a page reload, they will now see the + // enter email / phone UI again. + await supertokensPasswordless.clearLoginAttemptInfo(); + window.alert("Login failed. Please try again"); + window.location.assign("/auth") + } else { + // OTP resent successfully. + window.alert("Please check your email for the OTP"); + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + + + + + + +```bash +curl --location --request POST '/auth/signinup/code/resend' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "deviceId": "...", + "preAuthSessionId": "...." +}' +``` + + +The response body from the API call has a `status` property in it: +- `status: "OK"`: This means that the OTP was successfully sent. +- `status: "RESTART_FLOW_ERROR"`: This can happen if the user has already successfully logged in into another device whilst also trying to login to this one. You want to take the user back to the login screen where they can enter their email / phone number again. Be sure to remove the stored `deviceId` and `preAuthSessionId` from the frontend storage. +- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend. + + + + + +#### How to detect if the user is on step 3.1 or step 3.2? + +If you are building the UI for both of the previous steps on the same page you might run into an issue when the user refreshes the page. +To prevent this you need a way to know which UI to show. + + + + + + + +```tsx +import { getLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; + +async function hasInitialOTPBeenSent() { + return await getLoginAttemptInfo() !== undefined; +} +``` + + + + +```tsx +async function hasInitialOTPBeenSent() { + return await supertokensPasswordless.getLoginAttemptInfo() !== undefined; +} +``` + + + + +If `hasInitialOTPBeenSent` returns `true`, it means that the user has already sent the initial OTP to themselves, and you can show the enter OTP form + resend OTP button 3.2. Else show a form asking them to enter their email / phone number 3.1. + + + + + +Since you save the `preAuthSessionId` and `deviceId` after you send the initial OTP, you can determine if the user is in step 3.1 or 3.2. +Check if you stored these tokens on the device. + +If they aren't, you should follow 3.1, else follow 3.2. + +:::note[You need to clear these tokens if:] +- the user navigates away from the 3.2 page +- you get a `RESTART_FLOW_ERROR` at any point in time from an API call +- the user has successfully logged in. +::: + + + + + +#### 2.3 Verifying the OTP + +When the user enters an OTP you have to call the following API to verify it + + + + + + + +```tsx +import { consumeCode, clearLoginAttemptInfo } from "supertokens-web-js/recipe/passwordless"; + +async function handleOTPInput(otp: string) { + try { + let response = await consumeCode({ + userInputCode: otp + }); + + if (response.status === "OK") { + // we clear the login attempt info that was added when the createCode function + // was called since the login was successful. + await clearLoginAttemptInfo(); + if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { + // user sign up success + } else { + // user sign in success + } + window.location.assign("/home") + } else if (response.status === "INCORRECT_USER_INPUT_CODE_ERROR") { + // the user entered an invalid OTP + window.alert("Wrong OTP! Please try again. Number of attempts left: " + (response.maximumCodeInputAttempts - response.failedCodeInputAttemptCount)); + } else if (response.status === "EXPIRED_USER_INPUT_CODE_ERROR") { + // it can come here if the entered OTP was correct, but has expired because + // it was generated too long ago. + window.alert("Old OTP entered. Please regenerate a new one and try again"); + } else { + // this can happen if the user tried an incorrect OTP too many times. + // or if it was denied due to security reasons in case of automatic account linking + + // we clear the login attempt info that was added when the createCode function + // was called - so that if the user does a page reload, they will now see the + // enter email / phone UI again. + await clearLoginAttemptInfo(); + window.alert("Login failed. Please try again"); + window.location.assign("/auth") + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + +```tsx +async function handleOTPInput(otp: string) { + try { + let response = await supertokensPasswordless.consumeCode({ + userInputCode: otp + }); + + if (response.status === "OK") { + // we clear the login attempt info that was added when the createCode function + // was called since the login was successful. + await supertokensPasswordless.clearLoginAttemptInfo(); + if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { + // user sign up success + } else { + // user sign in success + } + window.location.assign("/home") + } else if (response.status === "INCORRECT_USER_INPUT_CODE_ERROR") { + // the user entered an invalid OTP + window.alert("Wrong OTP! Please try again. Number of attempts left: " + (response.maximumCodeInputAttempts - response.failedCodeInputAttemptCount)); + } else if (response.status === "EXPIRED_USER_INPUT_CODE_ERROR") { + // it can come here if the entered OTP was correct, but has expired because + // it was generated too long ago. + window.alert("Old OTP entered. Please regenerate a new one and try again"); + } else { + // this can happen if the user tried an incorrect OTP too many times. + // or if it was denied due to security reasons in case of automatic account linking + + // we clear the login attempt info that was added when the createCode function + // was called - so that if the user does a page reload, they will now see the + // enter email / phone UI again. + await supertokensPasswordless.clearLoginAttemptInfo(); + window.alert("Login failed. Please try again"); + window.location.assign("/auth") + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + + + + + + +```bash +curl --location --request POST '/auth/signinup/code/consume' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "deviceId": "...", + "preAuthSessionId": "...", + "userInputCode": "" +}' +``` + + +The response body from the API call has a `status` property in it: +- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. +- `status: "INCORRECT_USER_INPUT_CODE_ERROR"`: The entered OTP is invalid. The response contains information about the maximum number of retries and the number of failed attempts. +- `status: "EXPIRED_USER_INPUT_CODE_ERROR"`: The entered OTP is too old. You should ask the user to resend a new OTP and try again. +- `status: "RESTART_FLOW_ERROR"`: These responses that the user tried invalid OTPs too many times. +- `status: "GENERAL_ERROR"`: This is possible if you have overridden the backend API to send back a custom error message which should display on the frontend. +- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. + + + + + + @@ -501,55 +1550,169 @@ On success, the backend sends back session tokens as part of the response header ### 3. Initialize the backend SDK - +You need to initialize the **Backend SDK** alongside the code that starts your server. +The init call includes [configuration details](/references/backend-sdks/reference#sdk-configuration) for your app. It specifies how the backend connects to the **SuperTokens Core**, as well as the **Recipes** used in your setup. + +For the **Passwordless** recipe, you also need to specify the `flowType` and `contactMethod`. +Click one of the options from the next form and the code snippet updates. + + + + + + + +```tsx title="Backend SDK Init" {3,24,25,26,27} +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import Passwordless from "supertokens-node/recipe/passwordless"; + +supertokens.init({ + // Replace this with the framework you are using + framework: "express", + supertokens: { + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + connectionURI: "https://try.supertokens.io", + // apiKey: + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [ + Passwordless.init({ + flowType: "MAGIC_LINK", + contactMethod: "EMAIL" + }), + Session.init() + ] +}); +``` + - + + + + + + + + + +```python title="Backend SDK Init" {3} +from supertokens_python import init, InputAppInfo, SupertokensConfig +from supertokens_python.recipe import passwordless, session +from supertokens_python.recipe.passwordless import ContactEmailOnlyConfig + +init( + app_info=InputAppInfo( + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" + ), + supertokens_config=SupertokensConfig( + # We use try.supertokens for demo purposes. + # At the end of the tutorial we will show you how to create + # your own SuperTokens core instance and then update your config. + connection_uri="https://try.supertokens.io", + # api_key: + ), + framework='fastapi', + recipe_list=[ + session.init(), # initializes session features + passwordless.init( + flow_type="MAGIC_LINK", + contact_config=ContactEmailOnlyConfig() + ) + ], + mode='asgi' # use wsgi if you are running using gunicorn +) +``` + + + + + + + + + +```go title="Backend SDK Init" +import ( + "github.com/supertokens/supertokens-golang/recipe/session" + "github.com/supertokens/supertokens-golang/recipe/passwordless" + "github.com/supertokens/supertokens-golang/recipe/passwordless/plessmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + apiBasePath := "/auth" + websiteBasePath := "/auth" + err := supertokens.Init(supertokens.TypeInput{ + Supertokens: &supertokens.ConnectionInfo{ + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + ConnectionURI: "https://try.supertokens.io", + // APIKey: + }, + AppInfo: supertokens.AppInfo{ + AppName: "", + APIDomain: "", + WebsiteDomain: "", + APIBasePath: &apiBasePath, + WebsiteBasePath: &websiteBasePath, + }, + RecipeList: []supertokens.Recipe{ + passwordless.Init(plessmodels.TypeInput{ + FlowType: "MAGIC_LINK", + ContactMethodEmailConfig + }), + session.Init(nil), // initializes session features + }, + }) + + if err != nil { + panic(err.Error()) + } +} +``` + + + + + + + + ## Next steps Having completed the main setup, you can explore more advanced topics related to the **Passwordless** recipe. - - - - Customize the Magic Link - - - Change how Magic Links get created. - - - - - OTP Customization - - - Change the format of the generated One-Time Password. - - - - - Hooks and overrides - - - Add custom logic after the logs in or signs up. - - - - - Email Delivery - - - Customize how emails get delivered to your users. - - - - - SMS Delivery - - - Customize how SMS messages get delivered to your users. - - - - + + +Change how Magic Links get created. + + +Change the format of the generated One-Time Password. + + +Add custom logic after the logs in or signs up. + + +Customize how emails get delivered to your users. + + +Customize how SMS messages get delivered to your users. + + diff --git a/docs/authentication/passwordless/introduction.mdx b/docs/authentication/passwordless/introduction.mdx index fcd26bd067..ab7caf01d0 100644 --- a/docs/authentication/passwordless/introduction.mdx +++ b/docs/authentication/passwordless/introduction.mdx @@ -1,97 +1,49 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -pagination_next: null -pagination_prev: null -skip_llms_txt: true -description: >- - Authenticate users with passwordless methods like Magic Links or One-Time - Passwords. -page_type: overview -recipe: passwordless -category: passwordless +description: Authenticate users with passwordless methods like Magic Links or One-Time Passwords. +sidebar: + order: 1 --- - -# Introduction - ## Overview The **Passwordless** `recipe` provides a way of authenticating users through generated credentials like **Magic Links** or **One-Time Passwords**. You can use it out of the box, with the **Pre-Built UI**, or implement your own interface through the available SDKs. -Sign in form UI for passwordless login +Sign in form UI for passwordless login ## Getting started You can either follow setup guide or use the `CLI` tool to generate an example app that shows you how the recipe works. - - - - Quickstart - - - Go through a quick tutorial that shows you how to add the **Passwordless** recipe to your app. - - - - - Example Applications - - - Use the CLI to generate a boilerplate app that you can use as a starting point. - - - + + +Go through a quick tutorial that shows you how to add the **Passwordless** recipe to your app. + + +Use the CLI to generate a boilerplate app that you can use as a starting point. + + ## Customization To adjust the functionality to fit your use case you can explore different sections from the documentation. - - - - Customize the Magic Link - - - Change how you create Magic Links. - - - - - One-Time Password (OTP) Customization - - - Change the format of the generated One-Time Password. - - - - - Hooks and Overrides - - - Add custom logic after the logs in or signs up. - - - - - Email Delivery - - - Customize how you deliver emails to your users. - - - - - SMS Delivery - - - Customize how you deliver SMS messages to your users. - - - - - + + +Change how you create Magic Links. + + +Change the format of the generated One-Time Password. + + +Add custom logic after the logs in or signs up. + + +Customize how you deliver emails to your users. + + +Customize how you deliver SMS messages to your users. + + diff --git a/docs/authentication/passwordless/invite-link-flow.mdx b/docs/authentication/passwordless/invite-link-flow.mdx index 8bc6585420..6166dff9f0 100644 --- a/docs/authentication/passwordless/invite-link-flow.mdx +++ b/docs/authentication/passwordless/invite-link-flow.mdx @@ -1,18 +1,10 @@ --- title: Implement invite link based sign up -hide_title: true -description: >- - Discover how to implement an invite based sign up flow with the passwordless - recipe. -sidebar_position: 10 -page_type: guide -recipe: passwordless -category: passwordless +description: Discover how to implement an invite based sign up flow with the passwordless recipe. +sidebar: + order: 10 --- - -# Passwordless login via invite link - ## Overview In this flow, the admin of the app calls an API to sign up a user and send them an invite link. @@ -21,8 +13,8 @@ If a user has not received an invitation before, their sign in attempt fails. ## Before you start -This guide assumes that you have already implemented the [EmailPassword recipe](/docs/authentication/email-password/introduction) and have a working application integrated with **SuperTokens**. -If you have not, please check the [Quickstart Guide](/docs/quickstart/introduction). +This guide assumes that you have already implemented the [EmailPassword recipe](/authentication/email-password/introduction) and have a working application integrated with **SuperTokens**. +If you have not, please check the [Quickstart Guide](/quickstart/introduction). ## Steps @@ -34,12 +26,12 @@ Additionally, protect the endpoint with a role requirement. The `passwordless` API uses the default magic link path, `/auth/verify`, for the invite link. If you are using the pre-built UI, the frontend SDK automatically logs the user in. -For custom UI implementations, use the [`consumeCode` function provided by the frontend SDK](/docs/authentication/passwordless/initial-setup) to call the `passwordless` API that verifies the code in the URL and creates the user. +For custom UI implementations, use the [`consumeCode` function provided by the frontend SDK](/authentication/passwordless/initial-setup) to call the `passwordless` API that verifies the code in the URL and creates the user. - - - - + + + + ```tsx import express from "express"; @@ -74,8 +66,8 @@ app.post("/create-user", verifySession({ }); ``` - - + + ```tsx import Hapi from "@hapi/hapi"; @@ -120,8 +112,8 @@ server.route({ } }) ``` - - + + ```tsx import Fastify from "fastify"; @@ -157,8 +149,8 @@ fastify.post("/create-user", { }); ``` - - + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; @@ -195,8 +187,8 @@ exports.handler = verifySession(createUser, { }); ``` - - + + ```tsx import KoaRouter from "koa-router"; @@ -232,8 +224,8 @@ router.post("/create-user", verifySession({ }); ``` - - + + ```tsx import { inject, intercept } from "@loopback/core"; @@ -271,12 +263,12 @@ class LikeComment { } ``` - - + + + - - + @@ -330,7 +322,6 @@ import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import UserRoles from "supertokens-node/recipe/userroles"; import Passwordless from "supertokens-node/recipe/passwordless"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -366,13 +357,12 @@ export function POST(request: NextRequest) { ``` - - + + ```tsx import { Controller, Post, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; import UserRoles from "supertokens-node/recipe/userroles"; import Passwordless from "supertokens-node/recipe/passwordless"; @@ -405,12 +395,12 @@ export class CreateUserController { } } ``` - - - - - - + + + + + + ```go import ( @@ -455,8 +445,8 @@ func createUserAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + ```go import ( @@ -515,8 +505,8 @@ func createUserAPI(c *gin.Context) { } ``` - - + + ```go import ( @@ -562,8 +552,8 @@ func createUserAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + ```go import ( @@ -609,13 +599,13 @@ func createUserAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + - - + + ```python from fastapi import Depends @@ -626,7 +616,7 @@ from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.userroles import UserRoleClaim -@app.post('/create-user') # type: ignore +@app.post('/create-user') async def create_user(session: SessionContainer = Depends(verify_session( override_global_claim_validators=lambda global_validators, session, user_context: global_validators + [UserRoleClaim.validators.includes("admin")] @@ -643,8 +633,8 @@ async def create_user(session: SessionContainer = Depends(verify_session( # TODO: send 200 responspe to client ``` - - + + ```python from supertokens_python.recipe.passwordless.syncio import create_magic_link, signinup @@ -652,7 +642,7 @@ from supertokens_python.recipe.session.framework.flask import verify_session from supertokens_python.recipe.userroles import UserRoleClaim -@app.route('/create_user', methods=['POST']) # type: ignore +@app.route('/create_user', methods=['POST']) @verify_session( override_global_claim_validators=lambda global_validators, session, user_context: global_validators + [UserRoleClaim.validators.includes("admin")] @@ -670,8 +660,8 @@ def create_user(): # TODO: send 200 responspe to client ``` - - + + ```python from django.http import HttpRequest @@ -698,14 +688,14 @@ async def create_user(request: HttpRequest): # TODO: send 200 responspe to client ``` - - + + - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] In the above code snippets, the `"public"` `tenantId` passes when calling the functions - this is the default `tenantId`. If you are using the multi-tenancy feature, you can pass in a different `tenantId` and this ensures that the user with that email adds only to that tenant. You also need to pass in the `tenantId` to the createMagicLink function which adds the `tenantId` to the generated magic link. The resulting link uses the `websiteDomain` configured in the `appInfo` object in `SuperTokens.init`, but you can change the link's domain to match that of the tenant before sending it. @@ -717,15 +707,14 @@ You also need to pass in the `tenantId` to the createMagicLink function which ad Update the backend SDK API function to only allow sign up requests from invited users. To do this you need to check if a user exists in **SuperTokens**. - - + + ```tsx import Passwordless from "supertokens-node/recipe/passwordless"; import supertokens from "supertokens-node"; Passwordless.init({ - contactMethod: "EMAIL", flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // typecheck-only, removed from output override: { apis: (originalImplementation) => { return { @@ -764,8 +753,8 @@ Passwordless.init({ }) ``` - - + + ```go import ( @@ -819,8 +808,8 @@ func main() { } ``` - - + + ```python from typing import Any, Dict, Optional, Union @@ -902,10 +891,10 @@ def override_passwordless_apis(original_implementation: APIInterface): init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ passwordless.init( - contact_config="", # type: ignore # typecheck-only, removed from output + contact_config="", # typecheck-only, removed from output flow_type="USER_INPUT_CODE", override=passwordless.InputOverrideConfig( apis=override_passwordless_apis, @@ -915,22 +904,20 @@ init( ) ``` - - - - + + --- ## See also - - - - - - - - - + + + + + + + + + diff --git a/docs/authentication/passwordless/meta.ts b/docs/authentication/passwordless/meta.ts new file mode 100644 index 0000000000..74cd3d4c92 --- /dev/null +++ b/docs/authentication/passwordless/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Passwordless", + "icon": "wand-sparkles", + "order": 2 +}); diff --git a/docs/authentication/social/_blocks/backend-providers-init.mdx b/docs/authentication/social/_blocks/backend-providers-init.mdx deleted file mode 100644 index 9e3bfadd2f..0000000000 --- a/docs/authentication/social/_blocks/backend-providers-init.mdx +++ /dev/null @@ -1,310 +0,0 @@ - -Populate the `providers` array with the third party authentication providers that you want. - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "...", - }, - recipeList: [ - ThirdParty.init({ - //highlight-start - signInAndUpFeature: { - // We have provided you with development keys which you can use for testing. - // IMPORTANT: Please replace them with your own OAuth keys for production use. - providers: [{ - config: { - thirdPartyId: "google", - clients: [{ - clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - clientSecret: "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" - }] - } - }, { - config: { - thirdPartyId: "github", - clients: [{ - clientId: "467101b197249757c71f", - clientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd" - }] - } - }, { - config: { - thirdPartyId: "apple", - clients: [{ - clientId: "4398792-io.supertokens.example.service", - additionalConfig: { - keyId: "7M48Y4RYDL", - privateKey: - "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", - teamId: "YWQCXGJRJL", - } - }] - } - }], - } - //highlight-end - }), - // ... - ] -}); -``` - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - // Inside supertokens.Init - thirdparty.Init(&tpmodels.TypeInput{ - // highlight-start - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - // We have provided you with development keys which you can use for testing. - // IMPORTANT: Please replace them with your own OAuth keys for production use. - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "google", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - ClientSecret: "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", - }, - }, - }, - }, - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "github", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "467101b197249757c71f", - ClientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd", - }, - }, - }, - }, - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "apple", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "4398792-io.supertokens.example.service", - AdditionalConfig: map[string]interface{}{ - "keyId": "7M48Y4RYDL", - "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", - "teamId": "YWQCXGJRJL", - }, - }, - }, - }, - }, - }, - }, - // highlight-end - }) -} -``` - - - -```python -from supertokens_python.recipe.thirdparty.provider import ProviderInput, ProviderConfig, ProviderClientConfig -from supertokens_python.recipe import thirdparty - -# Inside init -thirdparty.init( - # highlight-start - sign_in_and_up_feature=thirdparty.SignInAndUpFeature(providers=[ - # We have provided you with development keys which you can use for testing. - # IMPORTANT: Please replace them with your own OAuth keys for production use. - ProviderInput( - config=ProviderConfig( - third_party_id="google", - clients=[ - ProviderClientConfig( - client_id="1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - client_secret="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", - ), - ], - ), - ), - ProviderInput( - config=ProviderConfig( - third_party_id="github", - clients=[ - ProviderClientConfig( - client_id="467101b197249757c71f", - client_secret="e97051221f4b6426e8fe8d51486396703012f5bd", - ) - ], - ), - ), - ProviderInput( - config=ProviderConfig( - third_party_id="apple", - clients=[ - ProviderClientConfig( - client_id="io.supertokens.example.service", - additional_config={ - "keyId": "7M48Y4RYDL", - "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", - "teamId": "YWQCXGJRJL" - }, - ), - ], - ), - ), - ]) - # highlight-end -) -``` - - - - - -:::important -The examples use a set of development keys meant for demonstration purposes only. -Please use your own OAuth credentials. -Read the list of [built-in providers](/docs/authentication/social/built-in-providers-config) that also includes information on how to generate your own keys. -To add a provider that is not listed, you can follow the guide on [setting up custom providers](/docs/authentication/social/custom-providers). -::: - - -#### Set OAuth scopes - -To add additional OAuth scopes when accessing your third-party provider, add them to the configuration when initializing the backend `SDK`. - -For example if you are using Google as your third party provider, you can add an additional scope as follows: - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - supertokens: { - connectionURI: "...", - }, - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "google", - clients: [{ - clientId: "TODO: GOOGLE_CLIENT_ID", - clientSecret: "TODO: GOOGLE_CLIENT_SECRET", - scope: ["scope1", "scope2"] - }] - } - } - ] - } - }) - ] -}); -``` - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "google", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "TODO: GOOGLE_CLIENT_ID", - ClientSecret: "TODO: GOOGLE_CLIENT_SECRET", - Scope: []string{ - "scope1", "scope2", - }, - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="google", - clients=[ - ProviderClientConfig( - client_id="GOOGLE_CLIENT_ID", - client_secret="GOOGLE_CLIENT_SECRET", - scope=["scope1", "scope2"] - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - -:::important -Along with your custom scopes, also add scopes that ask for the user's email and its verification status. For example, with Google, this scope is `"https://www.googleapis.com/auth/userinfo.email"`. -::: diff --git a/docs/authentication/social/_blocks/backend-sdk-init.mdx b/docs/authentication/social/_blocks/backend-sdk-init.mdx deleted file mode 100644 index 1eb794bd37..0000000000 --- a/docs/authentication/social/_blocks/backend-sdk-init.mdx +++ /dev/null @@ -1,132 +0,0 @@ - -You have to initialize the **Backend Software Development Kit (SDK)** alongside the code that starts your server. -The init call includes [configuration details](/docs/references/backend-sdks/reference#sdk-configuration) for your app. It specifies how the backend connects to the **SuperTokens Core**, as well as the **Recipes** used in your setup. - - - - - - - -```tsx title="Backend SDK Init" showAppTypeSelect -import supertokens from "supertokens-node"; -import Session from "supertokens-node/recipe/session"; -// highlight-next-line -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -supertokens.init({ - // Replace this with the framework you are using - framework: "express", - supertokens: { - // We use try.supertokens for demo purposes. - // At the end of the tutorial we will show you how to create - // your own SuperTokens core instance and then update your config. - connectionURI: "https://try.supertokens.io^{derived.appIdPathname}", - // apiKey: - }, - appInfo: { - // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", - }, - recipeList: [ - // highlight-start - ThirdParty.init({/*TODO: See next step*/}), - // highlight-end - Session.init() - ] -}); -``` - - - - - - - - - - - -```python title="Backend SDK Init" showAppTypeSelect -from supertokens_python import init, InputAppInfo, SupertokensConfig -from supertokens_python.recipe import thirdparty, session -# highlight-next-line - -init( - app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" - ), - supertokens_config=SupertokensConfig( - # We use try.supertokens for demo purposes. - # At the end of the tutorial we will show you how to create - # your own SuperTokens core instance and then update your config. - connection_uri="https://try.supertokens.io^{derived.appIdPathname}", - # api_key: - ), - framework='fastapi', - recipe_list=[ - session.init(), # initializes session features - thirdparty.init( - # TODO: See next step - ) # type: ignore - ], - mode='asgi' # use wsgi if you are running using gunicorn -) -``` - - - - - - - - -```go title="Backend SDK Init" showAppTypeSelect -import ( - "github.com/supertokens/supertokens-golang/recipe/session" - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - apiBasePath := "^{appInfo.apiBasePath}" - websiteBasePath := "^{appInfo.websiteBasePath}" - err := supertokens.Init(supertokens.TypeInput{ - Supertokens: &supertokens.ConnectionInfo{ - // We use try.supertokens for demo purposes. - // At the end of the tutorial we will show you how to create - // your own SuperTokens core instance and then update your config. - ConnectionURI: "https://try.supertokens.io^{derived.appIdPathname}", - // APIKey: - }, - AppInfo: supertokens.AppInfo{ - AppName: "^{appInfo.appName}", - APIDomain: "^{appInfo.apiDomain}", - WebsiteDomain: "^{appInfo.websiteDomain}", - APIBasePath: &apiBasePath, - WebsiteBasePath: &websiteBasePath, - }, - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{/*TODO: See next step*/}), - session.Init(nil), // initializes session features - }, - }) - - if err != nil { - panic(err.Error()) - } -} -``` - - - - diff --git a/docs/authentication/social/_blocks/frontend-custom-ui-mobile-access-token-flow.mdx b/docs/authentication/social/_blocks/frontend-custom-ui-mobile-access-token-flow.mdx deleted file mode 100644 index 246b69644d..0000000000 --- a/docs/authentication/social/_blocks/frontend-custom-ui-mobile-access-token-flow.mdx +++ /dev/null @@ -1,44 +0,0 @@ - -### Fetching the OAuth/Access tokens on the frontend - -1. Sign in with the social provider. The minimum required scope is the one that provides access to the user's email. You can use any library to sign in with the social provider. -2. Get the access token on the frontend if it is available. -3. Get the id token from the sign in result if it is available. - -:::important -You need to provide either the access token or the id token, or both in step 2, depending on what is available. -::: - -### Calling the `signinup` API to use the OAuth tokens - - -Once you have the `access_token` or the `id_token` from the auth provider, you need to call the `/signinup` API exposed by the backend `SDK` as shown below: - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "thirdPartyId": "google", - "clientType": "...", - "oAuthTokens": { - "access_token": "...", - "id_token": "..." - }, -}' -``` - -:::important -- The `clientType` input is optional, and you need it only if you have initialised more than one client in the provide on the backend (See the "Social / Single Sign-On login for both, web and mobile apps" section below). -- If you have the `id_token`, you can send that along with the `access_token`. -::: - -The response body from the API call has a `status` property in it: -- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. -- `status: "NO_EMAIL_GIVEN_BY_PROVIDER"`: This occurs if the social / Single Sign-On provider did not provide an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider. -- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. -- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. - -:::note -On success, the backend sends back session tokens as part of the response headers which are automatically handled by the frontend `SDK` for you. -::: - diff --git a/docs/authentication/social/_blocks/frontend-custom-ui-mobile-authorization-code-flow.mdx b/docs/authentication/social/_blocks/frontend-custom-ui-mobile-authorization-code-flow.mdx deleted file mode 100644 index 6b134898a9..0000000000 --- a/docs/authentication/social/_blocks/frontend-custom-ui-mobile-authorization-code-flow.mdx +++ /dev/null @@ -1,666 +0,0 @@ - -### Sign in with Apple example - - - - - - - -#### Fetching the authorisation token on the frontend - -For react native apps, this involves setting up the [react-native-apple-authentication library](https://github.com/invertase/react-native-apple-authentication) in your app. Check out their `README` for steps on how to integrate their `SDK` into your application. The minimum scope required by SuperTokens is the one that gives the user's email. In the case of Apple, that could be the user's actual email or the proxy email provided by Apple - it doesn't matter. - -Once the integration is complete, you should call the `appleAuth.performRequest` function for iOS and the `appleAuthAndroid.signIn` function for Android. Either way, the result of the function is a one-time use auth code which you should send to your backend as shown in the next step. - -A full example of this is available in [the example app](https://github.com/supertokens/supertokens-react-native/blob/master/examples/with-thirdparty/apple.ts). - -In case you are using Expo, you can use the [expo-apple-authentication](https://docs.expo.dev/versions/latest/sdk/apple-authentication/) library instead (not that this library only works on iOS). - - - - - - - - - - -#### Fetching the authorisation token on the frontend - -:::info -At the moment this flow is not supported on Android. -::: - - - - - - - - - -#### Fetching the authorisation token on the frontend - -For iOS you use the normal sign in with apple flow and then use the authorization code to login with SuperTokens. You can see a full example of this in the `onAppleClicked` function in [the example app](https://github.com/supertokens/supertokens-ios/blob/master/examples/with-thirdparty/with-thirdparty/LoginScreen/LoginScreenViewController.swift). - -```swift -import UIKit -import AuthenticationServices - -fileprivate class ViewController: UIViewController, ASAuthorizationControllerPresentationContextProviding, ASAuthorizationControllerDelegate { - func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { - return view.window! - } - - func loginWithApple() { - let authorizationRequest = ASAuthorizationAppleIDProvider().createRequest() - authorizationRequest.requestedScopes = [.email, .fullName] - - let authorizationController = ASAuthorizationController(authorizationRequests: [authorizationRequest]) - - authorizationController.presentationContextProvider = self - authorizationController.delegate = self - authorizationController.performRequests() - } - - func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { - guard let credential: ASAuthorizationAppleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential, - let authorizationCode = credential.authorizationCode, - let authorizationCodeString: String = String(data: authorizationCode, encoding: .utf8), - let email: String = credential.email as? String, - let nameComponents: PersonNameComponents = credential.fullName as? PersonNameComponents, - let firstName: String = nameComponents.givenName as? String, - let lastName: String = nameComponents.familyName as? String else {return} - - // Send the user information and auth code to the backend. Refer to the next step. - } -} -``` - - - - - - - - - -#### Fetching the authorisation token on the frontend - -For flutter, use the [`sign_in_with_apple`](https://pub.dev/packages/sign_in_with_apple) package. Make sure to follow the prerequisite steps to get the package setup. After setup, use the snippet below to trigger the apple sign-in flow. You can see a full example of this in the `loginWithApple` function in [the example app](https://github.com/supertokens/supertokens-flutter/blob/master/examples/with-thirdparty/lib/screens/login.dart). - -```dart -import 'package:sign_in_with_apple/sign_in_with_apple.dart'; - -void loginWithApple() async { - try { - var credential = await SignInWithApple.getAppleIDCredential( - scopes: [ - AppleIDAuthorizationScopes.email, - AppleIDAuthorizationScopes.fullName, - ], - // Required for Android only - webAuthenticationOptions: WebAuthenticationOptions( - clientId: "", - redirectUri: Uri.parse( - "//callback/apple", - ), - ), - ); - - String authorizationCode = credential.authorizationCode; - String? idToken = credential.identityToken; - String? email = credential.email; - String? firstname = credential.givenName; - String? lastName = credential.familyName; - - // Send the user information and auth code to the backend. Refer to the next step. - } catch (e) { - // Sign in aborted or failed - } -} -``` - -In the snippet above for Android, you need an additional `webAuthenticationOptions` property when signing in with Apple. -This is because on Android the library uses the web login flow and requires the client id and redirection URI. -The `redirectUri` property here is the URL to which Apple makes a `POST` request after the user has logged in. -The SuperTokens backend SDKs provide an API for this at `//callback/apple`. - -#### Additional steps for Android - -For android, a way for the web login flow to redirect back to the app is also needed. By default, the API provided by the backend `SDKs` redirects to the website domain you provide when initializing the `SDK`. The API can be overridden to redirect to the app instead. For example, if using the Node.js `SDK`: - - - - - -```tsx -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -ThirdParty.init({ - // highlight-start - override: { - apis: (original) => { - return { - ...original, - appleRedirectHandlerPOST: async (input) => { - if (original.appleRedirectHandlerPOST === undefined) { - throw Error("Should never come here"); - } - - // inut.formPostInfoFromProvider contains all the query params attached by Apple - const stateInBase64 = input.formPostInfoFromProvider.state; - - // The web SDKs add a default state - if (stateInBase64 === undefined) { - // Redirect to android app - // We create a dummy URL to create the query string - const dummyUrl = new URL("http://localhost:8080"); - for (const [key, value] of Object.entries(input.formPostInfoFromProvider)) { - dummyUrl.searchParams.set(key, `${value}`); - } - - const queryString = dummyUrl.searchParams.toString(); - // Refer to the README of sign_in_with_apple to understand what this url is - const redirectUrl = `intent://callback?${queryString}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end`; - - input.options.res.setHeader("Location", redirectUrl, false); - input.options.res.setStatusCode(303); - input.options.res.sendHTMLResponse(""); - } else { - // For the web flow we can use the original implementation - original.appleRedirectHandlerPOST(input); - } - }, - }; - }, - }, - // highlight-end -}) -``` - - - - - -```go -import ( - "net/http" - "strings" - - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - thirdparty.Init(&tpmodels.TypeInput{ - Override: &tpmodels.OverrideStruct{ - // highlight-start - APIs: func(originalImplementation tpmodels.APIInterface) tpmodels.APIInterface { - originalAppleRedirectPost := *originalImplementation.AppleRedirectHandlerPOST - - *originalImplementation.AppleRedirectHandlerPOST = func(formPostInfoFromProvider map[string]interface{}, options tpmodels.APIOptions, userContext *map[string]interface{}) error { - // formPostInfoFromProvider contains all the query params attached by Apple - state, stateOk := formPostInfoFromProvider["state"].(string) - - queryParams := []string{} - if (!stateOk) || state == "" { - // Redirect to android app - for key, value := range formPostInfoFromProvider { - queryParams = append(queryParams, key+"="+value.(string)) - } - - queryString := "" - if len(queryParams) > 0 { - queryString = strings.Join(queryParams, "&") - } - - // Refer to the README of sign_in_with_apple to understand what this url is - redirectUri := "intent://callback?" + queryString + "#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end" - - options.Res.Header().Set("Location", redirectUri) - options.Res.WriteHeader(http.StatusSeeOther) - return nil - } else { - return originalAppleRedirectPost(formPostInfoFromProvider, options, userContext) - } - } - - return originalImplementation - }, - }, - // highlight-end - }) -} -``` - - - - - -```python -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty.interfaces import APIInterface, APIOptions -from typing import Dict, Any - -# highlight-start -def override_thirdparty_apis(original_implementation: APIInterface): - original_apple_redirect_post = original_implementation.apple_redirect_handler_post - - async def apple_redirect_handler_post( - form_post_info: Dict[str, Any], - api_options: APIOptions, - user_context: Dict[str, Any] - ): - # form_post_info contains all the query params attached by Apple - state = form_post_info["state"] - - # The web SDKs add a default state - if state is None: - query_items = [ - f"{key}={value}" for key, value in form_post_info.items() - ] - - query_string = "&".join(query_items) - - # Refer to the README of sign_in_with_apple to understand what this url is - redirect_url = "intent://callback?" + query_string + "#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end" - - api_options.response.set_header("Location", redirect_url) - api_options.response.set_status_code(303) - api_options.response.set_html_content("") - else: - return await original_apple_redirect_post(form_post_info, api_options, user_context) - - original_implementation.apple_redirect_handler_post = apple_redirect_handler_post - return original_implementation -# highlight-end - -thirdparty.init( - # highlight-start - override=thirdparty.InputOverrideConfig( - apis=override_thirdparty_apis - ), - # highlight-end -) -``` - - - - - -In the code above, the `appleRedirectHandlerPOST` API is overridden to check if the request came from the Android app. You can skip checking the state if you only have a mobile app and no website. `sign_in_with_apple` requires parsing the query params sent by Apple and including them in the redirect URL in a specific way. Then, redirect to the deep link URL. Refer to the README for `sign_in_with_apple` to read about the deep link setup required in Android. - - - - - - - -#### Calling the `signinup` API to consume the authorisation token - - - -Once you have the authorization code from the auth provider, you need to call the `/signinup` API exposed by the backend `SDK` as shown below: - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "thirdPartyId": "apple", - "clientType": "...", - "redirectURIInfo": { - "redirectURIOnProviderDashboard": "^{appInfo.apiDomain}^{appInfo.apiBasePath}/callback/apple", - "redirectURIQueryParams": { - "code": "...", - "user": { - "name":{ - "firstName":"...", - "lastName":"..." - }, - "email":"..." - } - } - } -}' -``` - -:::important -- On iOS, the client id set in the backend should be the same as the bundle identifier for your app. -- The `clientType` input is optional and required only if you initialize more than one client in the provider on the backend (See the "Social / `SSO` login for both, web and mobile apps" section below). -- On iOS, `redirectURIOnProviderDashboard` doesn't matter and its value can be a universal link configured for your app. -- On Android, the `redirectURIOnProviderDashboard` should match the one configured on the Apple developer dashboard. -- The `user` object contains information provided by Apple. -::: - -The response body from the API call has a `status` property in it: -- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. -- `status: "NO_EMAIL_GIVEN_BY_PROVIDER"`: This status occurs if the social / `SSO` provider did not provide an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider. -- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. -- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. - -:::note -On success, the backend sends back session tokens as part of the response headers which are automatically handled by the frontend `SDK` for you. -::: - - -### Sign in with Google example - - - - - - - -#### Fetching the authorisation token on the frontend - -This involves setting up the [@react-native-google-signin/google-signin](https://github.com/react-native-google-signin/google-signin) in your app. Checkout their `README` for steps on how to integrate their `SDK` into your application. The minimum scope required by SuperTokens is the one that gives the user's email. - -Once you configure the library, use `GoogleSignin.configure` and `GoogleSignin.signIn` to trigger the login flow and sign the user in with Google. Refer to [the example app](https://github.com/supertokens/supertokens-react-native/blob/master/examples/with-thirdparty/google.ts) to see the full code for this. - -```tsx -import { GoogleSignin } from "@react-native-google-signin/google-signin"; - -export const performGoogleSignIn = async (): Promise => { - GoogleSignin.configure({ - webClientId: "GOOGLE_WEB_CLIENT_ID", - iosClientId: "GOOGLE_IOS_CLIENT_ID", - }); - - try { - const response = await GoogleSignin.signIn({}); - const authCode = response.data?.serverAuthCode; - - // Refer to step 2 - - return true; - } catch (e) { - console.log("Google sign in failed with error", e); - } - - return false; -}; -``` - - - - - - - - - - -#### Fetching the authorisation token on the frontend - -Follow the [official Google Sign In guide](https://developers.google.com/identity/sign-in/android/start-integrating) to set up their library and sign the user in with Google. Fetch the authorization code from the Google sign-in result. For a full example, refer to the `signInWithGoogle` function in [the example app](https://github.com/supertokens/supertokens-android/blob/master/examples/with-thirdparty/app/src/main/java/com/supertokens/supertokensexample/LoginActivity.kt). - -```kotlin -import androidx.activity.result.ActivityResult -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle -import android.util.Log -import com.google.android.gms.auth.api.signin.GoogleSignIn -import com.google.android.gms.auth.api.signin.GoogleSignInOptions -import android.content.Intent - -class LoginActivity : AppCompatActivity() { - private lateinit var googleResultLauncher: ActivityResultLauncher - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - googleResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - onGoogleResultReceived(it) - } - } - - private fun signInWithGoogle() { - val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) - .requestServerAuthCode("GOOGLE_WEB_CLIENT_ID") - .requestEmail() - .build() - - val googleClient = GoogleSignIn.getClient(this, gso) - val signInIntent = googleClient.signInIntent - - googleResultLauncher.launch(signInIntent) - } - - private fun onGoogleResultReceived(it: ActivityResult) { - val task = GoogleSignIn.getSignedInAccountFromIntent(it.data) - val account = task.result - val authCode = account.serverAuthCode - - // Refer to step 2 - } -} -``` - - - - - - - - - -#### Fetching the authorisation token on the frontend - -For iOS, use the `GoogleSignIn` library. Follow the [official guide](https://developers.google.com/identity/sign-in/ios/start-integrating) to set up the library and sign the user in with Google. Use the result of Google sign-in to get the authorization code. For a full example, refer to the `onGoogleCliked` function in [the example app](https://github.com/supertokens/supertokens-ios/blob/master/examples/with-thirdparty/with-thirdparty/LoginScreen/LoginScreenViewController.swift). - -```swift -import UIKit -import GoogleSignIn - -fileprivate class LoginScreenViewController: UIViewController { - @IBAction func onGoogleCliked() { - GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in - guard error == nil else { return } - - guard let authCode: String = signInResult?.serverAuthCode as? String else { - print("Google login did not return an authorisation code") - return - } - - // Refer to step 2 - } - } -} -``` - - - - - - - - - -#### Fetching the authorisation token on the frontend - -For flutter, use the [`google_sign_in`](https://pub.dev/packages/google_sign_in) package. Make sure to follow the prerequisite steps to get the package setup. After setup, use the snippet below to trigger the Google sign-in flow. For a full example, refer to the `loginWithGoogle` in [the example app](https://github.com/supertokens/supertokens-flutter/blob/master/examples/with-thirdparty/lib/screens/login.dart). - -```dart -import 'package:google_sign_in/google_sign_in.dart'; -import 'dart:io'; - -Future loginWithGoogle() async { - GoogleSignIn googleSignIn; - - if (Platform.isAndroid) { - googleSignIn = GoogleSignIn( - serverClientId: "GOOGLE_WEB_CLIENT_ID", - scopes: [ - 'email', - ], - ); - } else { - googleSignIn = GoogleSignIn( - clientId: "GOOGLE_IOS_CLIENT_ID", - serverClientId: "GOOGLE_WEB_CLIENT_ID", - scopes: [ - 'email', - ], - ); - } - - GoogleSignInAccount? account = await googleSignIn.signIn(); - - if (account == null) { - print("Google sign in was aborted"); - return; - } - - String? authCode = account.serverAuthCode; - - if (authCode == null) { - print("Google sign in did not return a server auth code"); - return; - } - - // Refer to step 2 - } -``` - - - - - - - -

Step 2) Calling the `signinup` API to consume the authorisation token

- - - -Once you have the authorization code from the auth provider, you need to call the `signinup` API exposed by the backend `SDK` as shown below: - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "thirdPartyId": "google", - "clientType": "...", - "redirectURIInfo": { - "redirectURIOnProviderDashboard": "", - "redirectURIQueryParams": { - "code": "...", - } - } -}' -``` - -:::important -When calling the API exposed by the SuperTokens backend `SDK`, pass an empty string for `redirectURIOnProviderDashboard`. -The native login flow using the authorization code does not involve any redirection on the frontend. -::: - -The response body from the API call has a `status` property in it: -- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. -- `status: "NO_EMAIL_GIVEN_BY_PROVIDER"`: This status occurs if the social / `SSO` provider did not provide an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider. -- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. -- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. - -:::note -On success, the backend sends back session tokens as part of the response headers which are automatically handled by the frontend `SDK` for you. -::: - - -### Authorization code grant flow with `PKCE` - -This is similar to the first one, except that you do **not** need to provide a client secret during backend init. -This flow only works for providers which support the [`PKCE` flow](https://oauth.net/2/pkce/). - - - - - - - -#### Fetching the authorisation token on the frontend - -You can use the [react native auth library](https://github.com/FormidableLabs/react-native-app-auth) to also return the `PKCE` code verifier along with the authorization code. Achieve this by setting the `usePKCE` boolean to `true` and also by setting the `skipCodeExchange` to `true` when configuring the react native auth library. - - - - - - - - - - -#### Fetching the authorisation token on the frontend - -You can use the [AppAuth-Android](https://github.com/openid/AppAuth-Android) library to use the `PKCE` flow by using the `setCodeVerifier` method when creating a `AuthorizationRequest`. - - - - - - - - - -#### Fetching the authorisation token on the frontend - -You can use the [AppAuth-iOS](https://github.com/openid/AppAuth-iOS) library to use the `PKCE` flow. - - - - - - - - - - -#### Fetching the authorisation token on the frontend - -You can use [`flutter_appauth`](https://pub.dev/packages/flutter_appauth) to use the `PKCE` flow by providing a `codeVerifier` when you call the `appAuth.token` function. - - - - - - - -#### Calling the `signinup` API to consume the authorisation token - - - -Once you have the authorization code and `PKCE` verifier from the auth provider, you need to call the `/signinup` API exposed by the backend `SDK` as shown below: - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signinup' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "thirdPartyId": "THIRD_PARTY_ID", - "clientType": "...", - "redirectURIInfo": { - "redirectURIOnProviderDashboard": "REDIRECT_URI", - "redirectURIQueryParams": { - "code": "...", - }, - "pkceCodeVerifier": "..." - } -}' -``` - -:::important -- Replace `THIRD_PARTY_ID` with the provider id. The provider id must match the one you configure in the backend when initialising SuperTokens. -- `REDIRECT_URI` must exactly match the value you configure on the providers dashboard. -::: - -The response body from the API call has a `status` property in it: -- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. -- `status: "NO_EMAIL_GIVEN_BY_PROVIDER"`: This status occurs if the social / `SSO` provider did not provide an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider. -- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. -- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. - -:::note -On success, the backend sends back session tokens as part of the response headers which are automatically handled by the frontend `SDK` for you. -::: diff --git a/docs/authentication/social/_blocks/frontend-custom-ui-web-authorization-code-flow.mdx b/docs/authentication/social/_blocks/frontend-custom-ui-web-authorization-code-flow.mdx deleted file mode 100644 index 0997e98f23..0000000000 --- a/docs/authentication/social/_blocks/frontend-custom-ui-web-authorization-code-flow.mdx +++ /dev/null @@ -1,261 +0,0 @@ - -#### Redirecting to a social/single sign-on provider - -The first step is to fetch the URL on which the user authenticates. You can do this by querying the backend API exposed by SuperTokens (as shown below). The backend SDK automatically appends the right query params to the URL (like scope, client ID etc). - -After getting the URL, redirect the user there. In the code below, an example of login with Google appears: - - - - - -```tsx -import { getAuthorisationURLWithQueryParamsAndSetState } from "supertokens-web-js/recipe/thirdparty"; - -async function googleSignInClicked() { - try { - const authUrl = await getAuthorisationURLWithQueryParamsAndSetState({ - thirdPartyId: "google", - - // This is where Google should redirect the user back after login or error. - // This URL goes on the Google's dashboard as well. - frontendRedirectURI: "http:///auth/callback/google", - }); - - /* - Example value of authUrl: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&client_id=1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com&state=5a489996a28cafc83ddff&redirect_uri=https%3A%2F%2Fsupertokens.io%2Fdev%2Foauth%2Fredirect-to-app&flowName=GeneralOAuthFlow - */ - - // we redirect the user to google for auth. - window.location.assign(authUrl); - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - -```tsx -import supertokensThirdParty from "supertokens-web-js-script/recipe/thirdparty"; -async function googleSignInClicked() { - try { - const authUrl = await supertokensThirdParty.getAuthorisationURLWithQueryParamsAndSetState({ - thirdPartyId: "google", - - // This is where Google should redirect the user back after login or error. - // This URL goes on the Google's dashboard as well. - frontendRedirectURI: "http:///auth/callback/google", - }); - - /* - Example value of authUrl: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&client_id=1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com&state=5a489996a28cafc83ddff&redirect_uri=https%3A%2F%2Fsupertokens.io%2Fdev%2Foauth%2Fredirect-to-app&flowName=GeneralOAuthFlow - */ - - // we redirect the user to google for auth. - window.location.assign(authUrl); - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - -#### Handling the auth callback on your frontend - -Once the third party provider redirects your user back to your app, you need to consume the information to sign in the user. This requires you to: -- Setup a route in your app that handles this callback. It's recommended to use something like `http:///auth/callback/google` (for Google). Regardless of what you make this path, remember to use that same path when calling the `getAuthorisationURLWithQueryParamsAndSetState` function in the first step. - -- On that route, call the following function on page load - - - - -```tsx -import { signInAndUp } from "supertokens-web-js/recipe/thirdparty"; - -async function handleGoogleCallback() { - try { - const response = await signInAndUp(); - - if (response.status === "OK") { - console.log(response.user) - if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { - // sign up successful - } else { - // sign in successful - } - window.location.assign("/home"); - } else if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { - // the reason string is a user friendly message - // about what went wrong. It can also contain a support code which users - // can tell you so you know why their sign in / up was not allowed. - window.alert(response.reason) - } else { - // SuperTokens requires that the third party provider - // gives an email for the user. If that's not the case, sign up / in - // will fail. - - // As a hack to solve this, you can override the backend functions to create a fake email for the user. - - window.alert("No email provided by social login. Please use another form of login"); - window.location.assign("/auth"); // redirect back to login page - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - -```tsx -import supertokensThirdParty from "supertokens-web-js-script/recipe/thirdparty"; -async function handleGoogleCallback() { - try { - const response = await supertokensThirdParty.signInAndUp(); - - if (response.status === "OK") { - console.log(response.user) - if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { - // sign up successful - } else { - // sign in successful - } - window.location.assign("/home"); - } else if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { - // the reason string is a user friendly message - // about what went wrong. It can also contain a support code which users - // can tell you so you know why their sign in / up was not allowed. - window.alert(response.reason) - } else { - // SuperTokens requires that the third party provider - // gives an email for the user. If that's not the case, sign up / in - // will fail. - - // As a hack to solve this, you can override the backend functions to create a fake email for the user. - - window.alert("No email provided by social login. Please use another form of login"); - window.location.assign("/auth"); // redirect back to login page - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - -:::note -On success, the backend sends back session tokens as part of the response headers which are automatically handled by the frontend SDK. -::: - -#### Special case for login with Apple - - - -Unlike other providers, Apple does not redirect your user back to your frontend app. Instead, it redirects the user to your backend with a `FORM POST` request. This means that the URL you configure on Apple's dashboard should point to your backend API layer. Here, **middleware** handles the request and redirects the user to your frontend app. Your frontend app should then call the `signInAndUp` API on that page as shown previously. - -To tell SuperTokens which frontend route to redirect the user back to, set the `frontendRedirectURI` to the frontend route. Also, set the `redirectURIOnProviderDashboard` to point to your backend API route, to which Apple sends a `POST` request. - - - - -```tsx -import { getAuthorisationURLWithQueryParamsAndSetState } from "supertokens-web-js/recipe/thirdparty"; - -async function appleSignInClicked() { - try { - const authUrl = await getAuthorisationURLWithQueryParamsAndSetState({ - thirdPartyId: "apple", - - frontendRedirectURI: "http://localhost:3000/auth/callback/apple", // This is an example callback URL on your frontend. You can use another path as well. - // highlight-start - redirectURIOnProviderDashboard: "^{appInfo.apiDomain}^{appInfo.apiBasePath}/callback/apple", // This URL goes on the Apple's dashboard - // highlight-end - }); - - // we redirect the user to apple for auth. - window.location.assign(authUrl); - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - - -```tsx -import supertokensThirdParty from "supertokens-web-js-script/recipe/thirdparty"; -async function appleSignInClicked() { - try { - const authUrl = await supertokensThirdParty.getAuthorisationURLWithQueryParamsAndSetState({ - thirdPartyId: "apple", - - frontendRedirectURI: "http://localhost:3000/auth/callback/apple", // This is an example callback URL on your frontend. You can use another path as well. - // highlight-start - redirectURIOnProviderDashboard: "^{appInfo.apiDomain}^{appInfo.apiBasePath}/callback/apple", // This URL goes on the Apple's dashboard - // highlight-end - }); - - /* - Example value of authUrl: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&client_id=1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com&state=5a489996a28cafc83ddff&redirect_uri=https%3A%2F%2Fsupertokens.io%2Fdev%2Foauth%2Fredirect-to-app&flowName=GeneralOAuthFlow - */ - - // we redirect the user to google for auth. - window.location.assign(authUrl); - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` - - - - - -:::info - -If you are using the **Authorization Code Grant** flow with **PKCE** you do **not** need to provide a client secret during backend init. -This only works for providers which support the [PKCE flow](https://oauth.net/2/pkce/). - -::: - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-active-directory.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-active-directory.mdx deleted file mode 100644 index 2d0e7f6c9f..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-active-directory.mdx +++ /dev/null @@ -1,99 +0,0 @@ - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "active-directory", - name: "Active Directory", - clients: [{ - clientId: "...", - clientSecret: "...", - }], - oidcDiscoveryEndpoint: "https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "active-directory", - Name: "Active Directory", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - ClientSecret: "...", - }, - }, - OIDCDiscoveryEndpoint: "https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="active-directory", - name="Active Directoy", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], - oidc_discovery_endpoint="https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-apple.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-apple.mdx deleted file mode 100644 index 616ed35210..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-apple.mdx +++ /dev/null @@ -1,185 +0,0 @@ - -Call the following function / API to add the third party provider to a specific tenant. - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "apple", - name: "Apple", - clients: [{ - clientId: "...", - additionalConfig: { - "keyId": "...", - "privateKey": "...", - "teamId": "...", - } - }] - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "apple", - Name: "Apple", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - AdditionalConfig: map[string]interface{}{ - "keyId": "...", - "privateKey": "...", - "teamId": "...", - }, - }, - }, - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="apple", - name="Apple", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - additional_config={ - "keyId": "...", - "privateKey": "...", - "teamId": "...", - }, - ), - ], - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="apple", - name="Apple", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - additional_config={ - "keyId": "...", - "privateKey": "...", - "teamId": "...", - }, - ), - ], -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "apple", - "name": "Apple", - "clients": [ - { - "clientId": "...", - "additionalConfig": { - "keyId": "...", - "privateKey": "...", - "teamId": "..." - } - } - ] - } -}' -``` - - - - - -Create Apple Provider - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-bitbucket.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-bitbucket.mdx deleted file mode 100644 index a5b46ae719..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-bitbucket.mdx +++ /dev/null @@ -1,111 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "google", - clients: [{ - clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - clientSecret: "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", - }] - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "google", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - ClientSecret: "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", - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="google", - clients=[ - ProviderClientConfig( - client_id="1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - client_secret="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", - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-discord.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-discord.mdx deleted file mode 100644 index 0cc994795d..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-discord.mdx +++ /dev/null @@ -1,161 +0,0 @@ - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "discord", - name: "Discord", - clients: [{ - clientId: "...", - clientSecret: "...", - }] - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "discord", - Name: "Discord", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - ClientSecret: "...", - }, - }, - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="discord", - name="Discord", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="discord", - name="Discord", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "discord", - "name": "Discord", - "clients": [ - { - "clientId": "...", - "clientSecret": "..." - } - ] - } -}' -``` - - - - - -Create Discord Provider - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-facebook.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-facebook.mdx deleted file mode 100644 index aef8466715..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-facebook.mdx +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "facebook", - name: "Facebook", - clients: [{ - clientId: "...", - clientSecret: "...", - }] - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "facebook", - Name: "Facebook", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - ClientSecret: "...", - }, - }, - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="facebook", - name="Facebook", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="facebook", - name="Facebook", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "facebook", - "name": "Facebook", - "clients": [ - { - "clientId": "...", - "clientSecret": "..." - } - ] - } -}' -``` - - - - - -Create Facebook Provider - - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-github.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-github.mdx deleted file mode 100644 index f37acf4314..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-github.mdx +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "github", - name: "GitHub", - clients: [{ - clientId: "...", - clientSecret: "...", - }] - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "github", - Name: "GitHub", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - ClientSecret: "...", - }, - }, - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="github", - name="GitHub", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="github", - name="GitHub", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}/recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "github", - "name": "GitHub", - "clients": [ - { - "clientId": "...", - "clientSecret": "..." - } - ] - } -}' -``` - - - - - - -Create GitHub Provider - - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-gitlab.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-gitlab.mdx deleted file mode 100644 index 91ad2d0137..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-gitlab.mdx +++ /dev/null @@ -1,168 +0,0 @@ - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "gitlab", - name: "GitLab", - clients: [{ - clientId: "...", - clientSecret: "...", - }], - oidcDiscoveryEndpoint: "https://gitlab.example.com/.well-known/openid-configuration", - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "gitlab", - Name: "GitLab", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - ClientSecret: "...", - }, - }, - OIDCDiscoveryEndpoint: "https://gitlab.example.com/.well-known/openid-configuration", - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="gitlab", - name="Gitlab", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], - oidc_discovery_endpoint="https://gitlab.example.com/.well-known/openid-configuration" - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="gitlab", - name="Gitlab", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], - oidc_discovery_endpoint="https://gitlab.example.com/.well-known/openid-configuration" -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "gitlab", - "name": "GitLab", - "clients": [ - { - "clientId": "...", - "clientSecret": "..." - } - ], - "oidcDiscoveryEndpoint": "https://gitlab.example.com/.well-known/openid-configuration" - } -}' -``` - - - - - - -Create GitLab Provider - - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-google-workspaces.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-google-workspaces.mdx deleted file mode 100644 index 71b7b95ac2..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-google-workspaces.mdx +++ /dev/null @@ -1,174 +0,0 @@ - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "google-workspaces", - name: "Google Workspaces", - clients: [{ - clientId: "...", - clientSecret: "...", - additionalConfig: { - "hd": "example.com", - } - }] - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "google-workspaces", - Name: "Google Workspaces", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - ClientSecret: "...", - AdditionalConfig: map[string]interface{}{ - "hd": "example.com", - }, - }, - }, - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="google-workspaces", - name="Google Workspaces", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - additional_config={ - "hd": "example.com", - }, - ), - ], - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="google-workspaces", - name="Google Workspaces", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - additional_config={ - "hd": "example.com", - }, - ), - ], -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "google-workspaces", - "name": "Google Workspaces", - "clients": [ - { - "clientId": "...", - "clientSecret": "...", - "additionalConfig": { - "hd": "example.com" - } - } - ] - } -}' -``` - - - - - -Create Google Provider - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-google.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-google.mdx deleted file mode 100644 index de0aacb193..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-google.mdx +++ /dev/null @@ -1,155 +0,0 @@ - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "google", - name: "Google", - clients: [{ - clientId: "...", - clientSecret: "..." - }] - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "google", - Name: "Google", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - ClientSecret: "...", - }, - }, - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="google", - name="Google", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="google", - name="Google", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "google", - "name": "Google", - "clients": [ - { - "clientId": "...", - "clientSecret": "..." - } - ] - } -}' -``` - - - - - -Create Google Provider - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-linkedin.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-linkedin.mdx deleted file mode 100644 index eef90550d3..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-linkedin.mdx +++ /dev/null @@ -1,162 +0,0 @@ - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "linkedin", - name: "LinkedIn", - clients: [{ - clientId: "...", - clientSecret: "...", - }] - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "linkedin", - Name: "LinkedIn", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - ClientSecret: "...", - }, - }, - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="linkedin", - name="LinkedIn", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="linkedin", - name="LinkedIn", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "linkedin", - "name": "LinkedIn", - "clients": [ - { - "clientId": "...", - "clientSecret": "..." - } - ] - } -}' -``` - - - - - -Create LinkedIn Provider - - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-okta.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-okta.mdx deleted file mode 100644 index ea3c3d2ac8..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-okta.mdx +++ /dev/null @@ -1,169 +0,0 @@ - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "okta", - name: "Okta", - clients: [{ - clientId: "...", - clientSecret: "...", - }], - oidcDiscoveryEndpoint: "https://dev-.okta.com/.well-known/openid-configuration", - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "okta", - Name: "Okta", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - ClientSecret: "...", - }, - }, - OIDCDiscoveryEndpoint: "https://dev-.okta.com/.well-known/openid-configuration", - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="okta", - name="Okta", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], - oidc_discovery_endpoint="https://dev-.okta.com/.well-known/openid-configuration", - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="okta", - name="Okta", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - ), - ], - oidc_discovery_endpoint="https://dev-.okta.com/.well-known/openid-configuration", -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "okta", - "name": "Okta", - "clients": [ - { - "clientId": "...", - "clientSecret": "..." - } - ], - "oidcDiscoveryEndpoint": "https://dev-.okta.com/.well-known/openid-configuration" - } -}' -``` - - - - - - -Create Okta Provider - - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-saml.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-saml.mdx deleted file mode 100644 index 7bd810501a..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-saml.mdx +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "boxy-saml", - name: "", - clients: [{ - clientId: "...", - clientSecret: "...", - additionalConfig: { - "boxyURL": "", - } - }], - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "boxy-saml", - Name: "", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "...", - ClientSecret: "...", - AdditionalConfig: map[string]interface{}{ - "boxyURL": "", - }, - }, - }, - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="boxy-saml", - name="", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - additional_config={ - "boxyURL": "", - }, - ), - ], - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="boxy-saml", - name="", - clients=[ - ProviderClientConfig( - client_id="...", - client_secret="...", - additional_config={ - "boxyURL": "", - }, - ), - ], -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "boxy-SAML", - "name": "", - "clients": [ - { - "clientId": "...", - "clientSecret": "...", - "additionalConfig": { - "boxyURL": "" - } - } - ] - } -}' -``` - - - - - - -Create SAML Provider - - - - - diff --git a/docs/authentication/social/_blocks/multi-tenant-provider-config-twitter.mdx b/docs/authentication/social/_blocks/multi-tenant-provider-config-twitter.mdx deleted file mode 100644 index b5810d51c2..0000000000 --- a/docs/authentication/social/_blocks/multi-tenant-provider-config-twitter.mdx +++ /dev/null @@ -1,164 +0,0 @@ - - - - - -```tsx -import Multitenancy from "supertokens-node/recipe/multitenancy"; - -async function addThirdPartyToTenant() { - let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { - thirdPartyId: "twitter", - name: "Twitter", - clients: [{ - clientId: "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", - clientSecret: "BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", - }] - }); - - if (resp.createdNew) { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/multitenancy" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" -) - -func main() { - tenantId := "customer1" - - // highlight-start - resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ - ThirdPartyId: "twitter", - Name: "Twitter", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", - ClientSecret: "BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", - }, - }, - }, nil) - // highlight-end - - if err != nil { - // handle error - } - if resp.OK.CreatedNew { - // Provider added to customer1 - } else { - // Existing provider config overwritten for customer1 - } -} -``` - - - - - - - - - -```python -from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -async def some_func(): - tenant_id = "customer1" - result = await create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="twitter", - name="Twitter", - clients=[ - ProviderClientConfig( - client_id="4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", - client_secret="BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", - ), - ], - )) - - if result.status != "OK": - print("handle error") - elif result.created_new: - print("Provider added to customer1") - else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - -```python -from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config -from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig - -tenant_id = "customer1" -result = create_or_update_third_party_config(tenant_id, ProviderConfig( - third_party_id="twitter", - name="Twitter", - clients=[ - ProviderClientConfig( - client_id="4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", - client_secret="BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", - ), - ], -)) - -if result.status != "OK": - print("handle error") -elif result.created_new: - print("Provider added to customer1") -else: - print("Existing provider config overwritten for customer1") -``` - - - - - - - - - - -```bash -curl --location --request PUT '^{coreInfo.uri}//recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "config": { - "thirdPartyId": "twitter", - "name": "Twitter", - "clients": [ - { - "clientId": "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", - "clientSecret": "BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC" - } - ] - } -}' -``` - - - - - - -Create Twitter Provider - - - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-active-directory.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-active-directory.mdx deleted file mode 100644 index 3f981a5fa8..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-active-directory.mdx +++ /dev/null @@ -1,118 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "active-directory", - clients: [{ - clientId: "TODO", - clientSecret: "TODO" - }], - oidcDiscoveryEndpoint: "https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "active-directory", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "TODO:", - ClientSecret: "TODO:", - }, - }, - OIDCDiscoveryEndpoint: "https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="active-directory", - clients=[ - ProviderClientConfig( - client_id="TODO:", - client_secret="TODO:", - ), - ], - oidc_discovery_endpoint="https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-apple.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-apple.mdx deleted file mode 100644 index af8bb5441f..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-apple.mdx +++ /dev/null @@ -1,127 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "apple", - clients: [{ - clientId: "4398792-io.supertokens.example.service", - additionalConfig: { - "keyId": "7M48Y4RYDL", - "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", - "teamId": "YWQCXGJRJL", - }, - }] - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "apple", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "4398792-io.supertokens.example.service", - AdditionalConfig: map[string]interface{}{ - "keyId": "7M48Y4RYDL", - "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", - "teamId": "YWQCXGJRJL", - }, - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="apple", - clients=[ - ProviderClientConfig( - client_id="4398792-io.supertokens.example.service", - additional_config={ - "keyId": "7M48Y4RYDL", - "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", - "teamId": "YWQCXGJRJL", - }, - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-bitbucket.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-bitbucket.mdx deleted file mode 100644 index a5b46ae719..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-bitbucket.mdx +++ /dev/null @@ -1,111 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "google", - clients: [{ - clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - clientSecret: "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", - }] - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "google", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - ClientSecret: "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", - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="google", - clients=[ - ProviderClientConfig( - client_id="1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - client_secret="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", - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-discord.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-discord.mdx deleted file mode 100644 index 4c1ed47157..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-discord.mdx +++ /dev/null @@ -1,115 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "discord", - clients: [{ - clientId: "TODO", - clientSecret: "TODO" - }] - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "discord", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "TODO:", - ClientSecret: "TODO:", - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="discord", - clients=[ - ProviderClientConfig( - client_id="TODO:", - client_secret="TODO:", - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-facebook.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-facebook.mdx deleted file mode 100644 index 1386dabbe6..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-facebook.mdx +++ /dev/null @@ -1,115 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "facebook", - clients: [{ - clientId: "TODO", - clientSecret: "TODO" - }] - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "facebook", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "TODO:", - ClientSecret: "TODO:", - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="facebook", - clients=[ - ProviderClientConfig( - client_id="TODO:", - client_secret="TODO:", - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-github.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-github.mdx deleted file mode 100644 index 79a77f0734..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-github.mdx +++ /dev/null @@ -1,115 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "github", - clients: [{ - clientId: "TODO", - clientSecret: "TODO" - }] - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "github", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "TODO:", - ClientSecret: "TODO:", - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="github", - clients=[ - ProviderClientConfig( - client_id="TODO:", - client_secret="TODO:", - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-gitlab.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-gitlab.mdx deleted file mode 100644 index 3ed993fd4c..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-gitlab.mdx +++ /dev/null @@ -1,118 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "gitlab", - clients: [{ - clientId: "TODO", - clientSecret: "TODO" - }], - oidcDiscoveryEndpoint: "https://gitlab.example.com/.well-known/openid-configuration", - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "gitlab", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "TODO:", - ClientSecret: "TODO:", - }, - }, - OIDCDiscoveryEndpoint: "https://gitlab.example.com/.well-known/openid-configuration", - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="gitlab", - clients=[ - ProviderClientConfig( - client_id="TODO:", - client_secret="TODO:", - ), - ], - oidc_discovery_endpoint="https://gitlab.example.com/.well-known/openid-configuration" - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-google-workspaces.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-google-workspaces.mdx deleted file mode 100644 index 11c5e52333..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-google-workspaces.mdx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "google-workspaces", - clients: [{ - clientId: "TODO", - clientSecret: "TODO", - additionalConfig: { - "hd": "example.com" - } - }] - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "google-workspaces", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "TODO:", - ClientSecret: "TODO:", - AdditionalConfig: map[string]interface{}{ - "hd": "example.com", - }, - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="google-workspaces", - clients=[ - ProviderClientConfig( - client_id="TODO:", - client_secret="TODO:", - additional_config={ - "hd": "example.com", - }, - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-google.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-google.mdx deleted file mode 100644 index a5b46ae719..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-google.mdx +++ /dev/null @@ -1,111 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "google", - clients: [{ - clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - clientSecret: "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", - }] - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "google", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - ClientSecret: "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", - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="google", - clients=[ - ProviderClientConfig( - client_id="1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com", - client_secret="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", - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-linkedin.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-linkedin.mdx deleted file mode 100644 index af9d80c33a..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-linkedin.mdx +++ /dev/null @@ -1,115 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "linkedin", - clients: [{ - clientId: "TODO", - clientSecret: "TODO" - }] - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "linkedin", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "TODO:", - ClientSecret: "TODO:", - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="linkedin", - clients=[ - ProviderClientConfig( - client_id="TODO:", - client_secret="TODO:", - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-okta.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-okta.mdx deleted file mode 100644 index a72e9f329d..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-okta.mdx +++ /dev/null @@ -1,119 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "okta", - clients: [{ - clientId: "TODO", - clientSecret: "TODO" - }], - oidcDiscoveryEndpoint: "https://dev-.okta.com/.well-known/openid-configuration", - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "okta", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "TODO:", - ClientSecret: "TODO:", - }, - }, - OIDCDiscoveryEndpoint: "https://dev-.okta.com/.well-known/openid-configuration", - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="okta", - clients=[ - ProviderClientConfig( - client_id="TODO:", - client_secret="TODO:", - ), - ], - oidc_discovery_endpoint="https://dev-.okta.com/.well-known/openid-configuration", - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-saml.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-saml.mdx deleted file mode 100644 index f14c4732d3..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-saml.mdx +++ /dev/null @@ -1,126 +0,0 @@ - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "boxy-saml", - name: "", // Replace with the correct provider name - clients: [{ - clientId: "TODO", - clientSecret: "TODO", - additionalConfig: { - "boxyURL": "" - } - }], - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "boxy-saml", - Name: "", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "TODO:", - ClientSecret: "TODO:", - AdditionalConfig: map[string]interface{}{ - "boxyURL": "", - }, - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="boxy-saml", - name="", - clients=[ - ProviderClientConfig( - client_id="TODO:", - client_secret="TODO:", - additional_config={ - "boxyURL": "", - }, - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - diff --git a/docs/authentication/social/_blocks/single-tenant-provider-config-twitter.mdx b/docs/authentication/social/_blocks/single-tenant-provider-config-twitter.mdx deleted file mode 100644 index 848db81f66..0000000000 --- a/docs/authentication/social/_blocks/single-tenant-provider-config-twitter.mdx +++ /dev/null @@ -1,115 +0,0 @@ - - - - - -```tsx -import SuperTokens from "supertokens-node"; -import ThirdParty from "supertokens-node/recipe/thirdparty"; - -SuperTokens.init({ - appInfo: { - apiDomain: "...", - appName: "...", - websiteDomain: "..." - }, - supertokens: { - connectionURI: "...", - }, - recipeList: [ - ThirdParty.init({ - signInAndUpFeature: { - providers: [ - { - config: { - thirdPartyId: "twitter", - clients: [{ - clientId: "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", - clientSecret: "BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC" - }] - } - } - ] - } - }), // initializes signin / sign up features - ] -}); -``` - - - - - -```go -import ( - "github.com/supertokens/supertokens-golang/recipe/thirdparty" - "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" - "github.com/supertokens/supertokens-golang/supertokens" -) - -func main() { - supertokens.Init(supertokens.TypeInput{ - RecipeList: []supertokens.Recipe{ - thirdparty.Init(&tpmodels.TypeInput{ - SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ - Providers: []tpmodels.ProviderInput{ - { - Config: tpmodels.ProviderConfig{ - ThirdPartyId: "twitter", - Clients: []tpmodels.ProviderClientConfig{ - { - ClientID: "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", - ClientSecret: "BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", - }, - }, - }, - }, - }, - }, - }), - }, - }) -} -``` - - - - - - -```python -from supertokens_python import init, InputAppInfo -from supertokens_python.recipe import thirdparty -from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature - -init( - app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore - recipe_list=[ - thirdparty.init( - - # highlight-start - sign_in_and_up_feature=SignInAndUpFeature( - providers=[ - ProviderInput( - config=ProviderConfig( - third_party_id="twitter", - clients=[ - ProviderClientConfig( - client_id="4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", - client_secret="BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", - ), - ], - ), - ), - ] - ) - # highlight-end - ) - ] -) -``` - - - - diff --git a/docs/authentication/social/_category_.json b/docs/authentication/social/_category_.json deleted file mode 100644 index cc98313a23..0000000000 --- a/docs/authentication/social/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Social Login", - "position": 3 -} diff --git a/docs/authentication/social/add-multiple-clients-for-the-same-provider.mdx b/docs/authentication/social/add-multiple-clients-for-the-same-provider.mdx index 58d42deda6..8745457f7f 100644 --- a/docs/authentication/social/add-multiple-clients-for-the-same-provider.mdx +++ b/docs/authentication/social/add-multiple-clients-for-the-same-provider.mdx @@ -1,18 +1,10 @@ --- title: Add multiple clients for the same provider -hide_title: true -sidebar_position: 6 -description: >- - Configure multiple client IDs for social login providers in web and mobile - applications. -page_type: guide -recipe: thirdparty -category: thirdparty +description: Configure multiple client IDs for social login providers in web and mobile applications. +sidebar: + order: 6 --- - -# Add multiple clients for the same provider - ## Overview If you use a third-party login method for your web and mobile app, then you might need to setup different Client ID/Secret for the same provider on the backend. @@ -21,8 +13,8 @@ For example, in case of Apple login, Apple gives you different client IDs for iO ## Before you start -This guide assumes that you have already implemented the [EmailPassword recipe](/docs/authentication/email-password/introduction) and have a working application integrated with **SuperTokens**. -If you have not, please check the [Quickstart Guide](/docs/quickstart/introduction). +This guide assumes that you have already implemented the [EmailPassword recipe](/authentication/email-password/introduction) and have a working application integrated with **SuperTokens**. +If you have not, please check the [Quickstart Guide](/quickstart/introduction). ## Steps @@ -32,9 +24,9 @@ Add more clients to the Apple.init on the backend. Each client would need to be uniquely identified, and you achieve this using the `clientType` string. For example, you can add one `clientType` for `web-and-android` and one for `ios`. - + - + ```tsx import { ProviderInput } from "supertokens-node/recipe/thirdparty/types"; @@ -65,8 +57,8 @@ let providers: ProviderInput[] = [ ] ``` - - + + ```go import ( @@ -102,8 +94,8 @@ func main() { } ``` - - + + ```python from supertokens_python.recipe.thirdparty.provider import ProviderInput, ProviderConfig, ProviderClientConfig @@ -137,108 +129,103 @@ providers = [ ] ``` - - + + ### 2. Update the frontend configuration Use the right `clientType` as shown below: - + - + - - + - + - + We pass in the `clientType` during the init call. - + -```tsx +```tsx {9} import SuperTokens from 'supertokens-web-js'; SuperTokens.init({ appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", appName: "...", }, - // highlight-next-line clientType: "web-and-android", recipeList: [/*...*/], }); ``` - + If you are using the pre-built UI SDK (SuperTokens-auth-react) as well, you can provide the `clientType` configuration to it as follows: - + -```tsx +```tsx {10} import SuperTokens from 'supertokens-auth-react'; SuperTokens.init({ appInfo: { - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", appName: "...", }, - // highlight-next-line clientType: "web-and-android", recipeList: [/*...*/], }); ``` - + - + - + We pass in the `clientType` during the init call. - + -```tsx -import supertokens from "supertokens-web-js-script"; +```tsx {7} supertokens.init({ appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", appName: "...", }, - // highlight-next-line clientType: "web-and-android", recipeList: [/*...*/], }); ``` - - + + - + - + When making calls to the APIs from your mobile app, the request body also takes a `clientType` prop as seen in the above API calls. - - + + ## See also - - - - - + + + + + diff --git a/docs/authentication/social/built-in-providers-config.mdx b/docs/authentication/social/built-in-providers-config.mdx new file mode 100644 index 0000000000..ef12d9c7a4 --- /dev/null +++ b/docs/authentication/social/built-in-providers-config.mdx @@ -0,0 +1,3399 @@ +--- +title: Built-in providers +description: Configure single or multi-tenant login/SSO with built-in provider settings. +sidebar: + order: 3 +--- + +This page shows a full list of all the built-in providers exposed by **SuperTokens**. + + + + + +## Google + +To generate your client ID and secret follow the [official documentation](https://support.google.com/cloud/answer/6158849?hl=en). +Set the authorisation callback URL to `/auth/callback/google` + + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "google", + clients: [{ + clientId: "", + clientSecret: "", + }] + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "google", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "", + ClientSecret: "", + }, + }, + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="google", + clients=[ + ProviderClientConfig( + client_id="", + client_secret="", + ), + ], + ), + ), + ] + ) + ) + ] +) +``` + + + + +## Google workspaces + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "google-workspaces", + clients: [{ + clientId: "TODO", + clientSecret: "TODO", + additionalConfig: { + "hd": "example.com" + } + }] + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "google-workspaces", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "TODO:", + ClientSecret: "TODO:", + AdditionalConfig: map[string]interface{}{ + "hd": "example.com", + }, + }, + }, + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="google-workspaces", + clients=[ + ProviderClientConfig( + client_id="TODO:", + client_secret="TODO:", + additional_config={ + "hd": "example.com", + }, + ), + ], + ), + ), + ] + ) + ) + ] +) +``` + + + + +## Apple + +To generate your client ID and secret follow [this article](https://medium.com/identity-beyond-borders/how-to-configure-sign-in-with-apple-77c61e336003). +Set the authorisation callback URL to `/auth/callback/apple`. +Note that Apple doesn't allow `localhost` in the URL. +If you are in `dev` mode, you can use the `dev` keys provided above. + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "apple", + clients: [{ + clientId: "4398792-io.supertokens.example.service", + additionalConfig: { + "keyId": "7M48Y4RYDL", + "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", + "teamId": "YWQCXGJRJL", + }, + }] + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "apple", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "4398792-io.supertokens.example.service", + AdditionalConfig: map[string]interface{}{ + "keyId": "7M48Y4RYDL", + "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", + "teamId": "YWQCXGJRJL", + }, + }, + }, + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="apple", + clients=[ + ProviderClientConfig( + client_id="4398792-io.supertokens.example.service", + additional_config={ + "keyId": "7M48Y4RYDL", + "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", + "teamId": "YWQCXGJRJL", + }, + ), + ], + ), + ), + ] + ) + ) + ] +) +``` + + + + + +## Discord + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "discord", + clients: [{ + clientId: "TODO", + clientSecret: "TODO" + }] + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "discord", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "TODO:", + ClientSecret: "TODO:", + }, + }, + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="discord", + clients=[ + ProviderClientConfig( + client_id="TODO:", + client_secret="TODO:", + ), + ], + ), + ), + ] + ) + ) + ] +) +``` + + + + + +## Facebook + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "facebook", + clients: [{ + clientId: "TODO", + clientSecret: "TODO" + }] + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "facebook", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "TODO:", + ClientSecret: "TODO:", + }, + }, + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="facebook", + clients=[ + ProviderClientConfig( + client_id="TODO:", + client_secret="TODO:", + ), + ], + ), + ), + ] + ) + ) + ] +) +``` + + + + + +## GitHub + +To generate your client ID and secret follow the [official documentation](https://docs.github.com/en/developers/apps/creating-an-oauth-app). +Set the authorisation callback URL to `/auth/callback/github` + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "github", + clients: [{ + clientId: "TODO", + clientSecret: "TODO" + }] + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "github", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "TODO:", + ClientSecret: "TODO:", + }, + }, + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="github", + clients=[ + ProviderClientConfig( + client_id="TODO:", + client_secret="TODO:", + ), + ], + ), + ), + ] + ) + ) + ] +) +``` + + + + + +## GitLab + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "gitlab", + clients: [{ + clientId: "TODO", + clientSecret: "TODO" + }], + oidcDiscoveryEndpoint: "https://gitlab.example.com/.well-known/openid-configuration", + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "gitlab", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "TODO:", + ClientSecret: "TODO:", + }, + }, + OIDCDiscoveryEndpoint: "https://gitlab.example.com/.well-known/openid-configuration", + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="gitlab", + clients=[ + ProviderClientConfig( + client_id="TODO:", + client_secret="TODO:", + ), + ], + oidc_discovery_endpoint="https://gitlab.example.com/.well-known/openid-configuration" + ), + ), + ] + ) + ) + ] +) +``` + + + + + +## Twitter + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "twitter", + clients: [{ + clientId: "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", + clientSecret: "BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC" + }] + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "twitter", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", + ClientSecret: "BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", + }, + }, + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="twitter", + clients=[ + ProviderClientConfig( + client_id="4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", + client_secret="BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", + ), + ], + ), + ), + ] + ) + ) + ] +) +``` + + + + + +## LinkedIn + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "linkedin", + clients: [{ + clientId: "TODO", + clientSecret: "TODO" + }] + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "linkedin", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "TODO:", + ClientSecret: "TODO:", + }, + }, + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="linkedin", + clients=[ + ProviderClientConfig( + client_id="TODO:", + client_secret="TODO:", + ), + ], + ), + ), + ] + ) + ) + ] +) +``` + + + + + +## Okta + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "okta", + clients: [{ + clientId: "TODO", + clientSecret: "TODO" + }], + oidcDiscoveryEndpoint: "https://dev-.okta.com/.well-known/openid-configuration", + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "okta", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "TODO:", + ClientSecret: "TODO:", + }, + }, + OIDCDiscoveryEndpoint: "https://dev-.okta.com/.well-known/openid-configuration", + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="okta", + clients=[ + ProviderClientConfig( + client_id="TODO:", + client_secret="TODO:", + ), + ], + oidc_discovery_endpoint="https://dev-.okta.com/.well-known/openid-configuration", + ), + ), + ] + ) + ) + ] +) +``` + + + + + +## SAML + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "boxy-saml", + name: "", // Replace with the correct provider name + clients: [{ + clientId: "TODO", + clientSecret: "TODO", + additionalConfig: { + "boxyURL": "" + } + }], + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "boxy-saml", + Name: "", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "TODO:", + ClientSecret: "TODO:", + AdditionalConfig: map[string]interface{}{ + "boxyURL": "", + }, + }, + }, + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="boxy-saml", + name="", + clients=[ + ProviderClientConfig( + client_id="TODO:", + client_secret="TODO:", + additional_config={ + "boxyURL": "", + }, + ), + ], + ), + ), + ] + ) + ) + ] +) +``` + + + + + + +## Active Directory + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + supertokens: { + connectionURI: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "active-directory", + clients: [{ + clientId: "TODO", + clientSecret: "TODO" + }], + oidcDiscoveryEndpoint: "https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", + } + } + ] + } + }), // initializes signin / sign up features + ] +}); +``` + + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "active-directory", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "TODO:", + ClientSecret: "TODO:", + }, + }, + OIDCDiscoveryEndpoint: "https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="active-directory", + clients=[ + ProviderClientConfig( + client_id="TODO:", + client_secret="TODO:", + ), + ], + oidc_discovery_endpoint="https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", + ), + ), + ] + ) + ) + ] +) +``` + + + + + + + + + + +Call the following function / API to add the third party provider to a specific tenant. + +## Google + +To generate your client ID and secret follow the [official documentation](https://support.google.com/cloud/answer/6158849?hl=en) + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "google", + name: "Google", + clients: [{ + clientId: "...", + clientSecret: "..." + }] + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + +```go {9,10,11,12,13,14,15,16,17,18} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "google", + Name: "Google", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + }, + }, + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="google", + name="Google", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="google", + name="Google", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + +```bash +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "google", + "name": "Google", + "clients": [ + { + "clientId": "...", + "clientSecret": "..." + } + ] + } +}' +``` + + + + + +Create Google Provider + + + + + +## Google workspaces + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "google-workspaces", + name: "Google Workspaces", + clients: [{ + clientId: "...", + clientSecret: "...", + additionalConfig: { + "hd": "example.com", + } + }] + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + +```go {9,10,11,12,13,14,15,16,17,18,19,20,21} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "google-workspaces", + Name: "Google Workspaces", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + AdditionalConfig: map[string]interface{}{ + "hd": "example.com", + }, + }, + }, + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="google-workspaces", + name="Google Workspaces", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + additional_config={ + "hd": "example.com", + }, + ), + ], + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="google-workspaces", + name="Google Workspaces", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + additional_config={ + "hd": "example.com", + }, + ), + ], +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + +```bash +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "google-workspaces", + "name": "Google Workspaces", + "clients": [ + { + "clientId": "...", + "clientSecret": "...", + "additionalConfig": { + "hd": "example.com" + } + } + ] + } +}' +``` + + + + + +Create Google Provider + + + + + +## Apple + +To generate your client ID and secret follow [this article](https://medium.com/identity-beyond-borders/how-to-configure-sign-in-with-apple-77c61e336003) +Note that Apple doesn't allow `localhost` in the URL. +If you are in `dev` mode, you can use the `dev` keys provided above. + +Call the following function / API to add the third party provider to a specific tenant. + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "apple", + name: "Apple", + clients: [{ + clientId: "...", + additionalConfig: { + "keyId": "...", + "privateKey": "...", + "teamId": "...", + } + }] + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18,19,20,21,22} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "apple", + Name: "Apple", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + AdditionalConfig: map[string]interface{}{ + "keyId": "...", + "privateKey": "...", + "teamId": "...", + }, + }, + }, + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="apple", + name="Apple", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + additional_config={ + "keyId": "...", + "privateKey": "...", + "teamId": "...", + }, + ), + ], + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="apple", + name="Apple", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + additional_config={ + "keyId": "...", + "privateKey": "...", + "teamId": "...", + }, + ), + ], +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + +```bash +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "apple", + "name": "Apple", + "clients": [ + { + "clientId": "...", + "additionalConfig": { + "keyId": "...", + "privateKey": "...", + "teamId": "..." + } + } + ] + } +}' +``` + + + + + +Create Apple Provider + + + + + +## Discord + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "discord", + name: "Discord", + clients: [{ + clientId: "...", + clientSecret: "...", + }] + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "discord", + Name: "Discord", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + }, + }, + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="discord", + name="Discord", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="discord", + name="Discord", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + +```bash +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "discord", + "name": "Discord", + "clients": [ + { + "clientId": "...", + "clientSecret": "..." + } + ] + } +}' +``` + + + + + +Create Discord Provider + + + + + + +## Facebook + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "facebook", + name: "Facebook", + clients: [{ + clientId: "...", + clientSecret: "...", + }] + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "facebook", + Name: "Facebook", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + }, + }, + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="facebook", + name="Facebook", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="facebook", + name="Facebook", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + +```bash +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "facebook", + "name": "Facebook", + "clients": [ + { + "clientId": "...", + "clientSecret": "..." + } + ] + } +}' +``` + + + + + +Create Facebook Provider + + + + + + +## GitHub + +To generate your client ID and secret follow the [official documentation](https://docs.github.com/en/developers/apps/creating-an-oauth-app) + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "github", + name: "GitHub", + clients: [{ + clientId: "...", + clientSecret: "...", + }] + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "github", + Name: "GitHub", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + }, + }, + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="github", + name="GitHub", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="github", + name="GitHub", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + + +```bash +curl --location --request PUT '/recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "github", + "name": "GitHub", + "clients": [ + { + "clientId": "...", + "clientSecret": "..." + } + ] + } +}' +``` + + + + + + +Create GitHub Provider + + + + + + +## GitLab + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "gitlab", + name: "GitLab", + clients: [{ + clientId: "...", + clientSecret: "...", + }], + oidcDiscoveryEndpoint: "https://gitlab.example.com/.well-known/openid-configuration", + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18,19} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "gitlab", + Name: "GitLab", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + }, + }, + OIDCDiscoveryEndpoint: "https://gitlab.example.com/.well-known/openid-configuration", + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="gitlab", + name="Gitlab", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + oidc_discovery_endpoint="https://gitlab.example.com/.well-known/openid-configuration" + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="gitlab", + name="Gitlab", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + oidc_discovery_endpoint="https://gitlab.example.com/.well-known/openid-configuration" +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + +```bash +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "gitlab", + "name": "GitLab", + "clients": [ + { + "clientId": "...", + "clientSecret": "..." + } + ], + "oidcDiscoveryEndpoint": "https://gitlab.example.com/.well-known/openid-configuration" + } +}' +``` + + + + + + +Create GitLab Provider + + + + + + +## Twitter + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "twitter", + name: "Twitter", + clients: [{ + clientId: "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", + clientSecret: "BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", + }] + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "twitter", + Name: "Twitter", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", + ClientSecret: "BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", + }, + }, + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="twitter", + name="Twitter", + clients=[ + ProviderClientConfig( + client_id="4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", + client_secret="BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", + ), + ], + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="twitter", + name="Twitter", + clients=[ + ProviderClientConfig( + client_id="4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", + client_secret="BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC", + ), + ], +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + + +```bash +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "twitter", + "name": "Twitter", + "clients": [ + { + "clientId": "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ", + "clientSecret": "BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC" + } + ] + } +}' +``` + + + + + + +Create Twitter Provider + + + + + + +## LinkedIn + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "linkedin", + name: "LinkedIn", + clients: [{ + clientId: "...", + clientSecret: "...", + }] + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "linkedin", + Name: "LinkedIn", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + }, + }, + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="linkedin", + name="LinkedIn", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="linkedin", + name="LinkedIn", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + +```bash +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "linkedin", + "name": "LinkedIn", + "clients": [ + { + "clientId": "...", + "clientSecret": "..." + } + ] + } +}' +``` + + + + + +Create LinkedIn Provider + + + + + + +## Okta + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "okta", + name: "Okta", + clients: [{ + clientId: "...", + clientSecret: "...", + }], + oidcDiscoveryEndpoint: "https://dev-.okta.com/.well-known/openid-configuration", + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18,19} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "okta", + Name: "Okta", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + }, + }, + OIDCDiscoveryEndpoint: "https://dev-.okta.com/.well-known/openid-configuration", + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="okta", + name="Okta", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + oidc_discovery_endpoint="https://dev-.okta.com/.well-known/openid-configuration", + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="okta", + name="Okta", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + oidc_discovery_endpoint="https://dev-.okta.com/.well-known/openid-configuration", +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + + +```bash +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "okta", + "name": "Okta", + "clients": [ + { + "clientId": "...", + "clientSecret": "..." + } + ], + "oidcDiscoveryEndpoint": "https://dev-.okta.com/.well-known/openid-configuration" + } +}' +``` + + + + + + +Create Okta Provider + + + + + + +## SAML + + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "boxy-saml", + name: "", + clients: [{ + clientId: "...", + clientSecret: "...", + additionalConfig: { + "boxyURL": "", + } + }], + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18,19,20,21} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "boxy-saml", + Name: "", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + AdditionalConfig: map[string]interface{}{ + "boxyURL": "", + }, + }, + }, + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="boxy-saml", + name="", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + additional_config={ + "boxyURL": "", + }, + ), + ], + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + +```python +from supertokens_python.recipe.multitenancy.syncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +tenant_id = "customer1" +result = create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="boxy-saml", + name="", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + additional_config={ + "boxyURL": "", + }, + ), + ], +)) + +if result.status != "OK": + print("handle error") +elif result.created_new: + print("Provider added to customer1") +else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + + +```bash +curl --location --request PUT '//recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "config": { + "thirdPartyId": "boxy-SAML", + "name": "", + "clients": [ + { + "clientId": "...", + "clientSecret": "...", + "additionalConfig": { + "boxyURL": "" + } + } + ] + } +}' +``` + + + + + + +Create SAML Provider + + + + + + +## Active Directory + + + + +```tsx +import Multitenancy from "supertokens-node/recipe/multitenancy"; + +async function addThirdPartyToTenant() { + let resp = await Multitenancy.createOrUpdateThirdPartyConfig("customer1", { + thirdPartyId: "active-directory", + name: "Active Directory", + clients: [{ + clientId: "...", + clientSecret: "...", + }], + oidcDiscoveryEndpoint: "https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", + }); + + if (resp.createdNew) { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + +```go {9,10,11,12,13,14,15,16,17,18,19} +import ( + "github.com/supertokens/supertokens-golang/recipe/multitenancy" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + tenantId := "customer1" + + resp, err := multitenancy.CreateOrUpdateThirdPartyConfig(tenantId, tpmodels.ProviderConfig{ + ThirdPartyId: "active-directory", + Name: "Active Directory", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "...", + ClientSecret: "...", + }, + }, + OIDCDiscoveryEndpoint: "https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", + }, nil) + + if err != nil { + // handle error + } + if resp.OK.CreatedNew { + // Provider added to customer1 + } else { + // Existing provider config overwritten for customer1 + } +} +``` + + + + + + +```python +from supertokens_python.recipe.multitenancy.asyncio import create_or_update_third_party_config +from supertokens_python.recipe.thirdparty.provider import ProviderConfig, ProviderClientConfig + +async def some_func(): + tenant_id = "customer1" + result = await create_or_update_third_party_config(tenant_id, ProviderConfig( + third_party_id="active-directory", + name="Active Directoy", + clients=[ + ProviderClientConfig( + client_id="...", + client_secret="...", + ), + ], + oidc_discovery_endpoint="https://login.microsoftonline.com//v2.0/.well-known/openid-configuration", + )) + + if result.status != "OK": + print("handle error") + elif result.created_new: + print("Provider added to customer1") + else: + print("Existing provider config overwritten for customer1") +``` + + + + + + + + + +--- + +## See also + + + + + + + diff --git a/docs/authentication/social/built-in-providers.mdx b/docs/authentication/social/built-in-providers.mdx deleted file mode 100644 index 36e1cc93e9..0000000000 --- a/docs/authentication/social/built-in-providers.mdx +++ /dev/null @@ -1,191 +0,0 @@ ---- -id: built-in-providers-config -title: Built-in providers -hide_title: true -sidebar_position: 3 -description: Configure single or multi-tenant login/SSO with built-in provider settings. -page_type: guide -recipe: thirdparty -category: thirdparty ---- - -import SingleTenantProviderConfigGoogle from "./_blocks/single-tenant-provider-config-google.mdx"; -import SingleTenantProviderConfigGoogleWorkspaces from "./_blocks/single-tenant-provider-config-google-workspaces.mdx"; -import SingleTenantProviderConfigApple from "./_blocks/single-tenant-provider-config-apple.mdx"; -import SingleTenantProviderConfigDiscord from "./_blocks/single-tenant-provider-config-discord.mdx"; -import SingleTenantProviderConfigFacebook from "./_blocks/single-tenant-provider-config-facebook.mdx"; -import SingleTenantProviderConfigLinkedIn from "./_blocks/single-tenant-provider-config-linkedin.mdx"; -import SingleTenantProviderConfigOkta from "./_blocks/single-tenant-provider-config-okta.mdx"; -import SingleTenantProviderConfigGithub from "./_blocks/single-tenant-provider-config-github.mdx"; -import SingleTenantProviderConfigTwitter from "./_blocks/single-tenant-provider-config-twitter.mdx"; -import SingleTenantProviderConfigGitlab from "./_blocks/single-tenant-provider-config-gitlab.mdx"; -import SingleTenantProviderConfigSaml from "./_blocks/single-tenant-provider-config-saml.mdx"; -import SingleTenantProviderConfigActiveDirectory from "./_blocks/single-tenant-provider-config-active-directory.mdx"; -import MultiTenantProviderConfigGoogle from "./_blocks/multi-tenant-provider-config-google.mdx"; -import MultiTenantProviderConfigGoogleWorkspaces from "./_blocks/multi-tenant-provider-config-google-workspaces.mdx"; -import MultiTenantProviderConfigApple from "./_blocks/multi-tenant-provider-config-apple.mdx"; -import MultiTenantProviderConfigDiscord from "./_blocks/multi-tenant-provider-config-discord.mdx"; -import MultiTenantProviderConfigFacebook from "./_blocks/multi-tenant-provider-config-facebook.mdx"; -import MultiTenantProviderConfigLinkedIn from "./_blocks/multi-tenant-provider-config-linkedin.mdx"; -import MultiTenantProviderConfigOkta from "./_blocks/multi-tenant-provider-config-okta.mdx"; -import MultiTenantProviderConfigGithub from "./_blocks/multi-tenant-provider-config-github.mdx"; -import MultiTenantProviderConfigTwitter from "./_blocks/multi-tenant-provider-config-twitter.mdx"; -import MultiTenantProviderConfigGitlab from "./_blocks/multi-tenant-provider-config-gitlab.mdx"; -import MultiTenantProviderConfigSaml from "./_blocks/multi-tenant-provider-config-saml.mdx"; -import MultiTenantProviderConfigActiveDirectory from "./_blocks/multi-tenant-provider-config-active-directory.mdx"; - - - - -# Built-in providers - -This page shows a full list of all the built-in providers exposed by **SuperTokens**. - - - - - -## Google - -To generate your client ID and secret follow the [official documentation](https://support.google.com/cloud/answer/6158849?hl=en). -Set the authorisation callback URL to `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/callback/google` - - - -## Google workspaces - - - -## Apple - -To generate your client ID and secret follow [this article](https://medium.com/identity-beyond-borders/how-to-configure-sign-in-with-apple-77c61e336003). -Set the authorisation callback URL to `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/callback/apple`. -Note that Apple doesn't allow `localhost` in the URL. -If you are in `dev` mode, you can use the `dev` keys provided above. - - - -## Discord - - - -## Facebook - - - -## GitHub - -To generate your client ID and secret follow the [official documentation](https://docs.github.com/en/developers/apps/creating-an-oauth-app). -Set the authorisation callback URL to `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/callback/github` - - - -## GitLab - - - -## Twitter - - - -## LinkedIn - - - -## Okta - - - -## SAML - - - - -## Active Directory - - - - - - - - -Call the following function / API to add the third party provider to a specific tenant. - -## Google - -To generate your client ID and secret follow the [official documentation](https://support.google.com/cloud/answer/6158849?hl=en) - - - -## Google workspaces - - - -## Apple - -To generate your client ID and secret follow [this article](https://medium.com/identity-beyond-borders/how-to-configure-sign-in-with-apple-77c61e336003) -Note that Apple doesn't allow `localhost` in the URL. -If you are in `dev` mode, you can use the `dev` keys provided above. - - - -## Discord - - - - -## Facebook - - - - -## GitHub - -To generate your client ID and secret follow the [official documentation](https://docs.github.com/en/developers/apps/creating-an-oauth-app) - - - - -## GitLab - - - - -## Twitter - - - - -## LinkedIn - - - - -## Okta - - - - -## SAML - - - -## Active Directory - - - - - - - ---- - -## See also - - - - - - - diff --git a/docs/authentication/social/custom-invite-flow.mdx b/docs/authentication/social/custom-invite-flow.mdx index abf6d26cbd..33d48a3ee9 100644 --- a/docs/authentication/social/custom-invite-flow.mdx +++ b/docs/authentication/social/custom-invite-flow.mdx @@ -1,18 +1,10 @@ --- title: Implement a custom invite flow -hide_title: true -sidebar_position: 8 -description: >- - Implement an allow list for third-party sign-ups using the SuperTokens user - metadata recipe. -page_type: guide -recipe: thirdparty -category: thirdparty +description: Implement an allow list for third-party sign-ups using the SuperTokens user metadata recipe. +sidebar: + order: 8 --- - -# Implement a custom invite flow - ## Overview This guide shows you how to disable public sign ups to allow only certain people to access your app. @@ -21,12 +13,12 @@ From a third-party login perspective, you need to maintain an allow list of emai ## Before you start The tutorial assumes that you already have a working application integrated with **SuperTokens**. -If you have not, please check the [Quickstart Guide](/docs/quickstart/introduction). +If you have not, please check the [Quickstart Guide](/quickstart/introduction). ### Prerequisites This guide uses the `UserMetadata` recipe to store the allow list. -You need to [enable it](/docs/post-authentication/user-management/user-metadata) in the SDK initialization step. +You need to [enable it](/post-authentication/user-management/user-metadata) in the SDK initialization step. ## Steps @@ -37,8 +29,8 @@ This may seem like a strange use case of the user metadata recipe provided, but The following code samples show you how to save the allow list in the user metadata. - - + + ```tsx import UserMetadata from "supertokens-node/recipe/usermetadata" @@ -59,8 +51,8 @@ async function isEmailAllowed(email: string) { } ``` - - + + ```go import "github.com/supertokens/supertokens-golang/recipe/usermetadata" @@ -101,8 +93,8 @@ func isEmailAllowed(email string) (bool, error) { } ``` - - + + ```python from typing import List @@ -127,10 +119,10 @@ async def is_email_allowed(email: str): return email in allow_list ``` - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] For a multi tenant setup, you can even store an allow list per tenant. This setup allows limiting sign ups for different emails for different tenants. If doing this, pass in the tenantID to the functions above, which you can obtain from the input to the API overrides shown below. @@ -141,13 +133,12 @@ If doing this, pass in the tenantID to the functions above, which you can obtain Update the backend SDK API function to only allow sign up requests from users that are on the allow list. To do this you need to use the check functions from the previous code snippet. - - + + ```tsx import ThirdParty from "supertokens-node/recipe/thirdparty"; import supertokens from "supertokens-node"; -declare let isEmailAllowed: (email: string) => Promise // REMOVE_FROM_OUTPUT ThirdParty.init({ override: { @@ -194,8 +185,8 @@ ThirdParty.init({ }) ``` - - + + ```go import ( @@ -267,8 +258,8 @@ func main() { } ``` - - + + ```python from typing import Any, Dict, Optional, Union @@ -372,7 +363,7 @@ def override_thirdparty_apis(original_implementation: APIInterface): init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ thirdparty.init( override=thirdparty.InputOverrideConfig( @@ -383,16 +374,15 @@ init( ) ``` - - - + + ## See also - - - - - - + + + + + + diff --git a/docs/authentication/social/custom-providers.mdx b/docs/authentication/social/custom-providers.mdx index 598f4df6c8..ddb1c30214 100644 --- a/docs/authentication/social/custom-providers.mdx +++ b/docs/authentication/social/custom-providers.mdx @@ -1,18 +1,15 @@ --- title: Custom providers -sidebar_position: 4 description: 'Add custom authentication providers to SuperTokens ' -page_type: guide -recipe: thirdparty -category: thirdparty +sidebar: + order: 4 --- - ## Overview -If you can't find a provider in [the built-in list](/docs/authentication/social/built-in-providers-config), you can add your own custom implementation as shown below. +If you can't find a provider in [the built-in list](/authentication/social/built-in-providers-config), you can add your own custom implementation as shown below. -:::info Note +:::info[Note] If you think that SuperTokens should support this provider by default, make sure to let the team know [on GitHub](https://github.com/supertokens/supertokens-node/issues/88). ::: @@ -22,17 +19,17 @@ If you think that SuperTokens should support this provider by default, make sure ### 1. Render the authentication method in the authentication UI - + - + - - + + Include the provider in the `providers` array in the frontend SDK. -```tsx +```tsx {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30} import React from "react"; import SuperTokens from "supertokens-auth-react"; import ThirdParty from "supertokens-auth-react/recipe/thirdparty"; @@ -45,7 +42,6 @@ SuperTokens.init({ recipeList: [ ThirdParty.init({ signInAndUpFeature: { - // highlight-start providers: [ { id: "custom", @@ -64,7 +60,6 @@ SuperTokens.init({ }}>{"Login with " + props.name} } ], - // highlight-end // ... }, // ... @@ -73,47 +68,45 @@ SuperTokens.init({ ] }); ``` - + - + -:::caution -This is impossible for non-react apps at the moment. Please use custom UI instead for the sign in form. +:::warning[This is impossible for non-react apps at the moment. Please use custom UI instead for the sign in form.] ::: - + - + -:::caution -This is impossible for non-react apps at the moment. Please use custom UI instead for the sign in form. +:::warning[This is impossible for non-react apps at the moment. Please use custom UI instead for the sign in form.] ::: - - + + - + - + -You need to build your own UI listing the buttons for each of the social login providers you want your users to use. See [the implementation details page](../../custom-ui/thirdparty-login) for what to do after a user clicks one of the buttons. +You need to build your own UI listing the buttons for each of the social login providers you want your users to use. See [the implementation details page](/authentication/social/initial-setup#2-add-the-login-ui) for what to do after a user clicks one of the buttons. - + ### 2. Configure the credentials - + - + You can define a custom provider in a couple of ways. The simplest method is to provide the configuration for the `AuthorizationEndpoint`, `TokenEndpoint`, and the mapping for how the user's ID and email from the provider's profile information endpoint. This appears below: - + - + -```tsx +```tsx {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40} import SuperTokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty"; @@ -126,7 +119,6 @@ SuperTokens.init({ recipeList: [ ThirdParty.init({ signInAndUpFeature: { - // highlight-start providers: [{ config: { thirdPartyId: "custom", @@ -155,17 +147,16 @@ SuperTokens.init({ } } }] - // highlight-end } }) ] }) ``` - - + + -```go +```go {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45} import ( "github.com/supertokens/supertokens-golang/recipe/thirdparty" "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" @@ -179,7 +170,6 @@ func main() { SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ Providers: []tpmodels.ProviderInput{ { - // highlight-start Config: tpmodels.ProviderConfig{ ThirdPartyId: "custom", Name: "Custom provider", @@ -212,7 +202,6 @@ func main() { }, }, }, - // highlight-end }, }, }, @@ -222,10 +211,10 @@ func main() { } ``` - - + + -```python +```python {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import thirdparty from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature @@ -233,11 +222,10 @@ from supertokens_python.recipe.thirdparty.provider import UserInfoMap, UserField init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ thirdparty.init( - # highlight-start sign_in_and_up_feature=SignInAndUpFeature( providers=[ ProviderInput( @@ -273,19 +261,18 @@ init( ), ] ) - # highlight-end ) ] ) ``` - + - + ```bash -curl --location --request PUT '^{coreInfo.uri}/public/recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request PUT '/public/recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "config": { @@ -317,25 +304,25 @@ curl --location --request PUT '^{coreInfo.uri}/public/recipe/multitenancy/config }' ``` - + - + Select the **public** tenant from the tenant management page and then click on **Add new provider** in the Social/Enterprise Providers section -Social/Enterprise providers +Social/Enterprise providers Select **Add Custom Provider** option -New Provider +New Provider Fill in the details as shown below and click on **Save** -OAuth2 provider +OAuth2 provider - + - + | Configuration Field | Description | Example | |---|---|---| @@ -347,19 +334,19 @@ Fill in the details as shown below and click on **Save** | `TokenEndpoint` | API endpoint for exchanging Authorization Code | Google: `"https://oauth2.googleapis.com/token"` | | `TokenEndpointBodyParams` | Optional configuration to modify request body | Can add, modify, or remove (using null) body params | | `UserInfoEndpoint` | API endpoint for getting user information | Google: `"https://www.googleapis.com/oauth2/v1/userinfo"` | -| `UserInfoMap.FromUserInfoAPI` | Maps provider's JSON response fields to user info | Example mapping:
`userId: "id"`
`email: "email"`
`emailVerified: "email_verified"`
For nested values use: `userId: "user.id"` | +| `UserInfoMap.FromUserInfoAPI` | Maps provider's JSON response fields to user info | Example mapping:
`userId: "id"`
`email: "email"`
`emailVerified: "email_verified"`
For nested values use: `userId: "user.id"` | - - + + If the provider is Open ID Connect (OIDC) compatible, you can provide URL for the `OIDCDiscoverEndpoint` configuration. The backend SDK automatically discovers authorization endpoint, token endpoint and the user info endpoint by querying the `/.well-known/openid-configuration`. Below is an example of how to set the OIDC discovery endpoint: - - + + -```tsx +```tsx {13,14,15,16,17,18,19,20,21,22} import SuperTokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty"; @@ -372,7 +359,6 @@ SuperTokens.init({ recipeList: [ ThirdParty.init({ signInAndUpFeature: { - // highlight-start providers: [{ config: { thirdPartyId: "custom", @@ -382,9 +368,7 @@ SuperTokens.init({ clientSecret: "...", scope: ["profile", "email"] }], - // highlight-start oidcDiscoveryEndpoint: "https://example.com/.well-known/openid-configuration", - // highlight-end authorizationEndpointQueryParams: { "someKey1": "value1", "someKey2": null @@ -398,17 +382,16 @@ SuperTokens.init({ } } }] - // highlight-end } }) ] }) ``` - - + + -```go +```go {24} import ( "github.com/supertokens/supertokens-golang/recipe/thirdparty" "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" @@ -432,9 +415,7 @@ func main() { Scope: []string{"profile", "email"}, }, }, - // highlight-start OIDCDiscoveryEndpoint: "https://example.com/.well-known/openid-configuration", - // highlight-end AuthorizationEndpointQueryParams: map[string]interface{}{ // optional "someKey1": "value1", "someKey2": nil, @@ -460,10 +441,10 @@ func main() { } ``` - - + + -```python +```python {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import thirdparty from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature @@ -471,11 +452,10 @@ from supertokens_python.recipe.thirdparty.provider import UserInfoMap, UserField init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ thirdparty.init( - # highlight-start sign_in_and_up_feature=SignInAndUpFeature( providers=[ ProviderInput( @@ -506,20 +486,19 @@ init( ), ] ) - # highlight-end ) ] ) ``` - + - + ```bash -curl --location --request PUT '^{coreInfo.uri}/public/recipe/multitenancy/config/thirdparty' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request PUT '/public/recipe/multitenancy/config/thirdparty' \ +--header 'api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "config": { @@ -546,31 +525,31 @@ curl --location --request PUT '^{coreInfo.uri}/public/recipe/multitenancy/config }' ``` - + - + Select the **public** tenant from the tenant management page and then click on **Add new provider** in the Social/Enterprise Providers section -Social/Enterprise providers +Social/Enterprise providers Select **Add Custom Provider** option -New Provider +New Provider Fill in the details as shown below and click on **Save** -OAuth2 provider +OAuth2 provider - + - +
- The configuration values are similar to the ones in the "Via OAuth endpoints" method. Please read that section to understand the `thirdPartyId`, `name`, `clients` configuration. - Unlike the "Via OAuth endpoints", you can obtain the user's info from the ID token payload using the configuration specified by you in the `UserInfoMap.FromIdTokenPayload` map. - You can also add the `UserInfoMap.FromUserInfoAPI` map as done in the "Via OAuth endpoints" section. SuperTokens auto merges the user information. - + --- @@ -581,10 +560,10 @@ Sometimes, one of the steps in the providers interaction may not be per a standa For example, the API call made to get the user's profile info makes a `GET` call to the `UserInfoEndpoint` with the user's access token. If your provider requires a different method or requires multiple calls to different endpoints to get the profile info, then you can override the default implementation as shown below: - - + + -```tsx +```tsx {30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51} import SuperTokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty"; @@ -614,7 +593,6 @@ SuperTokens.init({ }, tokenEndpoint: "https://example.com/oauth/token" }, - // highlight-start override: (originalImplementation) => { return { ...originalImplementation, @@ -637,7 +615,6 @@ SuperTokens.init({ } } } - // highlight-end }] } }) @@ -645,10 +622,10 @@ SuperTokens.init({ }) ``` - - + + -```go +```go {31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52} import ( "github.com/supertokens/supertokens-golang/recipe/thirdparty" "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" @@ -679,7 +656,6 @@ func main() { }, TokenEndpoint: "https://example.com/oauth/token", }, - // highlight-start Override: func(originalImplementation *tpmodels.TypeProvider) *tpmodels.TypeProvider { // ... originalImplementation.GetUserInfo = func(oAuthTokens map[string]interface{}, userContext *map[string]interface{}) (tpmodels.TypeUserInfo, error) { @@ -702,7 +678,6 @@ func main() { } return originalImplementation }, - // highlight-end }, }, }, @@ -712,10 +687,10 @@ func main() { } ``` - - + + -```python +```python {35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import thirdparty from supertokens_python.recipe.thirdparty.provider import ProviderClientConfig, ProviderConfig, ProviderInput, Provider @@ -746,11 +721,10 @@ def override_custom_provider(provider: Provider) -> Provider: init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ thirdparty.init( - # highlight-start sign_in_and_up_feature=SignInAndUpFeature( providers=[ ProviderInput( @@ -775,14 +749,13 @@ init( ), ] ) - # highlight-end ) ] ) ``` - - + + The original implementation has 4 functions which can be overridden: @@ -806,11 +779,11 @@ The original implementation has 4 functions which can be overridden: ## See also - - - - - - - - + + + + + + + + diff --git a/docs/authentication/social/hooks-and-overrides.mdx b/docs/authentication/social/hooks-and-overrides.mdx index 6ff84b9cab..d27ab00f34 100644 --- a/docs/authentication/social/hooks-and-overrides.mdx +++ b/docs/authentication/social/hooks-and-overrides.mdx @@ -1,29 +1,20 @@ --- title: Hooks and overrides -hide_title: true -sidebar_position: 5 -description: >- - Customize the authentication flow to trigger events like analytics or database - updates. -page_type: guide -recipe: thirdparty -category: thirdparty +description: Customize the authentication flow to trigger events like analytics or database updates. +sidebar: + order: 5 --- - -# Hooks and overrides - - **SuperTokens** exposes a set of constructs that allow you to trigger different actions during the authentication lifecycle or to even fully customize the logic based on your use case. The following sections describe how you can adjust the `thirdparty` recipe to your needs. -Explore the [references pages](/docs/references) for a more in depth guide on hooks and overrides. +Explore the [references pages](/references) for a more in depth guide on hooks and overrides. ## Frontend hook - + - + This method gets fired, with the `SUCCESS` action, immediately after a successful sign in or sign up. Follow the code snippet to determine if the user is signing up or signing in. @@ -31,12 +22,12 @@ Follow the code snippet to determine if the user is signing up or signing in. With this method you can fire events immediately after a successful sign in. You can use it to send analytics events. - + - + -```tsx +```tsx {13,14,15,16,17,18,19,20,21} import SuperTokens from "supertokens-auth-react"; import ThirdParty from "supertokens-auth-react/recipe/thirdparty"; import Session from "supertokens-auth-react/recipe/session"; @@ -49,7 +40,6 @@ SuperTokens.init({ }, recipeList: [ ThirdParty.init({ - // highlight-start onHandleEvent: async (context) => { if (context.action === "SUCCESS") { if (context.isNewRecipeUser && context.user.loginMethods.length === 1) { @@ -59,7 +49,6 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init() ] @@ -67,16 +56,13 @@ SuperTokens.init({ ``` - + - + -```tsx +```tsx {11,12,13,14,15,16,17,18,19} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIThirdParty from "supertokens-auth-react-script/recipe/thirdparty"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -86,7 +72,6 @@ supertokensUIInit({ }, recipeList: [ supertokensUIThirdParty.init({ - // highlight-start onHandleEvent: async (context) => { if (context.action === "SUCCESS") { if (context.isNewRecipeUser && context.user.loginMethods.length === 1) { @@ -96,7 +81,6 @@ supertokensUIInit({ } } } - // highlight-end }), supertokensUISession.init() ] @@ -104,29 +88,29 @@ supertokensUIInit({ ``` - + - + - + - + -:::caution Not applicable +:::warning[Not applicable] This section is not applicable for custom UI since you are calling the `signInUp` API yourself anyway. You can do anything you want post `signIn` / `signUp` based on the result of the API call. ::: - + ## Backend override Overriding the `signInUp` function allows you to introduce your own logic for the sign in process. Use it to persist different types of data or trigger actions. - - + + -```tsx +```tsx {19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48} import SuperTokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty"; import Session from "supertokens-node/recipe/session"; @@ -145,7 +129,6 @@ SuperTokens.init({ signInAndUpFeature: { providers: [/* ... */] }, - // highlight-start override: { functions: (originalImplementation) => { return { @@ -176,16 +159,15 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init({ /* ... */ }) ] }); ``` - - + + -```go +```go {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54} import ( "fmt" @@ -198,7 +180,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ thirdparty.Init(&tpmodels.TypeInput{ - //highlight-start Override: &tpmodels.OverrideStruct{ Functions: func(originalImplementation tpmodels.RecipeInterface) tpmodels.RecipeInterface { // create a copy of the originalImplementation @@ -241,16 +222,15 @@ func main() { return originalImplementation }, }, - //highlight-end }), }, }) } ``` - - + + -```python +```python {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,81,82,83} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import thirdparty from supertokens_python.recipe.thirdparty.interfaces import ( @@ -262,7 +242,6 @@ from typing import Dict, Any, Optional, Union from supertokens_python.recipe.session.interfaces import SessionContainer -# highlight-start def override_thirdparty_functions( original_implementation: RecipeInterface, ) -> RecipeInterface: @@ -326,37 +305,33 @@ def override_thirdparty_functions( return original_implementation -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ thirdparty.init( - # highlight-start override=thirdparty.InputOverrideConfig( functions=override_thirdparty_functions ), - # highlight-end sign_in_and_up_feature=thirdparty.SignInAndUpFeature(providers=[]), ) ], ) ``` - - + + --- ## See also - - - - - - - - + + + + + + + + diff --git a/docs/authentication/social/initial-setup.mdx b/docs/authentication/social/initial-setup.mdx index d8c7a572da..0e3019105a 100644 --- a/docs/authentication/social/initial-setup.mdx +++ b/docs/authentication/social/initial-setup.mdx @@ -1,24 +1,10 @@ --- title: Initial Setup -hide_title: true -sidebar_position: 2 -description: >- - Authenticate using SuperTokens with ThirdParty Providers, creating a custom or - prebuilt login flow. -page_type: tutorial -recipe: thirdparty -category: thirdparty +description: Authenticate using SuperTokens with ThirdParty Providers, creating a custom or prebuilt login flow. +sidebar: + order: 2 --- -import ReactRouterCallout from "/docs/_blocks/react-router-callout.mdx"; -import FrontendCustomUIMobileAccessTokenFlow from "./_blocks/frontend-custom-ui-mobile-access-token-flow.mdx" -import FrontendCustomUIMobileAuthorizationCodeFlow from "./_blocks/frontend-custom-ui-mobile-authorization-code-flow.mdx" -import FrontendCustomUIWebAuthorizationCodeFlow from "./_blocks/frontend-custom-ui-web-authorization-code-flow.mdx" -import BackendSDKInit from "./_blocks/backend-sdk-init.mdx" -import BackendProviderInit from "./_blocks/backend-providers-init.mdx" - -# Initial setup - ## Overview This page shows you how to authenticate, using **ThirdParty Providers**, with **SuperTokens**. @@ -26,46 +12,44 @@ The tutorial creates a login flow, rendered by either the **Prebuilt UI** compon ## Before you start -:::important +:::note -These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction). +These instructions assume that you already have gone through the main [quickstart guide](/quickstart/introduction). If you have skipped that page please follow the tutorial and return here once you're done. ::: ## Steps - + - + ### 1. Initialize the frontend SDK - - + + #### 1.1 Add the `ThirdParty` recipe in your main configuration file. -```tsx +```tsx {4,17,18,19,20,21,22,23,24,25,26} import React from 'react'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; -// highlight-next-line import ThirdParty, {Github, Google, Facebook, Apple} from "supertokens-auth-react/recipe/thirdparty"; import Session from "supertokens-auth-react/recipe/session"; SuperTokens.init({ appInfo: { // learn more about this on https://supertokens.com/docs/references/frontend-sdks/reference#sdk-configuration - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", }, recipeList: [ -// highlight-start ThirdParty.init({ signInAndUpFeature: { providers: [ @@ -76,23 +60,21 @@ SuperTokens.init({ ] } }), - // highlight-end Session.init() ] }); ``` - #### 1.2 Include the pre-built UI components in your application. In order for the **pre-built UI** to render inside your application, you have to specify which routes show the authentication components. The **React SDK** uses [**React Router**](https://reactrouter.com/en/main) under the hood to achieve this. Based on whether you already use this package or not in your project, there are two different ways of configuring the routes. - - -```tsx + + +```tsx {9,21} import React from 'react'; import { BrowserRouter, @@ -101,7 +83,6 @@ import { Link } from "react-router-dom"; -// highlight-next-line import { ThirdPartyPreBuiltUI } from 'supertokens-auth-react/recipe/thirdparty/prebuiltui'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; @@ -113,8 +94,7 @@ class App extends React.Component { - {/*This renders the login UI on the ^{appInfo.websiteBasePath} route*/} - // highlight-next-line + {/*This renders the login UI on the /auth route*/} {getSuperTokensRoutesForReactRouterDom(reactRouterDom, [ThirdPartyPreBuiltUI])} {/*Your app routes*/} @@ -125,25 +105,56 @@ class App extends React.Component { } ``` - - - - + :::note[If you are using `useRoutes`, `createBrowserRouter` or have routes defined in a different file, you need to adjust the code sample.] +Please see [this issue](https://github.com/supertokens/supertokens-auth-react/issues/581#issuecomment-1246998493) for further details. ```tsx import React from 'react'; + +import { BrowserRouter, useRoutes } from "react-router-dom"; +import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; +import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; +import * as reactRouterDom from "react-router-dom"; + +function AppRoutes() { + const authRoutes = getSuperTokensRoutesForReactRouterDom( + reactRouterDom, + [/* Add your UI recipes here e.g. EmailPasswordPrebuiltUI, PasswordlessPrebuiltUI, ThirdPartyPrebuiltUI */] + ); + + const routes = useRoutes([ + ...authRoutes.map(route => route.props), + // Include the rest of your app routes + ]); + + return routes; +} + +function App() { + return ( + + + + + + ); +} +``` +::: + + + +```tsx {3,8,9,10,11} +import React from 'react'; import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; -// highlight-next-line import { ThirdPartyPreBuiltUI } from 'supertokens-auth-react/recipe/thirdparty/prebuiltui'; import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; class App extends React.Component { render() { - // highlight-start if (canHandleRoute([ThirdPartyPreBuiltUI])) { - // This renders the login UI on the ^{appInfo.websiteBasePath} route + // This renders the login UI on the /auth route return getRoutingComponent([ThirdPartyPreBuiltUI]) } - // highlight-end return ( {/*Your app*/} @@ -152,18 +163,15 @@ class App extends React.Component { } ``` - - + + - - + + Add the `ThirdParty` recipe in your `AuthComponent`. - ```tsx title="/app/auth/auth.component.ts" - import {init as supertokensUIInit} from "supertokens-auth-react-script"; - import supertokensUIThirdParty from "supertokens-auth-react-script/recipe/thirdparty"; - import supertokensUISession from "supertokens-auth-react-script/recipe/session"; + ```tsx title="/app/auth/auth.component.ts" {43,44,45,46,47,48,49,50,51,52} import { Component, OnDestroy, AfterViewInit, Renderer2, Inject } from "@angular/core"; import { DOCUMENT } from "@angular/common"; @@ -179,7 +187,7 @@ Add the `ThirdParty` recipe in your `AuthComponent`. ) { } ngAfterViewInit() { - this.loadScript('^{prebuiltUIVersion}'); + this.loadScript('https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js'); } ngOnDestroy() { @@ -199,14 +207,13 @@ Add the `ThirdParty` recipe in your `AuthComponent`. supertokensUIInit({ appInfo: { // learn more about this on https://supertokens.com/docs/references/frontend-sdks/reference#sdk-configuration - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", }, recipeList: [ -// highlight-start supertokensUIThirdParty.init({ signInAndUpFeature: { providers: [ @@ -217,7 +224,6 @@ Add the `ThirdParty` recipe in your `AuthComponent`. ] } }), -// highlight-end supertokensUISession.init(), ], }); @@ -228,16 +234,13 @@ Add the `ThirdParty` recipe in your `AuthComponent`. ``` - - + + Add the `ThirdParty` recipe in your `AuthView` file. - ```tsx - import {init as supertokensUIInit} from "supertokens-auth-react-script"; - import supertokensUIThirdParty from "supertokens-auth-react-script/recipe/thirdparty"; - import supertokensUISession from "supertokens-auth-react-script/recipe/session"; + ```tsx {21,22,23,24,25,26,27,28,29,30} + ``` You can initialize the SDK. - + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensThirdParty from 'supertokens-web-js-script/recipe/thirdparty'; +```tsx {9} supertokens.init({ appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", appName: "...", }, recipeList: [ supertokensSession.init(), - // highlight-next-line supertokensThirdParty.init(), ], }); ``` - - - + - + - + - + - + + ```tsx import SuperTokens from 'supertokens-react-native'; SuperTokens.init({ - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", }); ``` - + - + Add the `SuperTokens.init` function call at the start of your application. @@ -473,18 +883,17 @@ class MainApplication: Application() { override fun onCreate() { super.onCreate() - SuperTokens.Builder(this, "^{appInfo.apiDomain}") - .apiBasePath("^{appInfo.apiBasePath}") + SuperTokens.Builder(this, "") + .apiBasePath("/auth") .build() } } ``` - - - + + ```swift @@ -496,8 +905,8 @@ fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { do { try SuperTokens.initialize( - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}" + apiDomain: "", + apiBasePath: "/auth" ) } catch SuperTokensError.initError(let message) { // TODO: Handle initialization error @@ -512,29 +921,29 @@ fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; void main() { SuperTokens.init( - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", ); } ``` - + - + - + - + ### 2. Add the login UI @@ -559,87 +968,1406 @@ The frontend obtains the Access Token and then sends it to the backend. SuperTokens then fetches user info using the access token and logs them in. - - - - - - - - - - - - - - - :::info - - This flow is not applicable for web apps. + + + + + #### Redirecting to a social/single sign-on provider - ::: - - - - - - +The first step is to fetch the URL on which the user authenticates. You can do this by querying the backend API exposed by SuperTokens (as shown below). The backend SDK automatically appends the right query params to the URL (like scope, client ID etc). + +After getting the URL, redirect the user there. In the code below, an example of login with Google appears: + + + + + +```tsx +import { getAuthorisationURLWithQueryParamsAndSetState } from "supertokens-web-js/recipe/thirdparty"; + +async function googleSignInClicked() { + try { + const authUrl = await getAuthorisationURLWithQueryParamsAndSetState({ + thirdPartyId: "google", + + // This is where Google should redirect the user back after login or error. + // This URL goes on the Google's dashboard as well. + frontendRedirectURI: "http:///auth/callback/google", + }); + + /* + Example value of authUrl: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&client_id=&state=5a489996a28cafc83ddff&redirect_uri=https%3A%2F%2Fsupertokens.io%2Fdev%2Foauth%2Fredirect-to-app&flowName=GeneralOAuthFlow + */ + + // we redirect the user to google for auth. + window.location.assign(authUrl); + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + +```tsx +async function googleSignInClicked() { + try { + const authUrl = await supertokensThirdParty.getAuthorisationURLWithQueryParamsAndSetState({ + thirdPartyId: "google", + + // This is where Google should redirect the user back after login or error. + // This URL goes on the Google's dashboard as well. + frontendRedirectURI: "http:///auth/callback/google", + }); + + /* + Example value of authUrl: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&client_id=&state=5a489996a28cafc83ddff&redirect_uri=https%3A%2F%2Fsupertokens.io%2Fdev%2Foauth%2Fredirect-to-app&flowName=GeneralOAuthFlow + */ + + // we redirect the user to google for auth. + window.location.assign(authUrl); + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + -### 3. Initialize the backend SDK +#### Handling the auth callback on your frontend - +Once the third party provider redirects your user back to your app, you need to consume the information to sign in the user. This requires you to: +- Setup a route in your app that handles this callback. It's recommended to use something like `http://`<YOUR_WEBSITE_DOMAIN>`/auth/callback/google` (for Google). Regardless of what you make this path, remember to use that same path when calling the `getAuthorisationURLWithQueryParamsAndSetState` function in the first step. -### 4. Add the authentication providers +- On that route, call the following function on page load + + + + +```tsx +import { signInAndUp } from "supertokens-web-js/recipe/thirdparty"; + +async function handleGoogleCallback() { + try { + const response = await signInAndUp(); + + if (response.status === "OK") { + console.log(response.user) + if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { + // sign up successful + } else { + // sign in successful + } + window.location.assign("/home"); + } else if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in / up was not allowed. + window.alert(response.reason) + } else { + // SuperTokens requires that the third party provider + // gives an email for the user. If that's not the case, sign up / in + // will fail. + + // As a hack to solve this, you can override the backend functions to create a fake email for the user. + + window.alert("No email provided by social login. Please use another form of login"); + window.location.assign("/auth"); // redirect back to login page + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + +```tsx +async function handleGoogleCallback() { + try { + const response = await supertokensThirdParty.signInAndUp(); + + if (response.status === "OK") { + console.log(response.user) + if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { + // sign up successful + } else { + // sign in successful + } + window.location.assign("/home"); + } else if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in / up was not allowed. + window.alert(response.reason) + } else { + // SuperTokens requires that the third party provider + // gives an email for the user. If that's not the case, sign up / in + // will fail. + + // As a hack to solve this, you can override the backend functions to create a fake email for the user. + + window.alert("No email provided by social login. Please use another form of login"); + window.location.assign("/auth"); // redirect back to login page + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + +:::note[On success, the backend sends back session tokens as part of the response headers which are automatically handled by the frontend SDK.] +::: + +#### Special case for login with Apple + + +Unlike other providers, Apple does not redirect your user back to your frontend app. Instead, it redirects the user to your backend with a `FORM POST` request. This means that the URL you configure on Apple's dashboard should point to your backend API layer. Here, **middleware** handles the request and redirects the user to your frontend app. Your frontend app should then call the `signInAndUp` API on that page as shown previously. + +To tell SuperTokens which frontend route to redirect the user back to, set the `frontendRedirectURI` to the frontend route. Also, set the `redirectURIOnProviderDashboard` to point to your backend API route, to which Apple sends a `POST` request. + + + + +```tsx {9} +import { getAuthorisationURLWithQueryParamsAndSetState } from "supertokens-web-js/recipe/thirdparty"; + +async function appleSignInClicked() { + try { + const authUrl = await getAuthorisationURLWithQueryParamsAndSetState({ + thirdPartyId: "apple", + + frontendRedirectURI: "http://localhost:3000/auth/callback/apple", // This is an example callback URL on your frontend. You can use another path as well. + redirectURIOnProviderDashboard: "/auth/callback/apple", // This URL goes on the Apple's dashboard + }); + + // we redirect the user to apple for auth. + window.location.assign(authUrl); + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + + +```tsx {7} +async function appleSignInClicked() { + try { + const authUrl = await supertokensThirdParty.getAuthorisationURLWithQueryParamsAndSetState({ + thirdPartyId: "apple", + + frontendRedirectURI: "http://localhost:3000/auth/callback/apple", // This is an example callback URL on your frontend. You can use another path as well. + redirectURIOnProviderDashboard: "/auth/callback/apple", // This URL goes on the Apple's dashboard + }); + + /* + Example value of authUrl: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&client_id=&state=5a489996a28cafc83ddff&redirect_uri=https%3A%2F%2Fsupertokens.io%2Fdev%2Foauth%2Fredirect-to-app&flowName=GeneralOAuthFlow + */ + + // we redirect the user to google for auth. + window.location.assign(authUrl); + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + + +:::info[If you are using the **Authorization Code Grant** flow with **PKCE** you do **not** need to provide a client secret during backend init.] +This only works for providers which support the [PKCE flow](https://oauth.net/2/pkce/). + +::: + + + ### Sign in with Apple example + + + + + + + +#### Fetching the authorisation token on the frontend + +For react native apps, this involves setting up the [react-native-apple-authentication library](https://github.com/invertase/react-native-apple-authentication) in your app. Check out their `README` for steps on how to integrate their `SDK` into your application. The minimum scope required by SuperTokens is the one that gives the user's email. In the case of Apple, that could be the user's actual email or the proxy email provided by Apple - it doesn't matter. + +Once the integration is complete, you should call the `appleAuth.performRequest` function for iOS and the `appleAuthAndroid.signIn` function for Android. Either way, the result of the function is a one-time use auth code which you should send to your backend as shown in the next step. + +A full example of this is available in [the example app](https://github.com/supertokens/supertokens-react-native/blob/master/examples/with-thirdparty/apple.ts). + +In case you are using Expo, you can use the [expo-apple-authentication](https://docs.expo.dev/versions/latest/sdk/apple-authentication/) library instead (not that this library only works on iOS). + + + + + + + + + + +#### Fetching the authorisation token on the frontend + +:::info[At the moment this flow is not supported on Android.] +::: + + + + + + + + + +#### Fetching the authorisation token on the frontend + +For iOS you use the normal sign in with apple flow and then use the authorization code to login with SuperTokens. You can see a full example of this in the `onAppleClicked` function in [the example app](https://github.com/supertokens/supertokens-ios/blob/master/examples/with-thirdparty/with-thirdparty/LoginScreen/LoginScreenViewController.swift). + +```swift +import UIKit +import AuthenticationServices + +fileprivate class ViewController: UIViewController, ASAuthorizationControllerPresentationContextProviding, ASAuthorizationControllerDelegate { + func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { + return view.window! + } + + func loginWithApple() { + let authorizationRequest = ASAuthorizationAppleIDProvider().createRequest() + authorizationRequest.requestedScopes = [.email, .fullName] + + let authorizationController = ASAuthorizationController(authorizationRequests: [authorizationRequest]) + + authorizationController.presentationContextProvider = self + authorizationController.delegate = self + authorizationController.performRequests() + } + + func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { + guard let credential: ASAuthorizationAppleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential, + let authorizationCode = credential.authorizationCode, + let authorizationCodeString: String = String(data: authorizationCode, encoding: .utf8), + let email: String = credential.email as? String, + let nameComponents: PersonNameComponents = credential.fullName as? PersonNameComponents, + let firstName: String = nameComponents.givenName as? String, + let lastName: String = nameComponents.familyName as? String else {return} + + // Send the user information and auth code to the backend. Refer to the next step. + } +} +``` + + + + + + + + + +#### Fetching the authorisation token on the frontend + +For flutter, use the [`sign_in_with_apple`](https://pub.dev/packages/sign_in_with_apple) package. Make sure to follow the prerequisite steps to get the package setup. After setup, use the snippet below to trigger the apple sign-in flow. You can see a full example of this in the `loginWithApple` function in [the example app](https://github.com/supertokens/supertokens-flutter/blob/master/examples/with-thirdparty/lib/screens/login.dart). + +```dart +import 'package:sign_in_with_apple/sign_in_with_apple.dart'; + +void loginWithApple() async { + try { + var credential = await SignInWithApple.getAppleIDCredential( + scopes: [ + AppleIDAuthorizationScopes.email, + AppleIDAuthorizationScopes.fullName, + ], + // Required for Android only + webAuthenticationOptions: WebAuthenticationOptions( + clientId: "", + redirectUri: Uri.parse( + "//callback/apple", + ), + ), + ); + + String authorizationCode = credential.authorizationCode; + String? idToken = credential.identityToken; + String? email = credential.email; + String? firstname = credential.givenName; + String? lastName = credential.familyName; + + // Send the user information and auth code to the backend. Refer to the next step. + } catch (e) { + // Sign in aborted or failed + } +} +``` + +In the snippet above for Android, you need an additional `webAuthenticationOptions` property when signing in with Apple. +This is because on Android the library uses the web login flow and requires the client id and redirection URI. +The `redirectUri` property here is the URL to which Apple makes a `POST` request after the user has logged in. +The SuperTokens backend SDKs provide an API for this at `/`<API_BASE_PATH>`/callback/apple`. - +#### Additional steps for Android + +For android, a way for the web login flow to redirect back to the app is also needed. By default, the API provided by the backend `SDKs` redirects to the website domain you provide when initializing the `SDK`. The API can be overridden to redirect to the app instead. For example, if using the Node.js `SDK`: + + + + + +```tsx {4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39} +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +ThirdParty.init({ + override: { + apis: (original) => { + return { + ...original, + appleRedirectHandlerPOST: async (input) => { + if (original.appleRedirectHandlerPOST === undefined) { + throw Error("Should never come here"); + } + + // inut.formPostInfoFromProvider contains all the query params attached by Apple + const stateInBase64 = input.formPostInfoFromProvider.state; + + // The web SDKs add a default state + if (stateInBase64 === undefined) { + // Redirect to android app + // We create a dummy URL to create the query string + const dummyUrl = new URL("http://localhost:8080"); + for (const [key, value] of Object.entries(input.formPostInfoFromProvider)) { + dummyUrl.searchParams.set(key, `${value}`); + } + + const queryString = dummyUrl.searchParams.toString(); + // Refer to the README of sign_in_with_apple to understand what this url is + const redirectUrl = `intent://callback?${queryString}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end`; + + input.options.res.setHeader("Location", redirectUrl, false); + input.options.res.setStatusCode(303); + input.options.res.sendHTMLResponse(""); + } else { + // For the web flow we can use the original implementation + original.appleRedirectHandlerPOST(input); + } + }, + }; + }, + }, +}) +``` + + + + + +```go {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44} +import ( + "net/http" + "strings" + + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + thirdparty.Init(&tpmodels.TypeInput{ + Override: &tpmodels.OverrideStruct{ + APIs: func(originalImplementation tpmodels.APIInterface) tpmodels.APIInterface { + originalAppleRedirectPost := *originalImplementation.AppleRedirectHandlerPOST + + *originalImplementation.AppleRedirectHandlerPOST = func(formPostInfoFromProvider map[string]interface{}, options tpmodels.APIOptions, userContext *map[string]interface{}) error { + // formPostInfoFromProvider contains all the query params attached by Apple + state, stateOk := formPostInfoFromProvider["state"].(string) + + queryParams := []string{} + if (!stateOk) || state == "" { + // Redirect to android app + for key, value := range formPostInfoFromProvider { + queryParams = append(queryParams, key+"="+value.(string)) + } + + queryString := "" + if len(queryParams) > 0 { + queryString = strings.Join(queryParams, "&") + } + + // Refer to the README of sign_in_with_apple to understand what this url is + redirectUri := "intent://callback?" + queryString + "#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end" + + options.Res.Header().Set("Location", redirectUri) + options.Res.WriteHeader(http.StatusSeeOther) + return nil + } else { + return originalAppleRedirectPost(formPostInfoFromProvider, options, userContext) + } + } + + return originalImplementation + }, + }, + }) +} +``` + + + + + +```python {5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,37,38,39} +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty.interfaces import APIInterface, APIOptions +from typing import Dict, Any + +def override_thirdparty_apis(original_implementation: APIInterface): + original_apple_redirect_post = original_implementation.apple_redirect_handler_post + + async def apple_redirect_handler_post( + form_post_info: Dict[str, Any], + api_options: APIOptions, + user_context: Dict[str, Any] + ): + # form_post_info contains all the query params attached by Apple + state = form_post_info["state"] + + # The web SDKs add a default state + if state is None: + query_items = [ + f"{key}={value}" for key, value in form_post_info.items() + ] + + query_string = "&".join(query_items) + + # Refer to the README of sign_in_with_apple to understand what this url is + redirect_url = "intent://callback?" + query_string + "#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end" + + api_options.response.set_header("Location", redirect_url) + api_options.response.set_status_code(303) + api_options.response.set_html_content("") + else: + return await original_apple_redirect_post(form_post_info, api_options, user_context) + + original_implementation.apple_redirect_handler_post = apple_redirect_handler_post + return original_implementation + +thirdparty.init( + override=thirdparty.InputOverrideConfig( + apis=override_thirdparty_apis + ), +) +``` + + + + + +In the code above, the `appleRedirectHandlerPOST` API is overridden to check if the request came from the Android app. You can skip checking the state if you only have a mobile app and no website. `sign_in_with_apple` requires parsing the query params sent by Apple and including them in the redirect URL in a specific way. Then, redirect to the deep link URL. Refer to the README for `sign_in_with_apple` to read about the deep link setup required in Android. + + + + + + + +#### Calling the `signinup` API to consume the authorisation token + + +Once you have the authorization code from the auth provider, you need to call the `/signinup` API exposed by the backend `SDK` as shown below: + +```bash +curl --location --request POST '/auth/signinup' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "thirdPartyId": "apple", + "clientType": "...", + "redirectURIInfo": { + "redirectURIOnProviderDashboard": "/auth/callback/apple", + "redirectURIQueryParams": { + "code": "...", + "user": { + "name":{ + "firstName":"...", + "lastName":"..." + }, + "email":"..." + } + } + } +}' +``` + +:::note[- On iOS, the client id set in the backend should be the same as the bundle identifier for your app.] +- The `clientType` input is optional and required only if you initialize more than one client in the provider on the backend (See the "Social / `SSO` login for both, web and mobile apps" section below). +- On iOS, `redirectURIOnProviderDashboard` doesn't matter and its value can be a universal link configured for your app. +- On Android, the `redirectURIOnProviderDashboard` should match the one configured on the Apple developer dashboard. +- The `user` object contains information provided by Apple. +::: + +The response body from the API call has a `status` property in it: +- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. +- `status: "NO_EMAIL_GIVEN_BY_PROVIDER"`: This status occurs if the social / `SSO` provider did not provide an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider. +- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. +- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. + +:::note[On success, the backend sends back session tokens as part of the response headers which are automatically handled by the frontend `SDK` for you.] +::: + + +### Sign in with Google example + + + + + + + +#### Fetching the authorisation token on the frontend + +This involves setting up the [@react-native-google-signin/google-signin](https://github.com/react-native-google-signin/google-signin) in your app. Checkout their `README` for steps on how to integrate their `SDK` into your application. The minimum scope required by SuperTokens is the one that gives the user's email. + +Once you configure the library, use `GoogleSignin.configure` and `GoogleSignin.signIn` to trigger the login flow and sign the user in with Google. Refer to [the example app](https://github.com/supertokens/supertokens-react-native/blob/master/examples/with-thirdparty/google.ts) to see the full code for this. + +```tsx +import { GoogleSignin } from "@react-native-google-signin/google-signin"; + +export const performGoogleSignIn = async (): Promise => { + GoogleSignin.configure({ + webClientId: "GOOGLE_WEB_CLIENT_ID", + iosClientId: "GOOGLE_IOS_CLIENT_ID", + }); + + try { + const response = await GoogleSignin.signIn({}); + const authCode = response.data?.serverAuthCode; + + // Refer to step 2 + + return true; + } catch (e) { + console.log("Google sign in failed with error", e); + } + + return false; +}; +``` + + + + + + + + + + +#### Fetching the authorisation token on the frontend + +Follow the [official Google Sign In guide](https://developers.google.com/identity/sign-in/android/start-integrating) to set up their library and sign the user in with Google. Fetch the authorization code from the Google sign-in result. For a full example, refer to the `signInWithGoogle` function in [the example app](https://github.com/supertokens/supertokens-android/blob/master/examples/with-thirdparty/app/src/main/java/com/supertokens/supertokensexample/LoginActivity.kt). + +```kotlin +import androidx.activity.result.ActivityResult +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.util.Log +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.auth.api.signin.GoogleSignInOptions +import android.content.Intent + +class LoginActivity : AppCompatActivity() { + private lateinit var googleResultLauncher: ActivityResultLauncher + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + googleResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + onGoogleResultReceived(it) + } + } + + private fun signInWithGoogle() { + val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestServerAuthCode("GOOGLE_WEB_CLIENT_ID") + .requestEmail() + .build() + + val googleClient = GoogleSignIn.getClient(this, gso) + val signInIntent = googleClient.signInIntent + + googleResultLauncher.launch(signInIntent) + } + + private fun onGoogleResultReceived(it: ActivityResult) { + val task = GoogleSignIn.getSignedInAccountFromIntent(it.data) + val account = task.result + val authCode = account.serverAuthCode + + // Refer to step 2 + } +} +``` + + + + + + + + + +#### Fetching the authorisation token on the frontend + +For iOS, use the `GoogleSignIn` library. Follow the [official guide](https://developers.google.com/identity/sign-in/ios/start-integrating) to set up the library and sign the user in with Google. Use the result of Google sign-in to get the authorization code. For a full example, refer to the `onGoogleCliked` function in [the example app](https://github.com/supertokens/supertokens-ios/blob/master/examples/with-thirdparty/with-thirdparty/LoginScreen/LoginScreenViewController.swift). + +```swift +import UIKit +import GoogleSignIn + +fileprivate class LoginScreenViewController: UIViewController { + @IBAction func onGoogleCliked() { + GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in + guard error == nil else { return } + + guard let authCode: String = signInResult?.serverAuthCode as? String else { + print("Google login did not return an authorisation code") + return + } + + // Refer to step 2 + } + } +} +``` + + + + + + + + + +#### Fetching the authorisation token on the frontend + +For flutter, use the [`google_sign_in`](https://pub.dev/packages/google_sign_in) package. Make sure to follow the prerequisite steps to get the package setup. After setup, use the snippet below to trigger the Google sign-in flow. For a full example, refer to the `loginWithGoogle` in [the example app](https://github.com/supertokens/supertokens-flutter/blob/master/examples/with-thirdparty/lib/screens/login.dart). + +```dart +import 'package:google_sign_in/google_sign_in.dart'; +import 'dart:io'; + +Future loginWithGoogle() async { + GoogleSignIn googleSignIn; + + if (Platform.isAndroid) { + googleSignIn = GoogleSignIn( + serverClientId: "GOOGLE_WEB_CLIENT_ID", + scopes: [ + 'email', + ], + ); + } else { + googleSignIn = GoogleSignIn( + clientId: "GOOGLE_IOS_CLIENT_ID", + serverClientId: "GOOGLE_WEB_CLIENT_ID", + scopes: [ + 'email', + ], + ); + } + + GoogleSignInAccount? account = await googleSignIn.signIn(); + + if (account == null) { + print("Google sign in was aborted"); + return; + } + + String? authCode = account.serverAuthCode; + + if (authCode == null) { + print("Google sign in did not return a server auth code"); + return; + } + + // Refer to step 2 + } +``` + + + + + + + +

Step 2) Calling the `signinup` API to consume the authorisation token

+ + +Once you have the authorization code from the auth provider, you need to call the `signinup` API exposed by the backend `SDK` as shown below: + +```bash +curl --location --request POST '/auth/signinup' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "thirdPartyId": "google", + "clientType": "...", + "redirectURIInfo": { + "redirectURIOnProviderDashboard": "", + "redirectURIQueryParams": { + "code": "...", + } + } +}' +``` + +:::note[When calling the API exposed by the SuperTokens backend `SDK`, pass an empty string for `redirectURIOnProviderDashboard`.] +The native login flow using the authorization code does not involve any redirection on the frontend. +::: + +The response body from the API call has a `status` property in it: +- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. +- `status: "NO_EMAIL_GIVEN_BY_PROVIDER"`: This status occurs if the social / `SSO` provider did not provide an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider. +- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. +- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. + +:::note[On success, the backend sends back session tokens as part of the response headers which are automatically handled by the frontend `SDK` for you.] +::: + + +### Authorization code grant flow with `PKCE` + +This is similar to the first one, except that you do **not** need to provide a client secret during backend init. +This flow only works for providers which support the [`PKCE` flow](https://oauth.net/2/pkce/). + + + + + + + +#### Fetching the authorisation token on the frontend + +You can use the [react native auth library](https://github.com/FormidableLabs/react-native-app-auth) to also return the `PKCE` code verifier along with the authorization code. Achieve this by setting the `usePKCE` boolean to `true` and also by setting the `skipCodeExchange` to `true` when configuring the react native auth library. + + + + + + + + + + +#### Fetching the authorisation token on the frontend + +You can use the [AppAuth-Android](https://github.com/openid/AppAuth-Android) library to use the `PKCE` flow by using the `setCodeVerifier` method when creating a `AuthorizationRequest`. + + + + + + + + + +#### Fetching the authorisation token on the frontend + +You can use the [AppAuth-iOS](https://github.com/openid/AppAuth-iOS) library to use the `PKCE` flow. + + + + + + + + + + +#### Fetching the authorisation token on the frontend + +You can use [`flutter_appauth`](https://pub.dev/packages/flutter_appauth) to use the `PKCE` flow by providing a `codeVerifier` when you call the `appAuth.token` function. + + + + + + + +#### Calling the `signinup` API to consume the authorisation token + + +Once you have the authorization code and `PKCE` verifier from the auth provider, you need to call the `/signinup` API exposed by the backend `SDK` as shown below: + +```bash +curl --location --request POST '/auth/signinup' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "thirdPartyId": "THIRD_PARTY_ID", + "clientType": "...", + "redirectURIInfo": { + "redirectURIOnProviderDashboard": "REDIRECT_URI", + "redirectURIQueryParams": { + "code": "...", + }, + "pkceCodeVerifier": "..." + } +}' +``` + +:::note[- Replace `THIRD_PARTY_ID` with the provider id. The provider id must match the one you configure in the backend when initialising SuperTokens.] +- `REDIRECT_URI` must exactly match the value you configure on the providers dashboard. +::: + +The response body from the API call has a `status` property in it: +- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. +- `status: "NO_EMAIL_GIVEN_BY_PROVIDER"`: This status occurs if the social / `SSO` provider did not provide an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider. +- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. +- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. + +:::note[On success, the backend sends back session tokens as part of the response headers which are automatically handled by the frontend `SDK` for you.] +::: +
+
+ + + + + :::info[This flow is not applicable for web apps.] + + ::: + + + ### Fetching the OAuth/Access tokens on the frontend + +1. Sign in with the social provider. The minimum required scope is the one that provides access to the user's email. You can use any library to sign in with the social provider. +2. Get the access token on the frontend if it is available. +3. Get the id token from the sign in result if it is available. + +:::note[You need to provide either the access token or the id token, or both in step 2, depending on what is available.] +::: + +### Calling the `signinup` API to use the OAuth tokens + + +Once you have the `access_token` or the `id_token` from the auth provider, you need to call the `/signinup` API exposed by the backend `SDK` as shown below: + +```bash +curl --location --request POST '/auth/signinup' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "thirdPartyId": "google", + "clientType": "...", + "oAuthTokens": { + "access_token": "...", + "id_token": "..." + }, +}' +``` + +:::note[- The `clientType` input is optional, and you need it only if you have initialised more than one client in the provide on the backend (See the "Social / Single Sign-On login for both, web and mobile apps" section below).] +- If you have the `id_token`, you can send that along with the `access_token`. +::: + +The response body from the API call has a `status` property in it: +- `status: "OK"`: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user. +- `status: "NO_EMAIL_GIVEN_BY_PROVIDER"`: This occurs if the social / Single Sign-On provider did not provide an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider. +- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should display on the frontend. +- `status: "SIGN_IN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during `MFA`. The `reason` prop that's in the response body contains a support code using which you can see why the sign in / up was not allowed. + +:::note[On success, the backend sends back session tokens as part of the response headers which are automatically handled by the frontend `SDK` for you.] +::: + + + + + + +### 3. Initialize the backend SDK + +You have to initialize the **Backend Software Development Kit (SDK)** alongside the code that starts your server. +The init call includes [configuration details](/references/backend-sdks/reference#sdk-configuration) for your app. It specifies how the backend connects to the **SuperTokens Core**, as well as the **Recipes** used in your setup. + + + + + + +```tsx title="Backend SDK Init" {3,24} +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +supertokens.init({ + // Replace this with the framework you are using + framework: "express", + supertokens: { + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + connectionURI: "https://try.supertokens.io", + // apiKey: + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [ + ThirdParty.init({/*TODO: See next step*/}), + Session.init() + ] +}); +``` + + + + + + + +```python title="Backend SDK Init" {3} +from supertokens_python import init, InputAppInfo, SupertokensConfig +from supertokens_python.recipe import thirdparty, session + +init( + app_info=InputAppInfo( + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" + ), + supertokens_config=SupertokensConfig( + # We use try.supertokens for demo purposes. + # At the end of the tutorial we will show you how to create + # your own SuperTokens core instance and then update your config. + connection_uri="https://try.supertokens.io", + # api_key: + ), + framework='fastapi', + recipe_list=[ + session.init(), # initializes session features + thirdparty.init( + # TODO: See next step + ) + ], + mode='asgi' # use wsgi if you are running using gunicorn +) +``` + + + + + + + +```go title="Backend SDK Init" +import ( + "github.com/supertokens/supertokens-golang/recipe/session" + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + apiBasePath := "/auth" + websiteBasePath := "/auth" + err := supertokens.Init(supertokens.TypeInput{ + Supertokens: &supertokens.ConnectionInfo{ + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + ConnectionURI: "https://try.supertokens.io", + // APIKey: + }, + AppInfo: supertokens.AppInfo{ + AppName: "", + APIDomain: "", + WebsiteDomain: "", + APIBasePath: &apiBasePath, + WebsiteBasePath: &websiteBasePath, + }, + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{/*TODO: See next step*/}), + session.Init(nil), // initializes session features + }, + }) + + if err != nil { + panic(err.Error()) + } +} +``` + + + + + +### 4. Add the authentication providers + +Populate the `providers` array with the third party authentication providers that you want. + + + + +```tsx {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45} +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "...", + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + // We have provided you with development keys which you can use for testing. + // IMPORTANT: Please replace them with your own OAuth keys for production use. + providers: [{ + config: { + thirdPartyId: "google", + clients: [{ + clientId: "", + clientSecret: "" + }] + } + }, { + config: { + thirdPartyId: "github", + clients: [{ + clientId: "467101b197249757c71f", + clientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd" + }] + } + }, { + config: { + thirdPartyId: "apple", + clients: [{ + clientId: "4398792-io.supertokens.example.service", + additionalConfig: { + keyId: "7M48Y4RYDL", + privateKey: + "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", + teamId: "YWQCXGJRJL", + } + }] + } + }], + } + }), + // ... + ] +}); +``` + + + +```go {9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51} +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" +) + +func main() { + // Inside supertokens.Init + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + // We have provided you with development keys which you can use for testing. + // IMPORTANT: Please replace them with your own OAuth keys for production use. + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "google", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "", + ClientSecret: "", + }, + }, + }, + }, + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "github", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "467101b197249757c71f", + ClientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd", + }, + }, + }, + }, + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "apple", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "4398792-io.supertokens.example.service", + AdditionalConfig: map[string]interface{}{ + "keyId": "7M48Y4RYDL", + "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", + "teamId": "YWQCXGJRJL", + }, + }, + }, + }, + }, + }, + }, + }) +} +``` + + + +```python {6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46} +from supertokens_python.recipe.thirdparty.provider import ProviderInput, ProviderConfig, ProviderClientConfig +from supertokens_python.recipe import thirdparty + +# Inside init +thirdparty.init( + sign_in_and_up_feature=thirdparty.SignInAndUpFeature(providers=[ + # We have provided you with development keys which you can use for testing. + # IMPORTANT: Please replace them with your own OAuth keys for production use. + ProviderInput( + config=ProviderConfig( + third_party_id="google", + clients=[ + ProviderClientConfig( + client_id="", + client_secret="", + ), + ], + ), + ), + ProviderInput( + config=ProviderConfig( + third_party_id="github", + clients=[ + ProviderClientConfig( + client_id="467101b197249757c71f", + client_secret="e97051221f4b6426e8fe8d51486396703012f5bd", + ) + ], + ), + ), + ProviderInput( + config=ProviderConfig( + third_party_id="apple", + clients=[ + ProviderClientConfig( + client_id="io.supertokens.example.service", + additional_config={ + "keyId": "7M48Y4RYDL", + "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----", + "teamId": "YWQCXGJRJL" + }, + ), + ], + ), + ), + ]) +) +``` + + + + + +:::note[The examples use a set of development keys meant for demonstration purposes only.] +Please use your own OAuth credentials. +Read the list of [built-in providers](/authentication/social/built-in-providers-config) that also includes information on how to generate your own keys. +To add a provider that is not listed, you can follow the guide on [setting up custom providers](/authentication/social/custom-providers). +::: + + +#### Set OAuth scopes + +To add additional OAuth scopes when accessing your third-party provider, add them to the configuration when initializing the backend `SDK`. + +For example if you are using Google as your third party provider, you can add an additional scope as follows: + + + + +```tsx +import SuperTokens from "supertokens-node"; +import ThirdParty from "supertokens-node/recipe/thirdparty"; + +SuperTokens.init({ + supertokens: { + connectionURI: "...", + }, + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "..." + }, + recipeList: [ + ThirdParty.init({ + signInAndUpFeature: { + providers: [ + { + config: { + thirdPartyId: "google", + clients: [{ + clientId: "TODO: GOOGLE_CLIENT_ID", + clientSecret: "TODO: GOOGLE_CLIENT_SECRET", + scope: ["scope1", "scope2"] + }] + } + } + ] + } + }) + ] +}); +``` + + + + +```go +import ( + "github.com/supertokens/supertokens-golang/recipe/thirdparty" + "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels" + "github.com/supertokens/supertokens-golang/supertokens" +) + +func main() { + supertokens.Init(supertokens.TypeInput{ + RecipeList: []supertokens.Recipe{ + thirdparty.Init(&tpmodels.TypeInput{ + SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{ + Providers: []tpmodels.ProviderInput{ + { + Config: tpmodels.ProviderConfig{ + ThirdPartyId: "google", + Clients: []tpmodels.ProviderClientConfig{ + { + ClientID: "TODO: GOOGLE_CLIENT_ID", + ClientSecret: "TODO: GOOGLE_CLIENT_SECRET", + Scope: []string{ + "scope1", "scope2", + }, + }, + }, + }, + }, + }, + }, + }), + }, + }) +} +``` + + + + +```python {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26} +from supertokens_python import init, InputAppInfo +from supertokens_python.recipe import thirdparty +from supertokens_python.recipe.thirdparty import ProviderInput, ProviderConfig, ProviderClientConfig, SignInAndUpFeature + +init( + app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), + framework='...', + recipe_list=[ + thirdparty.init( + + sign_in_and_up_feature=SignInAndUpFeature( + providers=[ + ProviderInput( + config=ProviderConfig( + third_party_id="google", + clients=[ + ProviderClientConfig( + client_id="GOOGLE_CLIENT_ID", + client_secret="GOOGLE_CLIENT_SECRET", + scope=["scope1", "scope2"] + ), + ], + ), + ), + ] + ) + ) + ] +) +``` + + + + +:::note[Along with your custom scopes, also add scopes that ask for the user's email and its verification status. For example, with Google, this scope is `"https://www.googleapis.com/auth/userinfo.email"`.] +::: - +
## Next steps Having completed the main setup, you can explore more advanced topics related to the **ThirdParty** recipe. - - - - Built-in Providers - - - Read more about the common providers exposed by the recipe. - - - - - Custom Providers - - - See how you can create your own custom provider. - - - - - Custom Invite Flow - - - Disable public sign ups and use your own invite flow. - - - - - Hooks and Overrides - - - Add custom logic after the logs in or signs up. - - - + + +Read more about the common providers exposed by the recipe. + + +See how you can create your own custom provider. + + +Disable public sign ups and use your own invite flow. + + +Add custom logic after the logs in or signs up. + + diff --git a/docs/authentication/social/introduction.mdx b/docs/authentication/social/introduction.mdx index 4712db856b..4b66a31f32 100644 --- a/docs/authentication/social/introduction.mdx +++ b/docs/authentication/social/introduction.mdx @@ -1,87 +1,46 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -pagination_next: null -pagination_prev: null -skip_llms_txt: true -description: >- - Authenticate users with third-party providers using pre-built UI or custom SDK - interfaces. -page_type: overview -recipe: thirdparty -category: thirdparty +description: Authenticate users with third-party providers using pre-built UI or custom SDK interfaces. +sidebar: + order: 1 --- - -# Introduction - ## Overview The **ThirdParty** `recipe` provides a way of authenticating users through a third party provider. You can use it out of the box, with the **Pre-Built UI**, or implement your own interface through the available SDKs. -Sign in form UI for passwordless login +Sign in form UI for passwordless login ## Getting started You can either follow the quickstart tutorial or use the `CLI` tool to generate an example app that shows you how the recipe works. - - - - Quickstart - - - Go through a quick tutorial that shows you how to add the **ThirdParty** recipe to your app. - - - - - Example Applications - - - Use the CLI to generate a boilerplate app that you can use as a starting point. - - - + + +Go through a quick tutorial that shows you how to add the **ThirdParty** recipe to your app. + + +Use the CLI to generate a boilerplate app that you can use as a starting point. + + ## Customization To adjust the functionality to fit your use case you can explore different sections from the documentation. - - - - Built-in Providers - - - Read more about the common providers exposed by the recipe. - - - - - Custom Providers - - - See how you can create your own custom provider. - - - - - Hooks and Overrides - - - Add custom logic after the logs in or signs up. - - - - - Custom Invite Flow - - - Disable public sign ups and use your own invite flow. - - - + + +Read more about the common providers exposed by the recipe. + + +See how you can create your own custom provider. + + +Add custom logic after the logs in or signs up. + + +Disable public sign ups and use your own invite flow. + + diff --git a/docs/authentication/social/meta.ts b/docs/authentication/social/meta.ts new file mode 100644 index 0000000000..23d6e3b078 --- /dev/null +++ b/docs/authentication/social/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Social Login", + "icon": "circle-user-round", + "order": 3 +}); diff --git a/docs/authentication/unified-login/_blocks/create-oauth2-client-request-details.mdx b/docs/authentication/unified-login/_blocks/create-oauth2-client-request-details.mdx deleted file mode 100644 index 80462f85e1..0000000000 --- a/docs/authentication/unified-login/_blocks/create-oauth2-client-request-details.mdx +++ /dev/null @@ -1,102 +0,0 @@ - - - - Creates an OAuth2 client - - - - -**Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. - - - - - - -

Request

- -

Body Schema

- -| Name | Type | Description | Required | Default Value | -|--------------------------------------------|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------| -| `clientName` | `string` | A human-readable name of the client used for identification. | Yes | - | -| `grantTypes` | `array` of `GrantType` | The grant types that the Client uses. | Yes | - | -| `redirectUris` | `array` of `string` | List of URIs where the Authorization Server redirects after authorization. Can include mobile/desktop deep links. Must be exact URLs without wildcards. | Yes | - | | `scope` | `string` | Space-separated string of scopes the Client will request. Include `offline_access` to enable OAuth2 Refresh Token usage. | Yes | - | -| `scope` | `string` | String containing a space-separated list of scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use when requesting access tokens. Include the `offline_access` scope to exchange OAuth2 Refresh Tokens for OAuth2 Access Tokens | No | "" | -| `responseTypes` | `array` of `ResponseType` | The types of responses your client expects from the **Authorization Server** | No | - | -| `tokenEndpointAuthMethod` | `enum`(`"client_secret_basic"`, `"client_secret_post"`, `"private_key_jwt"`, `"none"`) | The requested client authentication method | No | `client_secret_basic` | -| `authorizationCodeGrantAccessTokenLifespan` | `Time Duration` | OAuth2 Access Token lifespan when using the Authorization Code grant flow. | No | `"1h"` | -| `authorizationCodeGrantIdTokenLifespan` | `Time Duration` | OAuth2 ID Token lifespan when using the Authorization Code grant flow. | No | `"1h"` | -| `authorizationCodeGrantRefreshTokenLifespan`| `Time Duration` | OAuth2 Refresh Token lifespan when using the Authorization Code grant flow. | If `refreshTokenGrantRefreshTokenLifespan` is also set | `"30d"` | -| `refreshTokenGrantRefreshTokenLifespan` | `Time Duration` | OAuth2 Refresh Token lifespan when using the Refresh Token grant flow. Must match `authorizationCodeGrantRefreshTokenLifespan`. | If `authorizationCodeGrantRefreshTokenLifespan` is also set | `"30d"` | -| `clientCredentialsGrantAccessTokenLifespan` | `Time Duration` | OAuth2 Access Token lifespan when using the Client Credentials grant flow. | No | `"1h"` | -| `enableRefreshTokenRotation` | `boolean` | Indicates that the refresh token is a one-time use. Set it to `false` to disable refresh token rotation. | No | `true` | - - -

GrantType

- -- `authorization_code`: allows exchanging the Authorization Code for an OAuth2 Access Token. -- `refresh_token`: allows exchanging the OAuth2 Refresh Token for an OAuth2 Access Token. -- `client_credentials`: allows the client to directly request an OAuth2 Access Token by authenticating itself with the Authorization Server using its own client credentials. - -

TokenEndpointAuthMethod

- -- `client_secret_basic`: uses the HTTP Basic Authentication scheme to authenticate the client. -- `client_secret_post`: uses the HTTP `POST` Authentication scheme to authenticate the client. -- `private_key_jwt`: uses JSON Web Tokens (JWT) to authenticate the client. -- `none`: indicates that the process of obtaining an OAuth2 Access Token does not use the client secret. Used for public clients (native apps or mobile apps). - -

ResponseType

- -- `code`: Indicates that the Client receives an Authorization Code that it exchanges for an OAuth2 Access Token. -- `id_token`: Indicates that the Client expects an ID Token. - -

Time Duration

- -A string value that signifies time duration in milliseconds, seconds, minutes, or hours: `"2000ms"`, `"60s"`, `"30m"`, `"1h"`. - -

Example

- -```bash -curl -X POST ^{coreInfo.uri}/recipe/oauth/clients \ - -H "Content-Type: application/json" \ - -H "api-key: ^{coreInfo.key}" \ - -d '{ - "clientName": "", - "responseTypes": ["code"], - "grantTypes": ["authorization_code", "refresh_token"], - "scope": "offline_access ", - "redirectUris": ["https:///oauth/callback"], - }' -``` - -

Response

- -

200

- -The client has been successfully created. - -

Response schema

- -| Property | Type | Description | -|-------------|----------------------------------|-----------------------------------------------| -| `clientName` | `string` | The name of the client. | -| `clientId` | `string` | Unique identifier for the client. | -| `clientSecret` | `string` | The secret is part of the create request as plain text, and then never again. The secret remains in hashed format and is not recoverable once lost. | -| `redirectUris` | `array` of `string` | The URLs used for redirection. | -| `audience` | `array` of `string` | Value used to identify for whom a token is issued. The created client can generate access token only for the specified audiences. | -| `scope` | `array` of `string` | A space separated string of scopes that the Client requests access to. | - -

Example

- -```json -{ - "clientName": "", - "clientId": "", - "redirectUris": ["https:///oauth/callback"], - "audience": [""], - "scope": ["offline_access "], -} -``` - -
diff --git a/docs/authentication/unified-login/_blocks/create-oauth2-client-request-m2m.mdx b/docs/authentication/unified-login/_blocks/create-oauth2-client-request-m2m.mdx deleted file mode 100644 index af751e4862..0000000000 --- a/docs/authentication/unified-login/_blocks/create-oauth2-client-request-m2m.mdx +++ /dev/null @@ -1,121 +0,0 @@ - - -import CreateOAuth2ClientRequestDetails from "./create-oauth2-client-request-details.mdx"; - - - - -```bash -curl --location --request POST '^{coreInfo.uri}/recipe/oauth/clients' \ - --header 'api-key: ^{coreInfo.key}' \ - --header 'Content-Type: application/json; charset=utf-8' \ - --data ' - { - "clientName": "", - "grantTypes": ["client_credentials"], - "scope": " ", - "audience": [""], - } -' -``` - - - - - ```tsx - const BASE_URL = '^{coreInfo.uri}'; - const API_KEY = '^{coreInfo.key}'; - - const url = `${BASE_URL}/recipe/oauth/clients`; - const options = { - method: 'POST', - headers: { - 'api-key': API_KEY, - 'Content-Type': 'application/json; charset=utf-8', - }, - body: JSON.stringify({ - clientName: "", - grantTypes: ["client_credentials"], - scope: " ", - audience: [""], - }) - }; - - fetch(url, options) - .then(response => response.json()) - .then(json => console.log(json)) - .catch(err => console.error(err)); -``` - - - - - ```go - - import ( - "fmt" - "net/http" - "strings" - "io" - ) - - func main() { - baseUrl := "^{coreInfo.uri}" - apiKey := "^{coreInfo.key}" - url := fmt.Sprintf("%s/recipe/oauth/clients", baseUrl) - payload := `{ - "clientName": "", - "grantTypes": ["client_credentials"], - "scope": " ", - "audience": [""], - }` - - req, _ := http.NewRequest("POST", url, strings.NewReader(payload)) - - req.Header.Add("accept", "application/json") - req.Header.Add("api-key", apiKey) - req.Header.Add("content-type", "application/json") - - res, _ := http.DefaultClient.Do(req) - - defer res.Body.Close() - body, _ := io.ReadAll(res.Body) - - fmt.Println(string(body)) - } - ``` - - - - - ```python - import requests - from typing import Dict, Any - - BASE_URL = "^{coreInfo.uri}" - API_KEY = "^{coreInfo.key}" - - url = f"{BASE_URL}/recipe/oauth/clients" - - payload: Dict[str, Any] ={ - "clientName": "", - "grantTypes": ["client_credentials"], - "scope": "custom_scope_1> ", - "audience": [""], - } - - headers = { - "api-key": API_KEY, - "Content-Type": "application/json", - } - - response = requests.post(url, json=payload, headers=headers) - - print(response.json()) - ``` - - - - - - diff --git a/docs/authentication/unified-login/_blocks/create-oauth2-client-request-no-auth.mdx b/docs/authentication/unified-login/_blocks/create-oauth2-client-request-no-auth.mdx deleted file mode 100644 index 2eddde7955..0000000000 --- a/docs/authentication/unified-login/_blocks/create-oauth2-client-request-no-auth.mdx +++ /dev/null @@ -1,129 +0,0 @@ - - -import CreateOAuth2ClientRequestDetails from "./create-oauth2-client-request-details.mdx"; - - - - -```bash -curl --location --request POST '^{coreInfo.uri}/recipe/oauth/clients' \ - --header 'api-key: ^{coreInfo.key}' \ - --header 'Content-Type: application/json; charset=utf-8' \ - --data ' - { - "clientName": "", - "responseTypes": ["code", "id_token"], - "grantTypes": ["authorization_code", "refresh_token"], - "tokenEndpointAuthMethod": "none", - "scope": "offline_access ", - "redirectUris": ["https:///oauth/callback"], - } -' -``` - - - - - ```tsx - const BASE_URL = '^{coreInfo.uri}'; - const API_KEY = '^{coreInfo.key}'; - - const url = `${BASE_URL}/recipe/oauth/clients`; - const options = { - method: 'POST', - headers: { - 'api-key': API_KEY, - 'Content-Type': 'application/json; charset=utf-8', - }, - body: JSON.stringify({ - clientName: "", - responseTypes: ["code", "id_token"], - grantTypes: ["authorization_code", "refresh_token"], - tokenEndpointAuthMethod: "none", - scope: "offline_access ", - redirectUris: ["https:///oauth/callback"], - }) - }; - - fetch(url, options) - .then(response => response.json()) - .then(json => console.log(json)) - .catch(err => console.error(err)); -``` - - - - - ```go - - import ( - "fmt" - "net/http" - "strings" - "io" - ) - - func main() { - baseUrl := "^{coreInfo.uri}" - apiKey := "^{coreInfo.key}" - url := fmt.Sprintf("%s/recipe/oauth/clients", baseUrl) - payload := `{ - "clientName": "", - "responseTypes": ["code", "id_token"], - "grantTypes": ["authorization_code", "refresh_token"], - "tokenEndpointAuthMethod": "none", - "scope": "offline_access ", - "redirectUris": ["https:///oauth/callback"], - }` - - req, _ := http.NewRequest("POST", url, strings.NewReader(payload)) - - req.Header.Add("accept", "application/json") - req.Header.Add("api-key", apiKey) - req.Header.Add("content-type", "application/json") - - res, _ := http.DefaultClient.Do(req) - - defer res.Body.Close() - body, _ := io.ReadAll(res.Body) - - fmt.Println(string(body)) - } - ``` - - - - - ```python - import requests - from typing import Dict, Any - - BASE_URL = "^{coreInfo.uri}" - API_KEY = "^{coreInfo.key}" - - url = f"{BASE_URL}/recipe/oauth/clients" - - payload: Dict[str, Any] ={ - "clientName": "", - "responseTypes": ["code", "id_token"], - "grantTypes": ["authorization_code", "refresh_token"], - "tokenEndpointAuthMethod": "none", - "scope": "offline_access ", - "redirectUris": ["https:///oauth/callback"], - } - - headers = { - "api-key": API_KEY, - "Content-Type": "application/json", - } - - response = requests.post(url, json=payload, headers=headers) - - print(response.json()) - ``` - - - - - - diff --git a/docs/authentication/unified-login/_blocks/create-oauth2-client-request.mdx b/docs/authentication/unified-login/_blocks/create-oauth2-client-request.mdx deleted file mode 100644 index 8f42db0eaa..0000000000 --- a/docs/authentication/unified-login/_blocks/create-oauth2-client-request.mdx +++ /dev/null @@ -1,125 +0,0 @@ - - -import CreateOAuth2ClientRequestDetails from "./create-oauth2-client-request-details.mdx"; - - - - -```bash -curl --location --request POST '^{coreInfo.uri}/recipe/oauth/clients' \ - --header 'api-key: ^{coreInfo.key}' \ - --header 'Content-Type: application/json; charset=utf-8' \ - --data ' - { - "clientName": "", - "responseTypes": ["code"], - "grantTypes": ["authorization_code", "refresh_token"], - "scope": "offline_access ", - "redirectUris": ["https:///oauth/callback"], - } -' -``` - - - - - ```tsx - const BASE_URL = '^{coreInfo.uri}'; - const API_KEY = '^{coreInfo.key}'; - - const url = `${BASE_URL}/recipe/oauth/clients`; - const options = { - method: 'POST', - headers: { - 'api-key': API_KEY, - 'Content-Type': 'application/json; charset=utf-8', - }, - body: JSON.stringify({ - clientName: "", - responseTypes: ["code"], - grantTypes: ["authorization_code", "refresh_token"], - scope: "offline_access ", - redirectUris: ["https:///oauth/callback"], - }) - }; - - fetch(url, options) - .then(response => response.json()) - .then(json => console.log(json)) - .catch(err => console.error(err)); -``` - - - - - ```go - - import ( - "fmt" - "net/http" - "strings" - "io" - ) - - func main() { - baseUrl := "^{coreInfo.uri}" - apiKey := "^{coreInfo.key}" - url := fmt.Sprintf("%s/recipe/oauth/clients", baseUrl) - payload := `{ - "clientName": "", - "responseTypes": ["code"], - "grantTypes": ["authorization_code", "refresh_token"], - "scope": "offline_access ", - "redirectUris": ["https:///oauth/callback"], - }` - - req, _ := http.NewRequest("POST", url, strings.NewReader(payload)) - - req.Header.Add("accept", "application/json") - req.Header.Add("api-key", apiKey) - req.Header.Add("content-type", "application/json") - - res, _ := http.DefaultClient.Do(req) - - defer res.Body.Close() - body, _ := io.ReadAll(res.Body) - - fmt.Println(string(body)) - } - ``` - - - - - ```python - import requests - from typing import Dict, Any - - BASE_URL = "^{coreInfo.uri}" - API_KEY = "^{coreInfo.key}" - - url = f"{BASE_URL}/recipe/oauth/clients" - - payload: Dict[str, Any] ={ - "clientName": "", - "responseTypes": ["code"], - "grantTypes": ["authorization_code", "refresh_token"], - "scope": "offline_access ", - "redirectUris": ["https:///oauth/callback"], - } - - headers = { - "api-key": API_KEY, - "Content-Type": "application/json", - } - - response = requests.post(url, json=payload, headers=headers) - - print(response.json()) - ``` - - - - - - diff --git a/docs/authentication/unified-login/_blocks/custom-ui-guide.mdx b/docs/authentication/unified-login/_blocks/custom-ui-guide.mdx deleted file mode 100644 index c8b64b910f..0000000000 --- a/docs/authentication/unified-login/_blocks/custom-ui-guide.mdx +++ /dev/null @@ -1,271 +0,0 @@ - - -The user interface that you are going to build should respect this flow: - - - -## A user accesses your application and tries to login. - -It's up to you how you want to handle this. -They can click a button to login or you can directly start the login flow. - -## They get redirected to the **Authorization Service Backend** - -A **OAuth2/OpenID Connect (OIDC)** library can execute this action. -Check the previous guides for information on what you could use. - -## The **Authorization Service Backend** redirects them to the **Authorization Service Frontend** login page. - -The page URL contains a `loginChallenge` parameter that keeps track of the login attempt. -Besides that, the URL can also include a `forceFreshAuth` parameter. -As the name suggests, this should force the login UI to be visible even though the user has an existing valid session. -This guide shows you how to handle this. - -## The **Authorization Service Frontend** renders the login UI and the user performs the login action. - -The login UI should render based on instructions that are specific to each authentication method which you are using. -The additional thing that you have to do here is to consider the `forceFreshAuth` parameter. - -## The **Authorization Service Frontend** redirects the user back to the **Authorization Service Backend** - -After the user submits the login form, you need to redirect them to a specific route that sends them to the original application. -From here, the authentication flow completes. - - - -Let's see how you can actually implement this UI. - -#### 4.1 Configure the redirection URLs - -As it has hinted in the previous section, the **Authorization Service Backend** sends the user to different pages from the **Authorization Service Frontend**, based on the action that needs execution. - -The default values for these routes are: - -- The login page maps to `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}` (this is also the place where a user ends up after logout) -- The token refresh page maps to `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/try-refresh` -- The logout page maps to `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/logout` - -If you want to change these routes, you need to add a custom override. - -:::info -This override needs addition to the **Authorization Service Backend**. -::: - - - - - -```tsx -import OAuth2Provider from "supertokens-node/recipe/oauth2provider"; - -OAuth2Provider.init({ - override: { - functions: (originalFunctions) => ({ - ...originalFunctions, - getFrontendRedirectionURL: async (input) => { - const websiteDomain = '^{appInfo.websiteDomain}'; - const websiteBasePath = '^{appInfo.websiteBasePath}'; - - if (input.type === "login") { - const queryParams = new URLSearchParams({ - loginChallenge: input.loginChallenge, - }); - if (input.hint !== undefined) { - queryParams.set("hint", input.hint); - } - if (input.forceFreshAuth) { - queryParams.set("forceFreshAuth", "true"); - } - - return `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}?${queryParams.toString()}`; - } else if (input.type === "try-refresh") { - return `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/try-refresh?loginChallenge=${input.loginChallenge}`; - } else if (input.type === "post-logout-fallback") { - return `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}`; - } else if (input.type === "logout-confirmation") { - return `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}/oauth/logout?logoutChallenge=${input.logoutChallenge}`; - } - - return `^{appInfo.websiteDomain}^{appInfo.websiteBasePath}`; - }, - }), - }, -}) - -``` - - - - - -:::caution - -At the moment, there is no support for creating OAuth2 providers in the Go SDK. - -::: - - - - - -:::caution - -At the moment, there is no support for creating OAuth2 providers in the Python SDK. - -::: - - - - - -#### 4.2 Handle the forceFreshAuth parameter - -Sometimes, even though there is an existing valid session in the **Authorization Service Frontend**, the requesting **Client** might force a new login attempt. -The `forceFreshAuth` parameter shows this. - -When the login page renders, you also need to check for this parameter. You are doing this to know if you need to show the login UI. - -Here is an example of how you can evaluate this case. - -```tsx -import Session from 'supertokens-web-js/recipe/session'; - -async function shouldLogin() { - const urlParams = new URLSearchParams(window.location.search); - const forceFreshAuth = urlParams.get('forceFreshAuth') as string; - if(forceFreshAuth === "true") return true; - - return Session.doesSessionExist(); -} - -``` - -:::info Multi Tenancy - -If you are using multi-tenancy, you also need to keep track of the `tenantId` query parameter and pass it between the **Authorization Service Frontend** pages. - -::: - -#### 4.3 Complete the login attempt - - -After the user submits the login form, you need to redirect them to a specific route to complete the **OAuth 2** flow. - -The following code sample shows you how to determine which URL to use. - - - - - -```tsx -import OAuth2Provider from "supertokens-web-js/recipe/oauth2provider"; - -async function getInitialRedirectionURL() { - const urlParams = new URLSearchParams(window.location.search); - const loginChallenge = urlParams.get('loginChallenge') as string; - const redirectionResponse = await OAuth2Provider.getRedirectURLToContinueOAuthFlow({ loginChallenge }); - if (redirectionResponse.status === "OK") { - return redirectionResponse.frontendRedirectTo; - } -} - -``` - - - - - -:::caution - -For mobile apps, you need to reuse the web authentication flow. Check this [guide](/docs/authentication/unified-login/reuse-website-login) for more information. - -::: - - - - - -#### 4.4 Add the token refresh page - -To have support for token refreshing, you need to add a new page to your application. -The path should correspond to the one outlined during the first step. - -When the user ends up on this page, you need to use the `Session` recipe to perform the refresh action. -Then they need redirection to a page from your application. - -Here's a code sample that shows you how to do this. - - - - - -```tsx -import OAuth2Provider from "supertokens-web-js/recipe/oauth2provider"; -import Session from 'supertokens-web-js/recipe/session'; - -async function refreshToken() { - await Session.attemptRefreshingSession(); - const urlParams = new URLSearchParams(window.location.search); - const loginChallenge = urlParams.get('loginChallenge') as string; - const redirectionResponse = await OAuth2Provider.getRedirectURLToContinueOAuthFlow({ loginChallenge }); - if (redirectionResponse.status === "OK") { - window.location.href = redirectionResponse.frontendRedirectTo; - } -} - -``` - - - - - -:::caution - -For mobile apps, you need to reuse the web authentication flow. Check this [guide](/docs/authentication/unified-login/reuse-website-login) for more information. - -::: - - - - - -#### 4.5 Add the logout page - -You need to add a logout page that users access when they want to end their session. -The path should correspond to the one outlined during the first step. - -The logout action should first ask the user for confirmation. -If the confirmation passes, then you can call the recipe function. -Based on the final response you can redirect the user to the provided redirection URL. - - - - - -```tsx -import OAuth2Provider from "supertokens-web-js/recipe/oauth2provider"; - -async function logout() { - const confirmation = confirm("Are you sure that you want to log out?"); - if(!confirmation) return; - - const urlParams = new URLSearchParams(window.location.search); - const logoutChallenge = urlParams.get('logoutChallenge') as string; - const redirectResponse = await OAuth2Provider.logOut({ logoutChallenge }); - window.location.href = redirectResponse.frontendRedirectTo; -} -``` - - - - - -:::caution - -For mobile apps, you need to reuse the web authentication flow. Check this [guide](/docs/authentication/unified-login/reuse-website-login) for more information. - -::: - - - - diff --git a/docs/authentication/unified-login/_blocks/paid-feature-callout.mdx b/docs/authentication/unified-login/_blocks/paid-feature-callout.mdx deleted file mode 100644 index 55296a7810..0000000000 --- a/docs/authentication/unified-login/_blocks/paid-feature-callout.mdx +++ /dev/null @@ -1,6 +0,0 @@ - -:::warning Paid Feature -This is a paid feature. - -For managed service users, open the [SaaS Dashboard](https://supertokens.com/dashboard), select the relevant **Managed** deployment, and enable this feature from **Features**. Changes are saved automatically. Once enabled, this feature is free on the provided development environment. -::: diff --git a/docs/authentication/unified-login/_category_.json b/docs/authentication/unified-login/_category_.json deleted file mode 100644 index 958f0dc6c7..0000000000 --- a/docs/authentication/unified-login/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Unified Login", - "position": 6 -} diff --git a/docs/authentication/unified-login/add-custom-claims-in-tokens.mdx b/docs/authentication/unified-login/add-custom-claims-in-tokens.mdx index 4e2d2fc15b..1e3477eba4 100644 --- a/docs/authentication/unified-login/add-custom-claims-in-tokens.mdx +++ b/docs/authentication/unified-login/add-custom-claims-in-tokens.mdx @@ -1,18 +1,10 @@ --- title: Add custom claims in tokens -hide_title: true -sidebar_position: 6 description: Add custom claims to OAuth2 access and ID tokens using overrides -page_type: guide -recipe: oauth2 -category: unified-login +sidebar: + order: 6 --- -import PaidFeatureCallout from './_blocks/paid-feature-callout.mdx' - -# Add custom claims in tokens - - ## Overview If you want to add custom properties in the token payloads you can do this by using overrides. @@ -22,9 +14,9 @@ If you want to add custom properties in the token payloads you can do this by us ## Add claims in the OAuth2 Access Token - + - + Override the `buildAccessTokenPayload` function to include the custom claims. @@ -51,17 +43,16 @@ OAuth2Provider.init({ ``` - + - + -:::caution -At the moment there is no support for creating OAuth2 providers in the Go SDK. +:::warning[At the moment there is no support for creating OAuth2 providers in the Go SDK.] ::: - + - + Override the `build_access_token_payload` function to include the custom claims. @@ -97,7 +88,7 @@ def override_oauth2provider_functions(original_implementation: RecipeInterface): init( - framework="...", # type: ignore + framework="...", app_info=InputAppInfo( app_name="...", api_domain="...", @@ -115,17 +106,17 @@ init( ) ``` - + - + --- ## Add claims in the ID Token - + - + Override the `buildIdTokenPayload` function to include the custom claims. @@ -152,17 +143,16 @@ OAuth2Provider.init({ ``` - + - + -:::caution -At the moment there is no support for creating OAuth2 providers in the Go SDK. +:::warning[At the moment there is no support for creating OAuth2 providers in the Go SDK.] ::: - + - + Override the `build_id_token_payload` function to include the custom claims. @@ -198,7 +188,7 @@ def override_oauth2provider_functions(original_implementation: RecipeInterface): init( - framework="...", # type: ignore + framework="...", app_info=InputAppInfo( app_name="...", api_domain="...", @@ -216,6 +206,6 @@ init( ) ``` - + - + diff --git a/docs/authentication/unified-login/introduction.mdx b/docs/authentication/unified-login/introduction.mdx index 177a615ded..1140f5936c 100644 --- a/docs/authentication/unified-login/introduction.mdx +++ b/docs/authentication/unified-login/introduction.mdx @@ -1,20 +1,10 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -pagination_prev: null -skip_llms_txt: true -description: >- - Authenticate multiple applications using SuperTokens and OAuth2 for unified - login across platforms. -page_type: overview -recipe: oauth2 -category: unified-login +description: Authenticate multiple applications using SuperTokens and OAuth2 for unified login across platforms. +sidebar: + order: 1 --- - -# Unified Login - ## Overview The **Unified Login** feature helps you in scenarios which involve different types of applications using a common **Authorization Server**. @@ -23,7 +13,9 @@ With it you can configure a common **OAuth2 Provider** that authenticates all yo ## Prerequisites - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: Before you can dive deeper in the functionality there are a few things to keep in mind: - The feature is available with the **SuperTokens Managed Service**. @@ -41,71 +33,34 @@ They organize the content based on the specific use case that you want to implem Before you explore a guide, read through the **OAuth2 Basics** page first. It explains concepts used in each tutorial. - - - - OAuth2 Basics
-
- - Go through a quick summary of the OAuth2 specifications to get accustomed with the language used in the quickstart guides. - -
- - - Applications with a common backend - - - Implement an authentication flow that involves multiple frontend applications that communicate with a common backend. - - - - - Applications with separate backends - - - Implement an authentication flow that involves multiple frontend applications that communicate with separate backends. - - - - - Common authentication for web and mobile - - - Use a common authentication service for both web and mobile applications. - - -
+ + +Go through a quick summary of the OAuth2 specifications to get accustomed with the language used in the quickstart guides. + + +Implement an authentication flow that involves multiple frontend applications that communicate with a common backend. + + +Implement an authentication flow that involves multiple frontend applications that communicate with separate backends. + + +Use a common authentication service for both web and mobile applications. + + ## Customization To adjust the functionality to fit your use case you can explore different sections from the documentation. - - - - Work with scopes - - - Discover the built-in scopes and see how you can override them. - - - - - Verify Tokens - - - Learn how to validate tokens. - - - - - Add custom claims in tokens - - - Modify the token payload with custom claims. - - - - - + + +Discover the built-in scopes and see how you can override them. + + +Learn how to validate tokens. + + +Modify the token payload with custom claims. + + diff --git a/docs/authentication/unified-login/meta.ts b/docs/authentication/unified-login/meta.ts new file mode 100644 index 0000000000..60687f0186 --- /dev/null +++ b/docs/authentication/unified-login/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Unified Login", + "icon": "share-2", + "order": 6 +}); diff --git a/docs/authentication/unified-login/oauth2-basics.mdx b/docs/authentication/unified-login/oauth2-basics.mdx index 9de64328ca..fe057328a3 100644 --- a/docs/authentication/unified-login/oauth2-basics.mdx +++ b/docs/authentication/unified-login/oauth2-basics.mdx @@ -1,21 +1,10 @@ --- title: OAuth2 Basics -hide_title: true -sidebar_position: 2 -toc_max_heading_level: 4 -description: >- - Authenticate multiple applications using SuperTokens and OAuth2 for unified - login across platforms. -page_type: guide -recipe: oauth2 -category: unified-login +description: Authenticate multiple applications using SuperTokens and OAuth2 for unified login across platforms. +sidebar: + order: 2 --- -import PaidFeatureCallout from './_blocks/paid-feature-callout.mdx' -import { Badge, HoverCard } from '@radix-ui/themes'; - -# OAuth2 basics - ## Overview Each quickstart guide uses OAuth2 specific concepts that you should be aware of. @@ -67,8 +56,7 @@ At the same time, tokens can provide more information about who the owner is. This is the main token that provides temporary access to protected resources. The **OAuth2 Access Token** should only be accessed and validated by the [**Resource Server**](#resource-server). -:::info -This token is different from the **SuperTokens Session Access Token**. +:::info[This token is different from the **SuperTokens Session Access Token**.] The latter functions in the **OAuth 2.0** authentication flows to maintain a session between the **authorization frontend** and the **authorization backend server**. ::: @@ -77,8 +65,7 @@ The latter functions in the **OAuth 2.0** authentication flows to maintain a ses A token that allows obtaining a new [**OAuth2 Access Token**](#oauth2-access-token) when the current one has expired. Using the refresh token does not require the user to re-authenticate. -:::info -This token is different from the **SuperTokens Session Refresh Token**. +:::info[This token is different from the **SuperTokens Session Refresh Token**.] The latter functions in the **OAuth 2.0** authentication flows to maintain a session between the **authorization frontend** and the **authorization backend server**. ::: @@ -108,7 +95,7 @@ Our implementation supports the following flow types: #### [Authorization Code Grant](https://oauth.net/2/grant-types/authorization-code/) -Authorization Code Grant +Authorization Code Grant This flow is best suited for scenarios that involve **web applications**. It consists of the following steps: @@ -133,7 +120,7 @@ This ensures that, even if the **Authorization Code** gets intercepted, it canno #### [Client credentials](https://oauth.net/2/grant-types/client-credentials/) -Client Credentials Grant +Client Credentials Grant This flow is best suited for **machine-to-machine** (M2M) interactions where there is no end-user. It consists of the following steps: diff --git a/docs/authentication/unified-login/quickstart-guides/_category_.json b/docs/authentication/unified-login/quickstart-guides/_category_.json deleted file mode 100644 index 1ecc161622..0000000000 --- a/docs/authentication/unified-login/quickstart-guides/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Quickstart Guides", - "position": 3 -} diff --git a/docs/authentication/unified-login/quickstart-guides/meta.ts b/docs/authentication/unified-login/quickstart-guides/meta.ts new file mode 100644 index 0000000000..84ae830ba0 --- /dev/null +++ b/docs/authentication/unified-login/quickstart-guides/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Quickstart Guides", + "icon": "zap", + "order": 3 +}); diff --git a/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend.mdx b/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend.mdx index 64ada82b5f..ee5e63f303 100644 --- a/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend.mdx +++ b/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend.mdx @@ -1,22 +1,10 @@ --- title: Multiple frontend domains with a common backend -hide_title: true -sidebar_position: 1 -toc_max_heading_level: 4 -description: >- - Implement OAuth2 authentication for multiple frontend domains using a shared - backend service. -page_type: tutorial -recipe: oauth2 -category: unified-login +description: Implement OAuth2 authentication for multiple frontend domains using a shared backend service. +sidebar: + order: 1 --- -import CreateOAuth2ClientRequest from "../_blocks/create-oauth2-client-request.mdx"; -import CustomUIGuide from "../_blocks/custom-ui-guide.mdx"; - - -# Multiple frontend domains with a common backend - ## Overview @@ -24,31 +12,33 @@ You can implement the following guide if you have multiple **`frontend applicati The authentication flow works in the following way: -## The User accesses the `frontend` application: - - The application `frontend` redirects the user to the **Authorization Service** backend, using the authorize URL. + +- The application `frontend` redirects the user to the **Authorization Service** backend, using the authorize URL. - The **Authorization Service** backend redirects the user to the login UI. - -## The User completes the login attempt: - - The **Authorization Service** backend redirects the user to the `callback URL`. - -## The user accesses the callback URL: - - The `frontend` uses the callback URL information to obtain a **OAuth2 Access Token** from the **Authorization Service** backend. - + + +- The **Authorization Service** backend redirects the user to the `callback URL`. + + +- The `frontend` uses the callback URL information to obtain a **OAuth2 Access Token** from the **Authorization Service** backend. + -Multiple Frontend Domains with a Single Backend +Multiple Frontend Domains with a Single Backend ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: -These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction). +These instructions assume that you already have gone through the main [quickstart guide](/quickstart/introduction). If you have skipped that page, please follow the tutorial and return here once you're done. :::info -If your frontend applications are on the same **domain**, but on different **sub-domains**, you can use [Session Sharing Across Subdomains](/docs/post-authentication/session-management/share-session-across-sub-domains). +If your frontend applications are on the same **domain**, but on different **sub-domains**, you can use [Session Sharing Across Subdomains](/post-authentication/session-management/share-session-across-sub-domains). ::: @@ -61,25 +51,243 @@ Go to the [**SuperTokens.com SaaS Dashboard**](https://supertokens.com/dashboard ### 2. Create the OAuth2 Clients -For each of your **`frontend`** applications create a separate [**OAuth2 client**](/docs/authentication/unified-login/oauth2-basics#client). +For each of your **`frontend`** applications create a separate [**OAuth2 client**](/authentication/unified-login/oauth2-basics#client). This can occur by directly calling the **SuperTokens Core** API. - + + + +```bash +curl --location --request POST '/recipe/oauth/clients' \ + --header 'api-key: ' \ + --header 'Content-Type: application/json; charset=utf-8' \ + --data ' + { + "clientName": "", + "responseTypes": ["code"], + "grantTypes": ["authorization_code", "refresh_token"], + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + } +' +``` + + + + + ```tsx + const BASE_URL = ''; + const API_KEY = ''; + + const url = `${BASE_URL}/recipe/oauth/clients`; + const options = { + method: 'POST', + headers: { + 'api-key': API_KEY, + 'Content-Type': 'application/json; charset=utf-8', + }, + body: JSON.stringify({ + clientName: "", + responseTypes: ["code"], + grantTypes: ["authorization_code", "refresh_token"], + scope: "offline_access ", + redirectUris: ["https:///oauth/callback"], + }) + }; + + fetch(url, options) + .then(response => response.json()) + .then(json => console.log(json)) + .catch(err => console.error(err)); +``` + + + + + ```go + + import ( + "fmt" + "net/http" + "strings" + "io" + ) + + func main() { + baseUrl := "" + apiKey := "" + url := fmt.Sprintf("%s/recipe/oauth/clients", baseUrl) + payload := `{ + "clientName": "", + "responseTypes": ["code"], + "grantTypes": ["authorization_code", "refresh_token"], + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + }` + + req, _ := http.NewRequest("POST", url, strings.NewReader(payload)) + + req.Header.Add("accept", "application/json") + req.Header.Add("api-key", apiKey) + req.Header.Add("content-type", "application/json") + + res, _ := http.DefaultClient.Do(req) + + defer res.Body.Close() + body, _ := io.ReadAll(res.Body) + + fmt.Println(string(body)) + } + ``` + + + + + ```python + import requests + from typing import Dict, Any + + BASE_URL = "" + API_KEY = "" + + url = f"{BASE_URL}/recipe/oauth/clients" + + payload: Dict[str, Any] ={ + "clientName": "", + "responseTypes": ["code"], + "grantTypes": ["authorization_code", "refresh_token"], + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + } + + headers = { + "api-key": API_KEY, + "Content-Type": "application/json", + } + + response = requests.post(url, json=payload, headers=headers) + + print(response.json()) + ``` + + + + + + Creates an OAuth2 client + + + + +**Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. + + + + + + + ## Request + + ### Body Schema + +| Name | Type | Description | Required | Default Value | +|--------------------------------------------|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------| +| `clientName` | `string` | A human-readable name of the client used for identification. | Yes | - | +| `grantTypes` | `array` of `GrantType` | The grant types that the Client uses. | Yes | - | +| `redirectUris` | `array` of `string` | List of URIs where the Authorization Server redirects after authorization. Can include mobile/desktop deep links. Must be exact URLs without wildcards. | Yes | - | | `scope` | `string` | Space-separated string of scopes the Client will request. Include `offline_access` to enable OAuth2 Refresh Token usage. | Yes | - | +| `scope` | `string` | String containing a space-separated list of scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use when requesting access tokens. Include the `offline_access` scope to exchange OAuth2 Refresh Tokens for OAuth2 Access Tokens | No | "" | +| `responseTypes` | `array` of `ResponseType` | The types of responses your client expects from the **Authorization Server** | No | - | +| `tokenEndpointAuthMethod` | `enum`(`"client_secret_basic"`, `"client_secret_post"`, `"private_key_jwt"`, `"none"`) | The requested client authentication method | No | `client_secret_basic` | +| `authorizationCodeGrantAccessTokenLifespan` | `Time Duration` | OAuth2 Access Token lifespan when using the Authorization Code grant flow. | No | `"1h"` | +| `authorizationCodeGrantIdTokenLifespan` | `Time Duration` | OAuth2 ID Token lifespan when using the Authorization Code grant flow. | No | `"1h"` | +| `authorizationCodeGrantRefreshTokenLifespan`| `Time Duration` | OAuth2 Refresh Token lifespan when using the Authorization Code grant flow. | If `refreshTokenGrantRefreshTokenLifespan` is also set | `"30d"` | +| `refreshTokenGrantRefreshTokenLifespan` | `Time Duration` | OAuth2 Refresh Token lifespan when using the Refresh Token grant flow. Must match `authorizationCodeGrantRefreshTokenLifespan`. | If `authorizationCodeGrantRefreshTokenLifespan` is also set | `"30d"` | +| `clientCredentialsGrantAccessTokenLifespan` | `Time Duration` | OAuth2 Access Token lifespan when using the Client Credentials grant flow. | No | `"1h"` | +| `enableRefreshTokenRotation` | `boolean` | Indicates that the refresh token is a one-time use. Set it to `false` to disable refresh token rotation. | No | `true` | + + +#### GrantType + +- `authorization_code`: allows exchanging the Authorization Code for an OAuth2 Access Token. +- `refresh_token`: allows exchanging the OAuth2 Refresh Token for an OAuth2 Access Token. +- `client_credentials`: allows the client to directly request an OAuth2 Access Token by authenticating itself with the Authorization Server using its own client credentials. +#### TokenEndpointAuthMethod -:::caution -You have to save the create OAuth2 Client response because this is not persisted internally for security reasons. +- `client_secret_basic`: uses the HTTP Basic Authentication scheme to authenticate the client. +- `client_secret_post`: uses the HTTP `POST` Authentication scheme to authenticate the client. +- `private_key_jwt`: uses JSON Web Tokens (JWT) to authenticate the client. +- `none`: indicates that the process of obtaining an OAuth2 Access Token does not use the client secret. Used for public clients (native apps or mobile apps). + +#### ResponseType + +- `code`: Indicates that the Client receives an Authorization Code that it exchanges for an OAuth2 Access Token. +- `id_token`: Indicates that the Client expects an ID Token. + +#### Time Duration + +A string value that signifies time duration in milliseconds, seconds, minutes, or hours: `"2000ms"`, `"60s"`, `"30m"`, `"1h"`. + +### Example + +```bash +curl -X POST /recipe/oauth/clients \ + -H "Content-Type: application/json" \ + -H "api-key: " \ + -d '{ + "clientName": "", + "responseTypes": ["code"], + "grantTypes": ["authorization_code", "refresh_token"], + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + }' +``` + +## Response + +### 200 + +The client has been successfully created. + +### Response schema + +| Property | Type | Description | +|-------------|----------------------------------|-----------------------------------------------| +| `clientName` | `string` | The name of the client. | +| `clientId` | `string` | Unique identifier for the client. | +| `clientSecret` | `string` | The secret is part of the create request as plain text, and then never again. The secret remains in hashed format and is not recoverable once lost. | +| `redirectUris` | `array` of `string` | The URLs used for redirection. | +| `audience` | `array` of `string` | Value used to identify for whom a token is issued. The created client can generate access token only for the specified audiences. | +| `scope` | `array` of `string` | A space separated string of scopes that the Client requests access to. | + +#### Example + +```json +{ + "clientName": "", + "clientId": "", + "redirectUris": ["https:///oauth/callback"], + "audience": [""], + "scope": ["offline_access "], +} +``` + + + + + + +:::warning[You have to save the create OAuth2 Client response because this is not persisted internally for security reasons.] The information is necessary in the next steps. ::: ### 3. Set up the Authorization Service Backend - #### 3.1 Initialize the OAuth2 recipe - - + + Update the `supertokens.init` call to include the new recipe. @@ -103,21 +311,19 @@ supertokens.init({ }); ``` - - - + -:::caution + -At the moment, there is no support for creating OAuth2 providers in the Go SDK. +:::warning[At the moment, there is no support for creating OAuth2 providers in the Go SDK.] ::: - + - + -```python +```python from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import oauth2provider @@ -138,19 +344,19 @@ init( ) ``` - + - + #### 3.2 Update the CORS configuration Set up the Backend API to allow requests from all the frontend domains. - + - + -```tsx +```tsx {12,13,14} import express from "express"; import cors from "cors"; import supertokens from "supertokens-node"; @@ -159,32 +365,28 @@ import { middleware } from "supertokens-node/framework/express"; const app = express(); // Add your actual frontend domains here -const allowedOrigins = ["^{appInfo.websiteDomain}", "", ""]; +const allowedOrigins = ["", "", ""]; app.use(cors({ - // highlight-start origin: allowedOrigins, allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()], credentials: true, - // highlight-end })); ``` - - - + -:::caution + -At the moment, there is no support for creating OAuth2 providers in the Go SDK. +:::warning[At the moment, there is no support for creating OAuth2 providers in the Go SDK.] ::: - + - + -```python +```python {12,13,14} from supertokens_python import get_all_cors_headers from fastapi import FastAPI from starlette.middleware.cors import CORSMiddleware @@ -196,11 +398,9 @@ app.add_middleware(get_middleware()) app.add_middleware( CORSMiddleware, - # highlight-start allow_origins=[ "", "", "" ], - # highlight-end allow_credentials=True, allow_methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], allow_headers=["Content-Type"] + get_all_cors_headers(), @@ -208,9 +408,9 @@ app.add_middleware( ``` - + - + #### 3.3 Implement a custom session verification function @@ -222,9 +422,9 @@ This is necessary because the flow uses two types of tokens: Hence the logic should distinguish between these two and prevent errors. - + - + Here is an example of how to implement this in the context of an Express API: @@ -278,7 +478,7 @@ async function verifySession(req: RequestWithUserId, res: Response, next: NextFu } const JWKS = jose.createRemoteJWKSet( - new URL("^{appInfo.apiDomain}^{appInfo.apiBasePath}/jwt/jwks.json"), + new URL("/auth/jwt/jwks.json"), ); // This is a basic example on how to validate an OAuth2 Token @@ -302,23 +502,21 @@ app.get("/protected", verifySession, async (req, res) => { }); ``` -For more information on how to verify the **OAuth2 Access Tokens**, please check the [separate guide](/docs/authentication/unified-login/verify-tokens). - - +For more information on how to verify the **OAuth2 Access Tokens**, please check the [separate guide](/authentication/unified-login/verify-tokens). - + -:::caution + -At the moment, there is no support for creating OAuth2 providers in the Go SDK. +:::warning[At the moment, there is no support for creating OAuth2 providers in the Go SDK.] ::: - + - + -```python +```python from supertokens_python.recipe.session.syncio import get_session from supertokens_python.recipe.session.exceptions import SuperTokensSessionError, TryRefreshTokenError from fastapi.requests import Request @@ -357,8 +555,8 @@ def verify_session(request: Request): def validate_token(token: str, required_scope: str) -> bool: - api_domain = "^{appInfo.apiDomain}" - api_base_path = "^{appInfo.apiBasePath}" + api_domain = "" + api_base_path = "/auth" client_id = "" jwks_url = f"{api_domain}{api_base_path}/jwt/jwks.json" @@ -392,23 +590,22 @@ def validate_token(token: str, required_scope: str) -> bool: # ``` - + - + ### 4. Configure the Authorization Service Frontend + - - - + #### 4.1 Initialize the recipe - + - + Add the import statement for the new recipe and update the list of recipe to also include the new initialization. @@ -430,9 +627,9 @@ SuperTokens.init({ ##### Include the pre-built UI in the rendering tree. - + - + ```tsx import React from 'react'; @@ -465,9 +662,9 @@ class App extends React.Component { } ``` - + - + ```tsx import React from 'react'; @@ -489,13 +686,13 @@ class App extends React.Component { } ``` - + - + - + - + Update the `AuthComponent` to include the `OAuth2Provider` recipe. You need to add a new item in the `recipeList` array. @@ -519,7 +716,7 @@ You need to add a new item in the `recipeList` array. ) { } ngAfterViewInit() { - this.loadScript('^{jsdeliver_prebuiltui}'); + this.loadScript('https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js'); } ngOnDestroy() { @@ -538,11 +735,11 @@ You need to add a new item in the `recipeList` array. script.onload = () => { supertokensUIInit({ appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ // Don't forget to also include the other recipes that you are already using @@ -555,9 +752,9 @@ You need to add a new item in the `recipeList` array. } ``` - + - + Update the `AuthView` component to include the `OAuth2Provider` recipe. @@ -578,11 +775,11 @@ You need to add a new item in the `recipeList` array, inside the `supertokensUII script.onload = () => { supertokensUIInit({ appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ // Don't forget to also include the other recipes that you are already using @@ -594,7 +791,7 @@ You need to add a new item in the `recipeList` array, inside the `supertokensUII }; onMounted(() => { - loadScript('^{jsdeliver_prebuiltui}'); + loadScript('https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js'); }); onUnmounted(() => { @@ -612,9 +809,9 @@ You need to add a new item in the `recipeList` array, inside the `supertokensUII ``` - + - + #### 4.2 Disable network interceptors @@ -629,16 +826,14 @@ Given that in the scenario you are implementing, the **OAuth2 Access Tokens** se The automatic request interception causes conflicts. To prevent this, you need to override the `shouldDoInterceptionBasedOnUrl` function in the `Session.init` call. -:::caution - -The code samples assume that you are using `^{appInfo.apiBasePath}` as the `apiBasePath` for the backend authentication routes. +:::warning[The code samples assume that you are using `/auth` as the `apiBasePath` for the backend authentication routes.] If that is different please adjust them based on your use case. ::: - + - + ```tsx import Session from "supertokens-auth-react/recipe/session"; @@ -652,8 +847,8 @@ Session.init({ try { let urlObj = new URL(url); // Interception should be done only for routes that need the SuperTokens Session Tokens - const isAuthApiRoute = urlObj.pathname.startsWith("^{appInfo.apiBasePath}"); - const isOAuth2ApiRoute = urlObj.pathname.startsWith("^{appInfo.apiBasePath}/oauth"); + const isAuthApiRoute = urlObj.pathname.startsWith("/auth"); + const isOAuth2ApiRoute = urlObj.pathname.startsWith("/auth/oauth"); if (!isAuthApiRoute || isOAuth2ApiRoute) { return false; } @@ -666,9 +861,9 @@ Session.init({ }) ``` - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: @@ -686,7 +881,7 @@ supertokensUISession.init({ shouldDoInterceptionBasedOnUrl: (url, apiDomain, sessionTokenBackendDomain) => { try { let urlObj = new URL(url); - if (!urlObj.pathname.startsWith("^{appInfo.apiBasePath}")) { + if (!urlObj.pathname.startsWith("/auth")) { return false; } } catch (ignored) { } @@ -711,7 +906,7 @@ Session.init({ shouldDoInterceptionBasedOnUrl: (url, apiDomain, sessionTokenBackendDomain) => { try { let urlObj = new URL(url); - if (!urlObj.pathname.startsWith("^{appInfo.apiBasePath}")) { + if (!urlObj.pathname.startsWith("/auth")) { return false; } } catch (ignored) { } @@ -723,9 +918,9 @@ Session.init({ }) ``` - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: @@ -743,7 +938,7 @@ supertokensUISession.init({ shouldDoInterceptionBasedOnUrl: (url, apiDomain, sessionTokenBackendDomain) => { try { let urlObj = new URL(url); - if (!urlObj.pathname.startsWith("^{appInfo.apiBasePath}")) { + if (!urlObj.pathname.startsWith("/auth")) { return false; } } catch (ignored) { } @@ -768,7 +963,7 @@ Session.init({ shouldDoInterceptionBasedOnUrl: (url, apiDomain, sessionTokenBackendDomain) => { try { let urlObj = new URL(url); - if (!urlObj.pathname.startsWith("^{appInfo.apiBasePath}")) { + if (!urlObj.pathname.startsWith("/auth")) { return false; } } catch (ignored) { } @@ -780,85 +975,342 @@ Session.init({ }) ``` - + - + -The code snippet only allows interception for API endpoints that start with `^{appInfo.apiBasePath}`. +The code snippet only allows interception for API endpoints that start with `/auth`. This ensures that calls made from the Frontend SDKs continue to use the **SuperTokens Session Tokens**. As a result, the authentication flow ends up working. For the other routes, you have full control on how you want to attach the **OAuth2 Access Tokens** to the API calls. - + + + + +The user interface that you are going to build should respect this flow: + + + +It's up to you how you want to handle this. +They can click a button to login or you can directly start the login flow. + + +A **OAuth2/OpenID Connect (OIDC)** library can execute this action. +Check the previous guides for information on what you could use. + + +The page URL contains a `loginChallenge` parameter that keeps track of the login attempt. +Besides that, the URL can also include a `forceFreshAuth` parameter. +As the name suggests, this should force the login UI to be visible even though the user has an existing valid session. +This guide shows you how to handle this. + + +The login UI should render based on instructions that are specific to each authentication method which you are using. +The additional thing that you have to do here is to consider the `forceFreshAuth` parameter. + + +After the user submits the login form, you need to redirect them to a specific route that sends them to the original application. +From here, the authentication flow completes. + + + +Let's see how you can actually implement this UI. + +#### 4.1 Configure the redirection URLs + +As it has hinted in the previous section, the **Authorization Service Backend** sends the user to different pages from the **Authorization Service Frontend**, based on the action that needs execution. + +The default values for these routes are: + +- The login page maps to `/auth` (this is also the place where a user ends up after logout) +- The token refresh page maps to `/auth/try-refresh` +- The logout page maps to `/auth/logout` + +If you want to change these routes, you need to add a custom override. + +:::info[This override needs addition to the **Authorization Service Backend**.] +::: + + + + + +```tsx +import OAuth2Provider from "supertokens-node/recipe/oauth2provider"; + +OAuth2Provider.init({ + override: { + functions: (originalFunctions) => ({ + ...originalFunctions, + getFrontendRedirectionURL: async (input) => { + const websiteDomain = ''; + const websiteBasePath = '/auth'; + + if (input.type === "login") { + const queryParams = new URLSearchParams({ + loginChallenge: input.loginChallenge, + }); + if (input.hint !== undefined) { + queryParams.set("hint", input.hint); + } + if (input.forceFreshAuth) { + queryParams.set("forceFreshAuth", "true"); + } + + return `/auth?${queryParams.toString()}`; + } else if (input.type === "try-refresh") { + return `/auth/try-refresh?loginChallenge=${input.loginChallenge}`; + } else if (input.type === "post-logout-fallback") { + return `/auth`; + } else if (input.type === "logout-confirmation") { + return `/auth/oauth/logout?logoutChallenge=${input.logoutChallenge}`; + } + + return `/auth`; + }, + }), + }, +}) + +``` + + + + + +:::warning[At the moment, there is no support for creating OAuth2 providers in the Go SDK.] + +::: + + + + + +:::warning[At the moment, there is no support for creating OAuth2 providers in the Python SDK.] + +::: + + + + + +#### 4.2 Handle the forceFreshAuth parameter + +Sometimes, even though there is an existing valid session in the **Authorization Service Frontend**, the requesting **Client** might force a new login attempt. +The `forceFreshAuth` parameter shows this. + +When the login page renders, you also need to check for this parameter. You are doing this to know if you need to show the login UI. + +Here is an example of how you can evaluate this case. + +```tsx +import Session from 'supertokens-web-js/recipe/session'; + +async function shouldLogin() { + const urlParams = new URLSearchParams(window.location.search); + const forceFreshAuth = urlParams.get('forceFreshAuth') as string; + if(forceFreshAuth === "true") return true; + + return Session.doesSessionExist(); +} + +``` + +:::info[Multi Tenancy] + +If you are using multi-tenancy, you also need to keep track of the `tenantId` query parameter and pass it between the **Authorization Service Frontend** pages. + +::: + +#### 4.3 Complete the login attempt + + +After the user submits the login form, you need to redirect them to a specific route to complete the **OAuth 2** flow. + +The following code sample shows you how to determine which URL to use. + + + + + +```tsx +import OAuth2Provider from "supertokens-web-js/recipe/oauth2provider"; + +async function getInitialRedirectionURL() { + const urlParams = new URLSearchParams(window.location.search); + const loginChallenge = urlParams.get('loginChallenge') as string; + const redirectionResponse = await OAuth2Provider.getRedirectURLToContinueOAuthFlow({ loginChallenge }); + if (redirectionResponse.status === "OK") { + return redirectionResponse.frontendRedirectTo; + } +} + +``` + + + + + +:::warning + +For mobile apps, you need to reuse the web authentication flow. Check this [guide](/authentication/unified-login/quickstart-guides/reuse-website-login) for more information. + +::: + + + + + +#### 4.4 Add the token refresh page + +To have support for token refreshing, you need to add a new page to your application. +The path should correspond to the one outlined during the first step. + +When the user ends up on this page, you need to use the `Session` recipe to perform the refresh action. +Then they need redirection to a page from your application. + +Here's a code sample that shows you how to do this. + + + + + +```tsx +import OAuth2Provider from "supertokens-web-js/recipe/oauth2provider"; +import Session from 'supertokens-web-js/recipe/session'; + +async function refreshToken() { + await Session.attemptRefreshingSession(); + const urlParams = new URLSearchParams(window.location.search); + const loginChallenge = urlParams.get('loginChallenge') as string; + const redirectionResponse = await OAuth2Provider.getRedirectURLToContinueOAuthFlow({ loginChallenge }); + if (redirectionResponse.status === "OK") { + window.location.href = redirectionResponse.frontendRedirectTo; + } +} + +``` + + + + + +:::warning + +For mobile apps, you need to reuse the web authentication flow. Check this [guide](/authentication/unified-login/quickstart-guides/reuse-website-login) for more information. + +::: + + + + + +#### 4.5 Add the logout page + +You need to add a logout page that users access when they want to end their session. +The path should correspond to the one outlined during the first step. + +The logout action should first ask the user for confirmation. +If the confirmation passes, then you can call the recipe function. +Based on the final response you can redirect the user to the provided redirection URL. + + + + + +```tsx +import OAuth2Provider from "supertokens-web-js/recipe/oauth2provider"; + +async function logout() { + const confirmation = confirm("Are you sure that you want to log out?"); + if(!confirmation) return; + + const urlParams = new URLSearchParams(window.location.search); + const logoutChallenge = urlParams.get('logoutChallenge') as string; + const redirectResponse = await OAuth2Provider.logOut({ logoutChallenge }); + window.location.href = redirectResponse.frontendRedirectTo; +} +``` + + + + + +:::warning + +For mobile apps, you need to reuse the web authentication flow. Check this [guide](/authentication/unified-login/quickstart-guides/reuse-website-login) for more information. + +::: - + - + - + ### 5. Update the login flow in your frontend applications Use a generic OAuth2 library to handle the login flow - + - + You can use the [react-oidc-context](https://github.com/authts/react-oidc-context) library. Follow the instructions from the library's page. Identify the configuration parameters based on the response received on **step 2**, when creating the **OAuth2 Client**. -- `authority` corresponds to the endpoint of the **Authorization Service** `^{appInfo.apiDomain}^{appInfo.apiBasePath}` +- `authority` corresponds to the endpoint of the **Authorization Service** `/auth` - `clientID` corresponds to `clientId` - `redirectUri` corresponds to a value from `callbackUrls` - `scope` corresponds to `scope` If you are using a multi-tenant setup, you also need to specify the `tenantId` parameter in the authorization URL. -To do this, set the `extraQueryParams` property with a specific value that should look like this: `{ tenant_id: "" }`. +To do this, set the `extraQueryParams` property with a specific value that should look like this: `{ tenant_id: "`<TENANT_ID>`" }`. - + - + You can use the [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc) library. Follow the instructions described in the [GitHub repository](https://github.com/manfredsteyer/angular-oauth2-oidc?tab=readme-ov-file#logging-in). Identify the configuration parameters based on the response received on **step 2**, when creating the **OAuth2 Client**. -- `issuer` corresponds to the endpoint of the **Authorization Service** `^{appInfo.apiDomain}^{appInfo.apiBasePath}` +- `issuer` corresponds to the endpoint of the **Authorization Service** `/auth` - `client_id` corresponds to `clientId` - `redirect_uri` corresponds to a value from `callbackUrls` - `scope` corresponds to `scope` If you are using a multi-tenant setup, you also need to specify the `tenantId` parameter in the authorization URL. -To do this, set the `extraQueryParams` property with a specific value that should look like this: `{ tenant_id: "" }`. +To do this, set the `extraQueryParams` property with a specific value that should look like this: `{ tenant_id: "`<TENANT_ID>`" }`. - + - + You can use the [oidc-client-ts](https://github.com/authts/oidc-client-ts?tab=readme-ov-file) library. -Follow the instructions described in the [GitHub repository](https://github.com/authts/oidc-client-ts/blob/main/docs/protocols/authorization-code-grant-with-pkce.md). +Follow the instructions described in the [GitHub repository](https://github.com/authts/oidc-client-ts/blob/main/docs/protocols/authorization-code-grant-with-pkce). Identify the configuration parameters based on the response received on **step 2**, when creating the **OAuth2 Client**. -- `issuer` corresponds to the endpoint of the **Authorization Service** `^{appInfo.apiDomain}^{appInfo.apiBasePath}` +- `issuer` corresponds to the endpoint of the **Authorization Service** `/auth` - `client_id` corresponds to `clientId` - `redirect_uri` corresponds to a value from `callbackUrls` - `scope` corresponds to `scope` If you are using a multi-tenant setup, you also need to specify the `tenantId` parameter in the authorization URL. -To do this, set the `extraQueryParams` property with a specific value that should look like this: `{ tenant_id: "" }`. +To do this, set the `extraQueryParams` property with a specific value that should look like this: `{ tenant_id: "`<TENANT_ID>`" }`. - + - + :::info -If you want to use the [**OAuth2 Refresh Tokens**](/docs/authentication/unified-login/oauth2-basics#oauth2-refresh-token) make sure to include the `offline_access` scope during the initialization step. +If you want to use the [**OAuth2 Refresh Tokens**](/authentication/unified-login/oauth2-basics#oauth2-refresh-token) make sure to include the `offline_access` scope during the initialization step. ::: diff --git a/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-separate-backends.mdx b/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-separate-backends.mdx index d0f2b01ca9..ac85acd95e 100644 --- a/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-separate-backends.mdx +++ b/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-separate-backends.mdx @@ -1,56 +1,47 @@ --- title: Multiple frontend domains with separate backends -hide_title: true -sidebar_position: 2 -description: >- - Set up multiple frontend domains with separate backends using OAuth2 - authentication. -page_type: tutorial -recipe: oauth2 -category: unified-login +description: Set up multiple frontend domains with separate backends using OAuth2 authentication. +sidebar: + order: 2 --- - -import CustomUIGuide from "../_blocks/custom-ui-guide.mdx"; -import CreateOAuth2ClientRequest from "../_blocks/create-oauth2-client-request.mdx"; - -# Multiple frontend domains with separate backends - ## Overview -You can use the following guide if you have a single [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server) that multiple applications use. +You can use the following guide if you have a single [**Authorization Service**](/authentication/unified-login/oauth2-basics#authorization-server) that multiple applications use. In turn, each app has separate **`frontend`** and **`backend`** instances that serve from different domains. The authentication flow works in the following way: ## The User accesses the `frontend` app - The application `frontend` calls a login endpoint on the `backend` application. - - The `backend` application generates an `authorization` URL to the [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server) and redirects the user to it. - - The [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server) backend redirects the user to the login UI + - The `backend` application generates an `authorization` URL to the [**Authorization Service**](/authentication/unified-login/oauth2-basics#authorization-server) and redirects the user to it. + - The [**Authorization Service**](/authentication/unified-login/oauth2-basics#authorization-server) backend redirects the user to the login UI ## The User completes the login attempt - - The [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server) backend redirects the user to a `callback URL` that includes the **Authorization Code**. + - The [**Authorization Service**](/authentication/unified-login/oauth2-basics#authorization-server) backend redirects the user to a `callback URL` that includes the **Authorization Code**. ## The user accesses the callback URL - The **Authentication Code** gets sent to the application `backend` - - The `backend` exchanges the **Authentication Code** for an [**OAuth2 Access Token**](/docs/authentication/unified-login/oauth2-basics#oauth2-access-token) + - The `backend` exchanges the **Authentication Code** for an [**OAuth2 Access Token**](/authentication/unified-login/oauth2-basics#oauth2-access-token) - The `backend` saves the received token in a server session and sends it back to the `frontend` as a cookie. The `frontend` can use the new cookie to access protected resources from the `backend`. -Multiple Frontend Domains with separate Backends +Multiple Frontend Domains with separate Backends ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: -These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction). +These instructions assume that you already have gone through the main [quickstart guide](/quickstart/introduction). If you have skipped that page, please follow the tutorial and return here once you're done. :::info -Note that, if the *frontends* and *backends* are in different *sub domains*, you don't need to use *OAuth* and can instead use [session sharing across sub domains](/docs/post-authentication/session-management/share-session-across-sub-domains). +Note that, if the *frontends* and *backends* are in different *sub domains*, you don't need to use *OAuth* and can instead use [session sharing across sub domains](/post-authentication/session-management/share-session-across-sub-domains). ::: @@ -64,31 +55,250 @@ Go to the [**SuperTokens.com SaaS Dashboard**](https://supertokens.com/dashboard ### 2. Create the OAuth2 Clients -For each of your applications you need to create a separate [**OAuth2 client**](/docs/authentication/unified-login/oauth2-basics#client). +For each of your applications you need to create a separate [**OAuth2 client**](/authentication/unified-login/oauth2-basics#client). You can do this by directly calling the **SuperTokens Core** API. - + + + +```bash +curl --location --request POST '/recipe/oauth/clients' \ + --header 'api-key: ' \ + --header 'Content-Type: application/json; charset=utf-8' \ + --data ' + { + "clientName": "", + "responseTypes": ["code"], + "grantTypes": ["authorization_code", "refresh_token"], + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + } +' +``` + + + + + ```tsx + const BASE_URL = ''; + const API_KEY = ''; + + const url = `${BASE_URL}/recipe/oauth/clients`; + const options = { + method: 'POST', + headers: { + 'api-key': API_KEY, + 'Content-Type': 'application/json; charset=utf-8', + }, + body: JSON.stringify({ + clientName: "", + responseTypes: ["code"], + grantTypes: ["authorization_code", "refresh_token"], + scope: "offline_access ", + redirectUris: ["https:///oauth/callback"], + }) + }; + + fetch(url, options) + .then(response => response.json()) + .then(json => console.log(json)) + .catch(err => console.error(err)); +``` + + + + + ```go + + import ( + "fmt" + "net/http" + "strings" + "io" + ) + + func main() { + baseUrl := "" + apiKey := "" + url := fmt.Sprintf("%s/recipe/oauth/clients", baseUrl) + payload := `{ + "clientName": "", + "responseTypes": ["code"], + "grantTypes": ["authorization_code", "refresh_token"], + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + }` + + req, _ := http.NewRequest("POST", url, strings.NewReader(payload)) + + req.Header.Add("accept", "application/json") + req.Header.Add("api-key", apiKey) + req.Header.Add("content-type", "application/json") + + res, _ := http.DefaultClient.Do(req) + + defer res.Body.Close() + body, _ := io.ReadAll(res.Body) + + fmt.Println(string(body)) + } + ``` + + + + + ```python + import requests + from typing import Dict, Any + + BASE_URL = "" + API_KEY = "" + + url = f"{BASE_URL}/recipe/oauth/clients" + + payload: Dict[str, Any] ={ + "clientName": "", + "responseTypes": ["code"], + "grantTypes": ["authorization_code", "refresh_token"], + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + } + + headers = { + "api-key": API_KEY, + "Content-Type": "application/json", + } + + response = requests.post(url, json=payload, headers=headers) + + print(response.json()) + ``` + + + + + + Creates an OAuth2 client + + + + +**Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. + + + + + + + ## Request + + ### Body Schema + +| Name | Type | Description | Required | Default Value | +|--------------------------------------------|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------| +| `clientName` | `string` | A human-readable name of the client used for identification. | Yes | - | +| `grantTypes` | `array` of `GrantType` | The grant types that the Client uses. | Yes | - | +| `redirectUris` | `array` of `string` | List of URIs where the Authorization Server redirects after authorization. Can include mobile/desktop deep links. Must be exact URLs without wildcards. | Yes | - | | `scope` | `string` | Space-separated string of scopes the Client will request. Include `offline_access` to enable OAuth2 Refresh Token usage. | Yes | - | +| `scope` | `string` | String containing a space-separated list of scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use when requesting access tokens. Include the `offline_access` scope to exchange OAuth2 Refresh Tokens for OAuth2 Access Tokens | No | "" | +| `responseTypes` | `array` of `ResponseType` | The types of responses your client expects from the **Authorization Server** | No | - | +| `tokenEndpointAuthMethod` | `enum`(`"client_secret_basic"`, `"client_secret_post"`, `"private_key_jwt"`, `"none"`) | The requested client authentication method | No | `client_secret_basic` | +| `authorizationCodeGrantAccessTokenLifespan` | `Time Duration` | OAuth2 Access Token lifespan when using the Authorization Code grant flow. | No | `"1h"` | +| `authorizationCodeGrantIdTokenLifespan` | `Time Duration` | OAuth2 ID Token lifespan when using the Authorization Code grant flow. | No | `"1h"` | +| `authorizationCodeGrantRefreshTokenLifespan`| `Time Duration` | OAuth2 Refresh Token lifespan when using the Authorization Code grant flow. | If `refreshTokenGrantRefreshTokenLifespan` is also set | `"30d"` | +| `refreshTokenGrantRefreshTokenLifespan` | `Time Duration` | OAuth2 Refresh Token lifespan when using the Refresh Token grant flow. Must match `authorizationCodeGrantRefreshTokenLifespan`. | If `authorizationCodeGrantRefreshTokenLifespan` is also set | `"30d"` | +| `clientCredentialsGrantAccessTokenLifespan` | `Time Duration` | OAuth2 Access Token lifespan when using the Client Credentials grant flow. | No | `"1h"` | +| `enableRefreshTokenRotation` | `boolean` | Indicates that the refresh token is a one-time use. Set it to `false` to disable refresh token rotation. | No | `true` | + + +#### GrantType + +- `authorization_code`: allows exchanging the Authorization Code for an OAuth2 Access Token. +- `refresh_token`: allows exchanging the OAuth2 Refresh Token for an OAuth2 Access Token. +- `client_credentials`: allows the client to directly request an OAuth2 Access Token by authenticating itself with the Authorization Server using its own client credentials. -:::caution -You have to save the create OAuth2 Client response because this is not persisted internally for security reasons. +#### TokenEndpointAuthMethod + +- `client_secret_basic`: uses the HTTP Basic Authentication scheme to authenticate the client. +- `client_secret_post`: uses the HTTP `POST` Authentication scheme to authenticate the client. +- `private_key_jwt`: uses JSON Web Tokens (JWT) to authenticate the client. +- `none`: indicates that the process of obtaining an OAuth2 Access Token does not use the client secret. Used for public clients (native apps or mobile apps). + +#### ResponseType + +- `code`: Indicates that the Client receives an Authorization Code that it exchanges for an OAuth2 Access Token. +- `id_token`: Indicates that the Client expects an ID Token. + +#### Time Duration + +A string value that signifies time duration in milliseconds, seconds, minutes, or hours: `"2000ms"`, `"60s"`, `"30m"`, `"1h"`. + +### Example + +```bash +curl -X POST /recipe/oauth/clients \ + -H "Content-Type: application/json" \ + -H "api-key: " \ + -d '{ + "clientName": "", + "responseTypes": ["code"], + "grantTypes": ["authorization_code", "refresh_token"], + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + }' +``` + +## Response + +### 200 + +The client has been successfully created. + +### Response schema + +| Property | Type | Description | +|-------------|----------------------------------|-----------------------------------------------| +| `clientName` | `string` | The name of the client. | +| `clientId` | `string` | Unique identifier for the client. | +| `clientSecret` | `string` | The secret is part of the create request as plain text, and then never again. The secret remains in hashed format and is not recoverable once lost. | +| `redirectUris` | `array` of `string` | The URLs used for redirection. | +| `audience` | `array` of `string` | Value used to identify for whom a token is issued. The created client can generate access token only for the specified audiences. | +| `scope` | `array` of `string` | A space separated string of scopes that the Client requests access to. | + +#### Example + +```json +{ + "clientName": "", + "clientId": "", + "redirectUris": ["https:///oauth/callback"], + "audience": [""], + "scope": ["offline_access "], +} +``` + + + + + +:::warning[You have to save the create OAuth2 Client response because this is not persisted internally for security reasons.] The information is necessary for the next steps. ::: ### 3. Set Up your Authorization Service backend -In your [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server) you need to initialize the **OAuth2Provider** recipe. -The recipe exposes the endpoints needed for enabling the [**OAuth 2.0**](/docs/authentication/unified-login/oauth2-basics) flow. +In your [**Authorization Service**](/authentication/unified-login/oauth2-basics#authorization-server) you need to initialize the **OAuth2Provider** recipe. +The recipe exposes the endpoints needed for enabling the [**OAuth 2.0**](/authentication/unified-login/oauth2-basics) flow. - - + + Update the `supertokens.init` call to include the `OAuth2Provider` recipe. Add the import statement for the recipe and update the list of recipes with the new initialization step. -```tsx +```tsx import supertokens from "supertokens-node"; import OAuth2Provider from "supertokens-node/recipe/oauth2provider"; @@ -108,21 +318,19 @@ supertokens.init({ }); ``` - - - + -:::caution + -At the moment there is no support for creating OAuth2 providers in the Go SDK. +:::warning[At the moment there is no support for creating OAuth2 providers in the Go SDK.] ::: - + - + -```python +```python from supertokens_python import init, InputAppInfo, SupertokensConfig from supertokens_python.recipe import oauth2provider @@ -143,22 +351,22 @@ init( ) ``` - + - + ### 4. Configure the Authorization Service frontend - + - + #### 4.1 Initialize the recipe - + - + Add the import statement for the new recipe and update the list of recipe to also include the new initialization. @@ -180,9 +388,9 @@ SuperTokens.init({ #### 4.2 Include the pre-built UI in the rendering tree. - + - + ```tsx import React from 'react'; @@ -215,9 +423,9 @@ class App extends React.Component { } ``` - + - + ```tsx import React from 'react'; @@ -239,13 +447,13 @@ class App extends React.Component { } ``` - + - + - + - + Update the `AuthComponent` to include the `OAuth2Provider` recipe. You need to add a new item in the `recipeList` array. @@ -269,7 +477,7 @@ You need to add a new item in the `recipeList` array. ) { } ngAfterViewInit() { - this.loadScript('^{prebuiltUIVersion}'); + this.loadScript('https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js'); } ngOnDestroy() { @@ -288,11 +496,11 @@ You need to add a new item in the `recipeList` array. script.onload = () => { supertokensUIInit({ appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ // Don't forget to also include the other recipes that you are already using @@ -306,9 +514,9 @@ You need to add a new item in the `recipeList` array. ``` - + - + Update the `AuthView` component to include the `OAuth2Provider` recipe. @@ -329,11 +537,11 @@ You need to add a new item in the `recipeList` array, inside the `supertokensUII script.onload = () => { supertokensUIInit({ appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" }, recipeList: [ // Don't forget to also include the other recipes that you are already using @@ -345,7 +553,7 @@ You need to add a new item in the `recipeList` array, inside the `supertokensUII }; onMounted(() => { - loadScript('^{prebuiltUIVersion}'); + loadScript('https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js'); }); onUnmounted(() => { @@ -364,24 +572,281 @@ You need to add a new item in the `recipeList` array, inside the `supertokensUII ``` - + - + + + + + +The user interface that you are going to build should respect this flow: + + + +It's up to you how you want to handle this. +They can click a button to login or you can directly start the login flow. + + +A **OAuth2/OpenID Connect (OIDC)** library can execute this action. +Check the previous guides for information on what you could use. + + +The page URL contains a `loginChallenge` parameter that keeps track of the login attempt. +Besides that, the URL can also include a `forceFreshAuth` parameter. +As the name suggests, this should force the login UI to be visible even though the user has an existing valid session. +This guide shows you how to handle this. + + +The login UI should render based on instructions that are specific to each authentication method which you are using. +The additional thing that you have to do here is to consider the `forceFreshAuth` parameter. + + +After the user submits the login form, you need to redirect them to a specific route that sends them to the original application. +From here, the authentication flow completes. + + + +Let's see how you can actually implement this UI. + +#### 4.1 Configure the redirection URLs + +As it has hinted in the previous section, the **Authorization Service Backend** sends the user to different pages from the **Authorization Service Frontend**, based on the action that needs execution. + +The default values for these routes are: + +- The login page maps to `/auth` (this is also the place where a user ends up after logout) +- The token refresh page maps to `/auth/try-refresh` +- The logout page maps to `/auth/logout` + +If you want to change these routes, you need to add a custom override. + +:::info[This override needs addition to the **Authorization Service Backend**.] +::: + + + + + +```tsx +import OAuth2Provider from "supertokens-node/recipe/oauth2provider"; + +OAuth2Provider.init({ + override: { + functions: (originalFunctions) => ({ + ...originalFunctions, + getFrontendRedirectionURL: async (input) => { + const websiteDomain = ''; + const websiteBasePath = '/auth'; + + if (input.type === "login") { + const queryParams = new URLSearchParams({ + loginChallenge: input.loginChallenge, + }); + if (input.hint !== undefined) { + queryParams.set("hint", input.hint); + } + if (input.forceFreshAuth) { + queryParams.set("forceFreshAuth", "true"); + } + + return `/auth?${queryParams.toString()}`; + } else if (input.type === "try-refresh") { + return `/auth/try-refresh?loginChallenge=${input.loginChallenge}`; + } else if (input.type === "post-logout-fallback") { + return `/auth`; + } else if (input.type === "logout-confirmation") { + return `/auth/oauth/logout?logoutChallenge=${input.logoutChallenge}`; + } + + return `/auth`; + }, + }), + }, +}) + +``` + + + + + +:::warning[At the moment, there is no support for creating OAuth2 providers in the Go SDK.] + +::: + + + + + +:::warning[At the moment, there is no support for creating OAuth2 providers in the Python SDK.] + +::: + + + + + +#### 4.2 Handle the forceFreshAuth parameter + +Sometimes, even though there is an existing valid session in the **Authorization Service Frontend**, the requesting **Client** might force a new login attempt. +The `forceFreshAuth` parameter shows this. + +When the login page renders, you also need to check for this parameter. You are doing this to know if you need to show the login UI. + +Here is an example of how you can evaluate this case. + +```tsx +import Session from 'supertokens-web-js/recipe/session'; + +async function shouldLogin() { + const urlParams = new URLSearchParams(window.location.search); + const forceFreshAuth = urlParams.get('forceFreshAuth') as string; + if(forceFreshAuth === "true") return true; + + return Session.doesSessionExist(); +} + +``` + +:::info[Multi Tenancy] + +If you are using multi-tenancy, you also need to keep track of the `tenantId` query parameter and pass it between the **Authorization Service Frontend** pages. + +::: + +#### 4.3 Complete the login attempt + + +After the user submits the login form, you need to redirect them to a specific route to complete the **OAuth 2** flow. + +The following code sample shows you how to determine which URL to use. + + + + + +```tsx +import OAuth2Provider from "supertokens-web-js/recipe/oauth2provider"; + +async function getInitialRedirectionURL() { + const urlParams = new URLSearchParams(window.location.search); + const loginChallenge = urlParams.get('loginChallenge') as string; + const redirectionResponse = await OAuth2Provider.getRedirectURLToContinueOAuthFlow({ loginChallenge }); + if (redirectionResponse.status === "OK") { + return redirectionResponse.frontendRedirectTo; + } +} + +``` + + + + + +:::warning + +For mobile apps, you need to reuse the web authentication flow. Check this [guide](/authentication/unified-login/quickstart-guides/reuse-website-login) for more information. + +::: + + + + + +#### 4.4 Add the token refresh page + +To have support for token refreshing, you need to add a new page to your application. +The path should correspond to the one outlined during the first step. + +When the user ends up on this page, you need to use the `Session` recipe to perform the refresh action. +Then they need redirection to a page from your application. + +Here's a code sample that shows you how to do this. + + + + + +```tsx +import OAuth2Provider from "supertokens-web-js/recipe/oauth2provider"; +import Session from 'supertokens-web-js/recipe/session'; + +async function refreshToken() { + await Session.attemptRefreshingSession(); + const urlParams = new URLSearchParams(window.location.search); + const loginChallenge = urlParams.get('loginChallenge') as string; + const redirectionResponse = await OAuth2Provider.getRedirectURLToContinueOAuthFlow({ loginChallenge }); + if (redirectionResponse.status === "OK") { + window.location.href = redirectionResponse.frontendRedirectTo; + } +} + +``` + + + + + +:::warning + +For mobile apps, you need to reuse the web authentication flow. Check this [guide](/authentication/unified-login/quickstart-guides/reuse-website-login) for more information. + +::: + + + + + +#### 4.5 Add the logout page + +You need to add a logout page that users access when they want to end their session. +The path should correspond to the one outlined during the first step. + +The logout action should first ask the user for confirmation. +If the confirmation passes, then you can call the recipe function. +Based on the final response you can redirect the user to the provided redirection URL. + + + + + +```tsx +import OAuth2Provider from "supertokens-web-js/recipe/oauth2provider"; + +async function logout() { + const confirmation = confirm("Are you sure that you want to log out?"); + if(!confirmation) return; + + const urlParams = new URLSearchParams(window.location.search); + const logoutChallenge = urlParams.get('logoutChallenge') as string; + const redirectResponse = await OAuth2Provider.logOut({ logoutChallenge }); + window.location.href = redirectResponse.frontendRedirectTo; +} +``` + + + + + +:::warning + +For mobile apps, you need to reuse the web authentication flow. Check this [guide](/authentication/unified-login/quickstart-guides/reuse-website-login) for more information. + +::: - + - - - + + ### 5. Set up session handling in each application In each of your individual `applications` you need to set up logic for handling the **OAuth 2.0** authentication flow. You can use a generic **OIDC** or **OAuth2** library to do this. - + - + You can use the [passport-oauth2](https://www.passportjs.org/packages/passport-oauth2/) library. Follow the instructions on the library's page and set up your application `backend`. @@ -397,9 +862,9 @@ You can determine the configuration parameters based on the response received in Make sure that you expose an endpoint that calls `passport.authenticate('oauth2')`. This way the user ends up accessing the actual login page served by the **Authorization Service**. - + - + You can use the [OAuth2](https://pkg.go.dev/golang.org/x/oauth2) library. Follow these [instructions](https://golang.org/pkg/golang.org/x/oauth2/#example-Config-RequestToken) and implement it in your `backend`. @@ -414,9 +879,9 @@ You can determine the configuration parameters based on the response received in Make sure that you expose an endpoint that redirects to the authentication URL obtained from calling `AuthCodeURL`. This way the user ends up accessing the actual login page served by the **Authorization Service**. - + - + You can use the [AuthLib](https://docs.authlib.org/) library. Follow these [instructions](https://docs.authlib.org/en/latest/client/oauth2.html) and implement it in your `backend`. @@ -431,9 +896,9 @@ You can determine the configuration parameters based on the response received in Make sure that you expose an endpoint that redirects to the authentication URL obtained from calling `create_authorization_url`. This way the user ends up accessing the actual login page served by the **Authorization Service**. - + - + You can use the [League OAuth2 Client](https://github.com/thephpleague/oauth2-client) library. Follow these [instructions](https://oauth2-client.thephpleague.com/usage/) and implement it in your `backend`. @@ -448,9 +913,9 @@ You can determine the configuration parameters based on the response received in Make sure that you expose an endpoint that redirects to the authentication URL obtained from calling `getAuthorizationUrl`. This way the user ends up accessing the actual login page served by the **Authorization Service**. - + - + You can use the [Spring Security](https://github.com/spring-projects/spring-security) library. Follow these [instructions](https://docs.spring.io/spring-security/reference/servlet/oauth2/index.html#oauth2-client-log-users-in) and implement it in your `backend`. @@ -460,18 +925,18 @@ You can determine the configuration parameters based on the response received in - `client-id` corresponds to `clientId` - `client-secret` corresponds to `clientSecret` - `scope` corresponds to `scope` -- `issuer-uri` corresponds to `^{appInfo.apiDomain}^{appInfo.apiBasePath}` +- `issuer-uri` corresponds to `/auth` - + - + You can use the [IdentityModel](https://github.com/IdentityModel/IdentityModel) library. Follow these [instructions](https://identitymodel.readthedocs.io/en/latest/client/token.html#requesting-a-token-using-the-authorization-code-grant-type) and implement it in your `backend`. You can determine the configuration parameters based on the response received in **step 2**. -- `Address` corresponds to `^{appInfo.apiDomain}^{appInfo.apiBasePath}` +- `Address` corresponds to `/auth` - `ClientId` corresponds to `clientId` - `ClientSecret` corresponds to `clientSecret` - `RedirectUri` corresponds to a value from `callbackUrls` @@ -479,13 +944,13 @@ You can determine the configuration parameters based on the response received in Make sure that you expose an endpoint that redirects to the authentication URL obtained by using [this example](https://identitymodel.readthedocs.io/en/latest/misc/request_url.html#authorization-endpoint). This way the user ends up accessing the actual login page served by the **Authorization Service**. - + - + :::info -If you want to use the [**OAuth2 Refresh Tokens**](/docs/authentication/unified-login/oauth2-basics#oauth2-refresh-token) make sure to include the `offline_access` scope during the initialization step. +If you want to use the [**OAuth2 Refresh Tokens**](/authentication/unified-login/oauth2-basics#oauth2-refresh-token) make sure to include the `offline_access` scope during the initialization step. ::: @@ -495,7 +960,7 @@ In your `frontend` applications you need to add a login action that directs the The user should first redirect to the `backend` authentication endpoint defined during the previous step. There the `backend` generates a safe `authorization` URL using the **OAuth2** library and then redirects the user there. -After the user has logged in from the [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server) they redirect to the `backend` callback URL. +After the user has logged in from the [**Authorization Service**](/authentication/unified-login/oauth2-basics#authorization-server) they redirect to the `backend` callback URL. Then the `backend` creates the authentication session and sends it to the user agent as a cookie. ### 7. Test the new authentication flow diff --git a/docs/authentication/unified-login/quickstart-guides/reuse-website-login.mdx b/docs/authentication/unified-login/quickstart-guides/reuse-website-login.mdx index cd1f7ca09f..f7dd3788d4 100644 --- a/docs/authentication/unified-login/quickstart-guides/reuse-website-login.mdx +++ b/docs/authentication/unified-login/quickstart-guides/reuse-website-login.mdx @@ -1,19 +1,10 @@ --- title: Reuse website login for desktop and mobile apps -hide_title: true -sidebar_position: 3 description: Implement web authentication for desktop and mobile apps using OAuth2 -page_type: tutorial -recipe: oauth2 -category: unified-login +sidebar: + order: 3 --- - -import CreateOAuth2ClientRequest from "../_blocks/create-oauth2-client-request-no-auth.mdx"; - -# Reuse website login for desktop and mobile apps - - ## Overview This pattern is useful if you want to have the same web authentication experience for your desktop and mobile apps. @@ -24,26 +15,29 @@ The authentication flow works in the following way: -## User accesses the native application - - The user gets redirected to [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server) authentication URL. - - The [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server) redirects the user to the login UI - -## User completes the login attempt - - The [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server) backend redirects the user to the `callback URL`. + +- The user gets redirected to [**Authorization Service**](/authentication/unified-login/oauth2-basics#authorization-server) authentication URL. + - The [**Authorization Service**](/authentication/unified-login/oauth2-basics#authorization-server) redirects the user to the login UI + + +- The [**Authorization Service**](/authentication/unified-login/oauth2-basics#authorization-server) backend redirects the user to the `callback URL`. - This URL should be a deep link that your actual application can open. - -## The application uses the callback URL information to request a **OAuth2 Access Token** from the [**Authorization Service**](/docs/authentication/unified-login/oauth2-basics#authorization-server). - - The application saves the returned token. + + +- The application saves the returned token. + -Reuse website login for desktop and mobile apps +Reuse website login for desktop and mobile apps ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: -These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction). +These instructions assume that you already have gone through the main [quickstart guide](/quickstart/introduction). If you have skipped that page, please follow the tutorial and return here once you're done. ## Steps @@ -56,45 +50,268 @@ Go to the [**SuperTokens.com SaaS Dashboard**](https://supertokens.com/dashboard ### 2. Create the OAuth2 Clients -For each of your applications you need to create a separate [**OAuth2 client**](/docs/authentication/unified-login/oauth2-basics#client). +For each of your applications you need to create a separate [**OAuth2 client**](/authentication/unified-login/oauth2-basics#client). You can do this by directly calling the **SuperTokens Core** API. - + + + +```bash +curl --location --request POST '/recipe/oauth/clients' \ + --header 'api-key: ' \ + --header 'Content-Type: application/json; charset=utf-8' \ + --data ' + { + "clientName": "", + "responseTypes": ["code", "id_token"], + "grantTypes": ["authorization_code", "refresh_token"], + "tokenEndpointAuthMethod": "none", + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + } +' +``` + + + + + ```tsx + const BASE_URL = ''; + const API_KEY = ''; + + const url = `${BASE_URL}/recipe/oauth/clients`; + const options = { + method: 'POST', + headers: { + 'api-key': API_KEY, + 'Content-Type': 'application/json; charset=utf-8', + }, + body: JSON.stringify({ + clientName: "", + responseTypes: ["code", "id_token"], + grantTypes: ["authorization_code", "refresh_token"], + tokenEndpointAuthMethod: "none", + scope: "offline_access ", + redirectUris: ["https:///oauth/callback"], + }) + }; + + fetch(url, options) + .then(response => response.json()) + .then(json => console.log(json)) + .catch(err => console.error(err)); +``` + + + + + ```go + + import ( + "fmt" + "net/http" + "strings" + "io" + ) + + func main() { + baseUrl := "" + apiKey := "" + url := fmt.Sprintf("%s/recipe/oauth/clients", baseUrl) + payload := `{ + "clientName": "", + "responseTypes": ["code", "id_token"], + "grantTypes": ["authorization_code", "refresh_token"], + "tokenEndpointAuthMethod": "none", + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + }` + + req, _ := http.NewRequest("POST", url, strings.NewReader(payload)) + + req.Header.Add("accept", "application/json") + req.Header.Add("api-key", apiKey) + req.Header.Add("content-type", "application/json") + + res, _ := http.DefaultClient.Do(req) + + defer res.Body.Close() + body, _ := io.ReadAll(res.Body) + + fmt.Println(string(body)) + } + ``` + + + + + ```python + import requests + from typing import Dict, Any + + BASE_URL = "" + API_KEY = "" + + url = f"{BASE_URL}/recipe/oauth/clients" + + payload: Dict[str, Any] ={ + "clientName": "", + "responseTypes": ["code", "id_token"], + "grantTypes": ["authorization_code", "refresh_token"], + "tokenEndpointAuthMethod": "none", + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + } + + headers = { + "api-key": API_KEY, + "Content-Type": "application/json", + } + + response = requests.post(url, json=payload, headers=headers) + + print(response.json()) + ``` + + + + + + Creates an OAuth2 client + + + + +**Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. + + + + + + + ## Request + + ### Body Schema + +| Name | Type | Description | Required | Default Value | +|--------------------------------------------|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------| +| `clientName` | `string` | A human-readable name of the client used for identification. | Yes | - | +| `grantTypes` | `array` of `GrantType` | The grant types that the Client uses. | Yes | - | +| `redirectUris` | `array` of `string` | List of URIs where the Authorization Server redirects after authorization. Can include mobile/desktop deep links. Must be exact URLs without wildcards. | Yes | - | | `scope` | `string` | Space-separated string of scopes the Client will request. Include `offline_access` to enable OAuth2 Refresh Token usage. | Yes | - | +| `scope` | `string` | String containing a space-separated list of scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use when requesting access tokens. Include the `offline_access` scope to exchange OAuth2 Refresh Tokens for OAuth2 Access Tokens | No | "" | +| `responseTypes` | `array` of `ResponseType` | The types of responses your client expects from the **Authorization Server** | No | - | +| `tokenEndpointAuthMethod` | `enum`(`"client_secret_basic"`, `"client_secret_post"`, `"private_key_jwt"`, `"none"`) | The requested client authentication method | No | `client_secret_basic` | +| `authorizationCodeGrantAccessTokenLifespan` | `Time Duration` | OAuth2 Access Token lifespan when using the Authorization Code grant flow. | No | `"1h"` | +| `authorizationCodeGrantIdTokenLifespan` | `Time Duration` | OAuth2 ID Token lifespan when using the Authorization Code grant flow. | No | `"1h"` | +| `authorizationCodeGrantRefreshTokenLifespan`| `Time Duration` | OAuth2 Refresh Token lifespan when using the Authorization Code grant flow. | If `refreshTokenGrantRefreshTokenLifespan` is also set | `"30d"` | +| `refreshTokenGrantRefreshTokenLifespan` | `Time Duration` | OAuth2 Refresh Token lifespan when using the Refresh Token grant flow. Must match `authorizationCodeGrantRefreshTokenLifespan`. | If `authorizationCodeGrantRefreshTokenLifespan` is also set | `"30d"` | +| `clientCredentialsGrantAccessTokenLifespan` | `Time Duration` | OAuth2 Access Token lifespan when using the Client Credentials grant flow. | No | `"1h"` | +| `enableRefreshTokenRotation` | `boolean` | Indicates that the refresh token is a one-time use. Set it to `false` to disable refresh token rotation. | No | `true` | + + +#### GrantType + +- `authorization_code`: allows exchanging the Authorization Code for an OAuth2 Access Token. +- `refresh_token`: allows exchanging the OAuth2 Refresh Token for an OAuth2 Access Token. +- `client_credentials`: allows the client to directly request an OAuth2 Access Token by authenticating itself with the Authorization Server using its own client credentials. + +#### TokenEndpointAuthMethod + +- `client_secret_basic`: uses the HTTP Basic Authentication scheme to authenticate the client. +- `client_secret_post`: uses the HTTP `POST` Authentication scheme to authenticate the client. +- `private_key_jwt`: uses JSON Web Tokens (JWT) to authenticate the client. +- `none`: indicates that the process of obtaining an OAuth2 Access Token does not use the client secret. Used for public clients (native apps or mobile apps). + +#### ResponseType + +- `code`: Indicates that the Client receives an Authorization Code that it exchanges for an OAuth2 Access Token. +- `id_token`: Indicates that the Client expects an ID Token. + +#### Time Duration + +A string value that signifies time duration in milliseconds, seconds, minutes, or hours: `"2000ms"`, `"60s"`, `"30m"`, `"1h"`. + +### Example + +```bash +curl -X POST /recipe/oauth/clients \ + -H "Content-Type: application/json" \ + -H "api-key: " \ + -d '{ + "clientName": "", + "responseTypes": ["code"], + "grantTypes": ["authorization_code", "refresh_token"], + "scope": "offline_access ", + "redirectUris": ["https:///oauth/callback"], + }' +``` + +## Response + +### 200 + +The client has been successfully created. + +### Response schema + +| Property | Type | Description | +|-------------|----------------------------------|-----------------------------------------------| +| `clientName` | `string` | The name of the client. | +| `clientId` | `string` | Unique identifier for the client. | +| `clientSecret` | `string` | The secret is part of the create request as plain text, and then never again. The secret remains in hashed format and is not recoverable once lost. | +| `redirectUris` | `array` of `string` | The URLs used for redirection. | +| `audience` | `array` of `string` | Value used to identify for whom a token is issued. The created client can generate access token only for the specified audiences. | +| `scope` | `array` of `string` | A space separated string of scopes that the Client requests access to. | + +#### Example + +```json +{ + "clientName": "", + "clientId": "", + "redirectUris": ["https:///oauth/callback"], + "audience": [""], + "scope": ["offline_access "], +} +``` + + + + -:::caution -You have to save the create OAuth2 Client response because this is not persisted internally for security reasons. +:::warning[You have to save the create OAuth2 Client response because this is not persisted internally for security reasons.] The information is necessary for the next steps. ::: Based on the client creation process, you can infer two additional values that you need later on: -- `authorizeUrl` corresponds to `^{appInfo.apiDomain}^{appInfo.apiBasePath}/oauth/auth` -- `tokenFetchUrl` corresponds to `^{appInfo.apiDomain}^{appInfo.apiBasePath}/oauth/token` +- `authorizeUrl` corresponds to `/auth/oauth/auth` +- `tokenFetchUrl` corresponds to `/auth/oauth/token` ### 3. Configure the Authorization Service Check one of the previous guides that show you how to set up the **Authorization Service** and then return to this page. Choose the tutorial based whether you use multiple backend services or not: -- [Single Backend Setup](/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend#3-set-up-the-authorization-service-backend) -- [Multiple Backends Setup](/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend#3-set-up-the-authorization-service-backend) +- [Single Backend Setup](/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend#3-set-up-the-authorization-service-backend) +- [Multiple Backends Setup](/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend#3-set-up-the-authorization-service-backend) ### 4. Update the login flow in your applications In each of your individual `applications`, you need to set up logic for handling the **OAuth 2.0** authentication flow. You can use a generic **OIDC** or **OAuth** library to do this. - + - + - + You can use the [react-native-app-auth](https://commerce.nearform.com/open-source/react-native-app-auth/) library. Follow [the instructions](https://commerce.nearform.com/open-source/react-native-app-auth/docs/usage/config) to set up your application. You can identify the configuration parameters based on the response received in **step 2**, when creating the **OAuth2 Client**. -- `issuer` corresponds to the endpoint of the **Authorization Service** `^{appInfo.apiDomain}^{appInfo.apiBasePath}` +- `issuer` corresponds to the endpoint of the **Authorization Service** `/auth` - `clientID` corresponds to `clientId` - `redirectUrl` corresponds a value from `callbackUrls` - `scopes` corresponds to `scopes` @@ -103,13 +320,13 @@ You also need to set the `additionalParameters` property with the following valu - `max_age: 0` This forces a new authentication flow once the user ends up on the **Authorization Service** frontend. - `tenant_id: ` Optional, in case you are using a multi tenant setup. Set this to the actual tenant ID. - + - + - + - + You can use the [AppAuth-Android](https://github.com/openid/AppAuth-Android) library. Follow [the instructions](https://github.com/openid/AppAuth-Android?tab=readme-ov-file#authorization-service-configuration) to set up your application. @@ -123,13 +340,13 @@ You need to set additional query parameters by calling the `setAdditionalParamet - `max_age: 0` This forces a new authentication flow once the user ends up on the **Authorization Service** frontend. - `tenant_id: ` Optional, in case you are using a multi tenant setup. Set this to the actual tenant ID. - + - + - + - + You can use the [AppAuth-iOS](https://github.com/openid/AppAuth-Android) library. Follow [the instructions](https://github.com/openid/AppAuth-iOS?tab=readme-ov-file#auth-flow) to set up your application. @@ -146,13 +363,13 @@ You also need to set extra query parameters, when instantiating the `OIDAuthoriz - `max_age: 0` This forces a new authentication flow once the user ends up on the **Authorization Service** frontend. - `tenant_id: ` Optional, in case you are using a multi tenant setup. Set this to the actual tenant ID. - + - + - + - + You can use the [AppAuth](https://github.com/MaikuB/flutter_appauth) library. Follow [the instructions](https://github.com/MaikuB/flutter_appauth/tree/master/flutter_appauth) to set up your application. @@ -160,7 +377,7 @@ Follow [the instructions](https://github.com/MaikuB/flutter_appauth/tree/master/ You can identify the configuration parameters based on the response received in **step 2**, when creating the **OAuth2 Client**. - `` corresponds to `clientId` -- `` corresponds to the endpoint of the **Authorization Service** `^{appInfo.apiDomain}^{appInfo.apiBasePath}` +- `` corresponds to the endpoint of the **Authorization Service** `/auth` - `` corresponds a value from `callbackUrls` - `scopes` corresponds to `scopes` @@ -168,15 +385,15 @@ You also need to set the `additionalParameters` property with the following valu - `max_age: 0` This forces a new authentication flow once the user ends up on the **Authorization Service** frontend. - `tenant_id: ` Optional, in case you are using a multi tenant setup. Set this to the actual tenant ID. - + - + - + :::info -If you want to use the [**OAuth2 Refresh Tokens**](/docs/authentication/unified-login/oauth2-basics#oauth2-refresh-token) make sure to include the `offline_access` scope during the initialization step. +If you want to use the [**OAuth2 Refresh Tokens**](/authentication/unified-login/oauth2-basics#oauth2-refresh-token) make sure to include the `offline_access` scope during the initialization step. ::: diff --git a/docs/authentication/unified-login/verify-tokens.mdx b/docs/authentication/unified-login/verify-tokens.mdx index 9b228ed5f7..0eb7c90ffc 100644 --- a/docs/authentication/unified-login/verify-tokens.mdx +++ b/docs/authentication/unified-login/verify-tokens.mdx @@ -1,18 +1,10 @@ --- title: Verify tokens -hide_title: true -sidebar_position: 5 -toc_max_heading_level: 4 description: 'Verify OAuth2 tokens using JWT libraries or the introspection endpoint ' -page_type: guide -recipe: oauth2 -category: unified-login +sidebar: + order: 5 --- - -# Verify tokens - - ## Overview You can verify an **OAuth2 Access Token** in two ways: @@ -26,10 +18,10 @@ It ensures that the validation occurs for the correct token type: - `1` represents an **OAuth2 Access Token** - `2` represents an **OAuth2 ID Token**. -:::caution no-title +:::warning The following guide covers only **OAuth2 Tokens** verification. -For information on how to verify **SuperTokens Session Tokens** please refer to the [following section](/docs/additional-verification/session-verification/protect-api-routes). +For information on how to verify **SuperTokens Session Tokens** please refer to the [following section](/additional-verification/session-verification/protect-api-routes). ::: @@ -42,24 +34,21 @@ It indicates that the token is valid from a cryptographic standpoint and that it The code samples show you a basic validation scenario where the token undergoes a check for the required scope for an action to occur. -:::info - -If your scenario involves a common backend with multiple frontend clients you can drop the `client_id` check. +:::info[If your scenario involves a common backend with multiple frontend clients you can drop the `client_id` check.] ::: - - + - + For NodeJS you can use [`jose`](https://github.com/panva/jose) to verify the token. ```tsx import * as jose from "jose"; -const JWKS = jose.createRemoteJWKSet(new URL('^{appInfo.apiDomain}^{appInfo.apiBasePath}jwt/jwks.json')) +const JWKS = jose.createRemoteJWKSet(new URL('/authjwt/jwks.json')) // Follow this example if you are using the Authorization Code Flow async function validateToken(jwt: string) { @@ -82,9 +71,9 @@ async function validateToken(jwt: string) { } ``` - + - + You can use the [`jwx`](https://github.com/lestrrat-go/jwx) library to verify the token. @@ -98,8 +87,8 @@ import ( ) func ValidateToken(token string) bool { - apiDomain := "^{appInfo.apiDomain}" - apiBasePath := "^{appInfo.apiBasePath}" + apiDomain := "" + apiBasePath := "/auth" clientId := "" requiredScope := "" @@ -139,20 +128,20 @@ func ValidateToken(token string) bool { } ``` - + - + You can use the [PyJWT](https://github.com/jpadilla/pyjwt) library to verify the token. -```python +```python from typing import Optional, List import jwt from jwt import PyJWKClient def validate_token(token: str) -> bool: - api_domain = "^{appInfo.apiDomain}" - api_base_path = "^{appInfo.apiBasePath}" + api_domain = "" + api_base_path = "/auth" client_id = "" required_scope = "" @@ -186,9 +175,9 @@ def validate_token(token: str) -> bool: return False ``` - + - + You can use the [Firebase JWT](https://github.com/firebase/php-jwt) library to verify the token. @@ -200,8 +189,8 @@ use Firebase\JWT\JWT; use Firebase\JWT\Key; function validateToken($jwt) { - $apiDomain = "^{appInfo.apiDomain}"; - $apiBasePath = "^{appInfo.apiBasePath}"; + $apiDomain = ""; + $apiBasePath = "/auth"; $jwksUrl = $apiDomain . $apiBasePath . '/jwt/jwks.json'; $requiredScope = ""; $clientId = ""; @@ -222,9 +211,9 @@ function validateToken($jwt) { } ``` - + - + You can use the [Auth0 JWT](https://github.com/auth0/java-jwt) library to verify the token. Here is an example of how you can do that: @@ -246,7 +235,7 @@ import java.util.Scanner; public class JWTVerifier { - private static final String JWKS_URL = "^{appInfo.apiDomain}^{appInfo.apiBasePath}jwt/jwks.json"; + private static final String JWKS_URL = "/authjwt/jwks.json"; private static final String CLIENT_ID = ""; private static Map fetchJWKS() throws Exception { @@ -288,9 +277,9 @@ public class JWTVerifier { } ``` - + - + You can use the [IdentityModel](https://github.com/IdentityModel/IdentityModel) library to verify the token. @@ -355,9 +344,9 @@ class AuthorizationCodeTokenValidator } ``` - + - + ### Email verification @@ -377,9 +366,9 @@ It is advisable to perform this process for high security operations to avoid th Here is an example of how you can use this validation method: - + - + ```tsx import OAuth2Provider from "supertokens-node/recipe/oauth2provider"; @@ -398,19 +387,17 @@ async function validateToken(token: string) { } ``` - - - + -:::caution + -The Go SDK does not support creating OAuth2 providers. +:::warning[The Go SDK does not support creating OAuth2 providers.] ::: - + - + ```python from supertokens_python.recipe.oauth2provider.interfaces import OAuth2TokenValidationRequirements @@ -430,9 +417,9 @@ def validate_token(token: str): ``` - + - + ```bash # The response status should be 200 @@ -440,11 +427,9 @@ def validate_token(token: str): curl -X POST \ -H "Content-Type: application/json" \ -d '{"token": ""}' \ - "^{appInfo.apiDomain}^{appInfo.apiBasePath}/oauth/introspect" + "/auth/oauth/introspect" ``` - - - - + + diff --git a/docs/authentication/unified-login/work-with-scopes.mdx b/docs/authentication/unified-login/work-with-scopes.mdx index 66ecf22527..7bea02a05d 100644 --- a/docs/authentication/unified-login/work-with-scopes.mdx +++ b/docs/authentication/unified-login/work-with-scopes.mdx @@ -1,18 +1,10 @@ --- title: Work with scopes -hide_title: true -sidebar_position: 4 -description: >- - Manage OAuth2 scopes, request specific scopes, and override granted scopes - during authentication. -page_type: guide -recipe: oauth2 -category: unified-login +description: Manage OAuth2 scopes, request specific scopes, and override granted scopes during authentication. +sidebar: + order: 4 --- - -# Work with scopes - ## Overview The creation process of an **OAuth2 Client** determines the allowed scopes. @@ -39,9 +31,9 @@ By default, the client receives all scopes. If you want to manually modify the list of scopes that the client receives during the authentication flow, you can do this by using overrides. - + - + ```tsx import OAuth2Provider from "supertokens-node/recipe/oauth2provider"; @@ -60,17 +52,16 @@ OAuth2Provider.init({ }); ``` - + - + -:::caution -The Go SDK does not support creating OAuth2 providers. +:::warning[The Go SDK does not support creating OAuth2 providers.] ::: - + - + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -120,6 +111,6 @@ init( ``` - + - + diff --git a/docs/deployment/_category_.json b/docs/deployment/_category_.json deleted file mode 100644 index 81a4840be8..0000000000 --- a/docs/deployment/_category_.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "label": "Deployment", - "collapsible": true, - "collapsed": true, - "customProps": { - "isMainCategory": true - }, - "position": 8 -} diff --git a/docs/deployment/meta.ts b/docs/deployment/meta.ts new file mode 100644 index 0000000000..469ca48a64 --- /dev/null +++ b/docs/deployment/meta.ts @@ -0,0 +1,8 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Deployment", + "icon": "server", + "order": 8, + "collapsed": true +}); diff --git a/docs/deployment/migrate-from-mysql.mdx b/docs/deployment/migrate-from-mysql.mdx index 1c2f09e080..5f65e23e3f 100644 --- a/docs/deployment/migrate-from-mysql.mdx +++ b/docs/deployment/migrate-from-mysql.mdx @@ -1,4 +1,6 @@ -# Migrate from MySQL to PostgreSQL +--- +title: Migrate from MySQL to PostgreSQL +--- ## Overview @@ -24,8 +26,7 @@ The instructions for this step are specific to your database management system. Start the same version of [`supertokens-postgresql`](https://hub.docker.com/r/supertokens/supertokens-postgresql) to initialize the schema in the database. -:::warning -Make sure to use the same version as the `supertokens-mysql` instance that you are currently running. +:::warning[Make sure to use the same version as the `supertokens-mysql` instance that you are currently running.] ::: ### 3. Export data from MySQL @@ -38,11 +39,9 @@ Run the following command to export most of your data: mysqldump supertokens --fields-terminated-by ',' --fields-enclosed-by '"' --fields-escaped-by '\' --no-create-info --tab /var/lib/mysql-files/ ``` -:::info - -If you do not have permissions to write to the database filesystem you can use the following python script to export tables one by one: +:::info[If you do not have permissions to write to the database filesystem you can use the following python script to export tables one by one:] -## Export script + ```python #!/usr/bin/env python3 import subprocess @@ -120,6 +119,7 @@ def main(): if __name__ == "__main__": main() ``` + ::: @@ -157,8 +157,7 @@ Connect to your PostgreSQL database and disable triggers to prevent constraint v SET session_replication_role = 'replica'; ``` -:::info -If you cannot disable the triggers, use the order specified in the next step. +:::info[If you cannot disable the triggers, use the order specified in the next step.] The *With Order* shows you how to import everything one by one without triggering the constraints. ::: @@ -167,14 +166,14 @@ The *With Order* shows you how to import everything one by one without triggerin For most tables, you can import the data directly. - + ```sql COPY FROM '/pg-data-host/.csv' CSV DELIMITER ',' QUOTE '"' ESCAPE '\' NULL as '\N'; ``` - + - + ```bash #!/bin/bash @@ -262,7 +261,7 @@ echo "" echo "Import complete!" ``` - + @@ -273,9 +272,7 @@ The `tenant_thirdparty_provider_clients` table requires special handling. You need to do this to differences between the `MySQL` `JSON` and `PostgreSQL` `text[]` formats. - -## Create a staging table - + ```sql CREATE TABLE tenant_thirdparty_provider_clients_raw ( connection_uri_domain VARCHAR(256) DEFAULT '' NOT NULL, @@ -290,16 +287,14 @@ CREATE TABLE tenant_thirdparty_provider_clients_raw ( additional_config TEXT ); ``` - -## Import data into the staging table: - + + ```sql COPY tenant_thirdparty_provider_clients_raw FROM '/host/tenant_thirdparty_provider_clients.txt' CSV DELIMITER ',' QUOTE '"' ESCAPE '\' NULL as '\N'; ``` - -## Convert and insert into the final table: - + + ```sql INSERT INTO tenant_thirdparty_provider_clients ( connection_uri_domain, app_id, tenant_id, third_party_id, client_type, @@ -313,7 +308,7 @@ SELECT ) FROM tenant_thirdparty_provider_clients_raw; ``` - + #### 5.4 Handle the WebAuthn credentials table @@ -321,9 +316,7 @@ FROM tenant_thirdparty_provider_clients_raw; The `webauthn_credentials` table requires conversion from MySQL Binary Large Object, `BLOB`, to PostgreSQL Binary Data, `BYTEA` format. - -## Create a staging table - + ```sql CREATE TABLE IF NOT EXISTS webauthn_credentials_staging ( id VARCHAR(256) NOT NULL, @@ -337,16 +330,14 @@ CREATE TABLE IF NOT EXISTS webauthn_credentials_staging ( updated_at BIGINT NOT NULL ); ``` - -## Import the hexadecimal data - + + ```sql COPY webauthn_credentials_staging FROM '/host/webauthn_credentials_hex.txt' CSV DELIMITER ',' QUOTE '"' ESCAPE '\' NULL as '\N'; ``` - -## Convert and insert into the final table - + + ```sql INSERT INTO webauthn_credentials ( id, app_id, rp_id, user_id, counter, public_key, transports, created_at, updated_at @@ -357,7 +348,7 @@ SELECT transports, created_at, updated_at FROM webauthn_credentials_staging; ``` - + @@ -464,6 +455,3 @@ fi ``` If the numbers match, you have successfully migrated your SuperTokens data from `MySQL` to `PostgreSQL` :tada: - - - diff --git a/docs/deployment/rate-limits.mdx b/docs/deployment/rate-limits.mdx index de0ffb051e..dd00257e56 100644 --- a/docs/deployment/rate-limits.mdx +++ b/docs/deployment/rate-limits.mdx @@ -1,16 +1,10 @@ --- title: Rate limit policy -hide_title: true -sidebar_position: 3 -description: >- - Understand and implement SuperTokens rate limit policies for managed and - self-hosted services. -page_type: guide -category: deployment +description: Understand and implement SuperTokens rate limit policies for managed and self-hosted services. +sidebar: + order: 3 --- -# Rate limit policy - ## Overview The following page describes how rate limits apply during SuperTokens API calls. @@ -25,15 +19,14 @@ However, if you query the core using different IP addresses or for a different a The free tier of the managed service has a rate limit of 50 requests per second with a burst of 50 requests per second (with no delay). This should be enough for 5-10 concurrent sign in / up (each sign in API call queries the SuperTokens core multiple times). -:::important -The backend SDK auto retries if it gets a `429` status code from the core (up to 5 times before throwing an error). +:::note[The backend SDK auto retries if it gets a `429` status code from the core (up to 5 times before throwing an error).] ::: ### Paying users If you are a paying user for SuperTokens, the rate limit and the burst limit adjust dynamically based on your usage (with a minimum of a 100rps). You should not see any `429`s unless there is a **significant** spike in requests. -:::info Paid Feature +:::info[Paid Feature] If you want higher rate limits, please [email support](mailto:support@supertokens.com), requesting a higher rate limit. ::: diff --git a/docs/deployment/scalability.mdx b/docs/deployment/scalability.mdx index 9c64ebc736..6d6e954f08 100644 --- a/docs/deployment/scalability.mdx +++ b/docs/deployment/scalability.mdx @@ -1,17 +1,10 @@ --- -id: scalability title: Scalability -hide_title: true -sidebar_position: 4 -description: >- - Learn how SuperTokens scales to handle millions of users and requests - efficiently. -page_type: guide -category: deployment +description: Learn how SuperTokens scales to handle millions of users and requests efficiently. +sidebar: + order: 4 --- -# Scalability - ## Overview The following page addresses how the **SuperTokens** components scale based on different factors. @@ -29,8 +22,7 @@ As the number of tenants scales, it does not affect performance on most operatio ## SuperTokens core -:::important -If you are using the managed service, the SuperTokens core is fully managed, and you don't have to worry about scaling it. +:::note[If you are using the managed service, the SuperTokens core is fully managed, and you don't have to worry about scaling it.] This section is for those who are self-hosting the SuperTokens core service. ::: @@ -49,11 +41,11 @@ The scale of end users that this can support is in the order of 1-2 million mont ### Average latency over 1 day - + ### Number of requests per minute over 1 day - + ### Performance tuning diff --git a/docs/deployment/self-host-supertokens.mdx b/docs/deployment/self-host-supertokens.mdx index e36c9dcac5..fe81d5f044 100644 --- a/docs/deployment/self-host-supertokens.mdx +++ b/docs/deployment/self-host-supertokens.mdx @@ -1,23 +1,13 @@ --- title: Self-host SuperTokens -hide_title: true -sidebar_position: 1 -toc_max_heading_level: 4 -description: >- - Run SuperTokens on your infrastructure, control authentication data, and scale - as needed. -page_type: tutorial -category: deployment +description: Run SuperTokens on your infrastructure, control authentication data, and scale as needed. +sidebar: + order: 1 --- +See how you can run **SuperTokens** in your own infrastructure. -# Self-hosting SuperTokens - - - See how you can run **SuperTokens** in your own infrastructure. - - - +--- ## Overview @@ -31,9 +21,8 @@ To deploy the Core Service you must configure two things: the actual API and the - The core service can be deployed using a **Docker** image or directly inside your VM. - The supported database is **PostgreSQL**. The minimum required version is `13.0`. -:::info -**SuperTokens Core** has dropped **MySQL** and **MongoDB** support with the `11.0.0` release. -If you want to reference the old documentation, please [open this page](/docs/legacy/core/v10/self-host-supertokens). +:::info[**SuperTokens Core** has dropped **MySQL** and **MongoDB** support with the `11.0.0` release.] +If you want to reference the old documentation, please [open this page](/legacy/core/v10/self-host-supertokens). ::: @@ -45,12 +34,11 @@ If you want to reference the old documentation, please [open this page](/docs/le #### With docker - ```bash docker run -p 3567:3567 -d supertokens/supertokens-postgresql:latest ``` -- To see all the environment variables available, please see [the README file](https://github.com/supertokens/supertokens-docker-postgresql/blob/master/README.md). +- To see all the environment variables available, please see [the README file](https://github.com/supertokens/supertokens-docker-postgresql/blob/master/README). - The above command starts the container with an in-memory database. This means you **do not need to connect it to PostgreSQL to test out SuperTokens**. @@ -69,8 +57,8 @@ Once downloaded, remove the zip, and you see a folder named `supertokens`. ##### 2. Install SuperTokens - - + + ```bash # sudo is required so that the supertokens @@ -79,9 +67,9 @@ Once downloaded, remove the zip, and you see a folder named `supertokens`. cd supertokens sudo ./install ``` - + - + ```bash @@ -89,13 +77,12 @@ cd supertokens ./install ``` -:::caution -You may get an error like `java cannot be opened because the developer cannot be verified`. To solve this, visit System Preferences > Security & Privacy > General Tab, and then click on the Allow button at the bottom. Then retry the command above. +:::warning[You may get an error like `java cannot be opened because the developer cannot be verified`. To solve this, visit System Preferences > Security & Privacy > General Tab, and then click on the Allow button at the bottom. Then retry the command above.] ::: - + - + ```batch @@ -106,11 +93,10 @@ cd supertokens install.bat ``` - - + + -:::important -After installing, you can delete the downloaded folder as you no longer need it. +:::note[After installing, you can delete the downloaded folder as you no longer need it.] Make any changes to the configuration in the `config.yaml` file in the installation directory, as specified in the output of the `supertokens --help` command. ::: @@ -124,7 +110,7 @@ supertokens start [--host=...] [--port=...] - The above command starts the container with an in-memory database. - To see all available options please run `supertokens start --help` -:::info Tip +:::info[Tip] To stop the service, run the following command: ```bash supertokens stop @@ -138,32 +124,28 @@ Open a browser and visit `http://localhost:3567/hello`. If you see a page that s If you are having issues with starting the docker image, please feel free to reach out [over email](mailto:support@supertokens.com) or [via Discord](https://supertokens.com/discord). -:::tip -The `/hello` route checks whether the database connection is correctly set up and only returns a 200 status code if there is no issue. +:::tip[The `/hello` route checks whether the database connection is correctly set up and only returns a 200 status code if there is no issue.] If you are using Kubernetes or docker swarm, this endpoint is perfect for doing readiness and liveness probes. ::: - ### 3. Connect the backend SDK with SuperTokens - The default `port` for SuperTokens is `3567`. You can change this by binding a different port in the `docker run` command. For example, `docker run -p 8080:3567` runs SuperTokens on port `8080` on your machine. - The connection info goes in the `supertokens` object in the `init` function on your backend: - - + + -```tsx +```tsx {4,5,6,7} import supertokens from "supertokens-node"; supertokens.init({ - // highlight-start supertokens: { connectionURI: "http://localhost:3567", apiKey: "someKey" // OR can be undefined }, - // highlight-end appInfo: { apiDomain: "...", appName: "...", @@ -173,58 +155,54 @@ supertokens.init({ }); ``` - - + + -```go +```go {5,6,7,8} import "github.com/supertokens/supertokens-golang/supertokens" func main() { supertokens.Init(supertokens.TypeInput{ - // highlight-start Supertokens: &supertokens.ConnectionInfo{ ConnectionURI: "http://localhost:3567", APIKey: "someKey", }, - // highlight-end }) } ``` - - + + -```python +```python {5,6,7,8} from supertokens_python import init, InputAppInfo, SupertokensConfig init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - # highlight-start supertokens_config=SupertokensConfig( connection_uri='http://localhost:3567', api_key='someKey' ), - # highlight-end - framework='...', # type: ignore + framework='...', recipe_list=[ #... ] ) ``` - - + + -:::info Security +:::info[Security] No API key exists by default. -Check [the API keys documentation](/docs/platform-configuration/supertokens-core/api-keys) to see how to add one. +Check [the API keys documentation](/platform-configuration/supertokens-core/api-keys) to see how to add one. ::: ### 4. Set up the database -#### 4.1 Create a database {{optional}} +#### 4.1 Create a database (optional) ```sql @@ -240,22 +218,19 @@ In this case, you need to provide your database's name as shown in the step belo ##### With docker -:::caution -Host being `localhost` / `127.0.0.1` does not work in a docker image. Instead, please provide the database's local / public host name or IP address. +:::warning[Host being `localhost` / `127.0.0.1` does not work in a docker image. Instead, please provide the database's local / public host name or IP address.] You also need to make the database listen on all the IPs of the local machine. Edit the `postgresql.conf` configuration file and set the value of `listen_addresses` to `0.0.0.0`. ::: -:::caution -It is important to use the `postgresql://` scheme designator in the PostgreSQL Connection URI. Using `postgres://` will lead to a startup error. +:::warning[It is important to use the `postgresql://` scheme designator in the PostgreSQL Connection URI. Using `postgres://` will lead to a startup error.] ::: -```bash +```bash {4,11,12,13,14,15} docker run \ -p 3567:3567 \ - // highlight-next-line -e POSTGRESQL_CONNECTION_URI="postgresql://username:pass@host/dbName" \ -d supertokens/supertokens-postgresql @@ -263,18 +238,15 @@ docker run \ docker run \ -p 3567:3567 \ - // highlight-start -e POSTGRESQL_USER="username" \ -e POSTGRESQL_PASSWORD="password" \ -e POSTGRESQL_HOST="host" \ -e POSTGRESQL_PORT="5432" \ -e POSTGRESQL_DATABASE_NAME="supertokens" \ - // highlight-end -d supertokens/supertokens-postgresql ``` -:::tip -You can also provide the table schema by setting the `POSTGRESQL_TABLE_SCHEMA` option. +:::tip[You can also provide the table schema by setting the `POSTGRESQL_TABLE_SCHEMA` option.] ::: ##### Without docker @@ -302,9 +274,7 @@ postgresql_database_name: "supertokens" You can also provide the table schema by setting the `postgresql_table_schema` option. - -:::info -The required tables should create automatically if the database user has table creation permission. +:::info[The required tables should create automatically if the database user has table creation permission.] If not, you can create them manually using the following snippet. @@ -911,29 +881,27 @@ SELECT * FROM key_value; If you see at least one row, it means that the connection has been successfully completed! -#### 4.4 Rename database tables {{optional}} +#### 4.4 Rename database tables (optional) -:::caution -If you already have tables created by SuperTokens, and then you rename them, SuperTokens creates new tables. Please be sure to migrate the data from the existing one to the new one. +:::warning[If you already have tables created by SuperTokens, and then you rename them, SuperTokens creates new tables. Please be sure to migrate the data from the existing one to the new one.] ::: You can add a prefix to all table names that SuperTokens manages. This way, all will be renamed in a way that has no clashes with your tables. For example, two tables created by SuperTokens have the names `emailpassword_users` and `thirdparty_users`. If you add a prefix to them (something like `"my_prefix"`), then the tables become `my_prefix_emailpassword_users` and `my_prefix_thirdparty_users`. - - + + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-next-line -e POSTGRESQL_TABLE_NAMES_PREFIX="my_prefix" \ -d supertokens/supertokens-postgresql ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -941,8 +909,8 @@ docker run \ postgresql_table_names_prefix: "my_prefix" ``` - - + + ### 5. Add license keys @@ -953,10 +921,10 @@ You can sign up on [**SuperTokens**](https://supertokens.com/auth) to receive on Once you have the license key you need to manually add it to your **SuperTokens Core Instance**. To do this you have to call the Core API with the following request: -```bash title="Add License Key" showAppTypeSelect -curl --location --request PUT ^{coreInfo.uri}/ee/license \ +```bash title="Add License Key" +curl --location --request PUT /ee/license \ --header 'Content-Type: application/json' \ - --header 'api-key: ^{coreInfo.key}' \ + --header 'api-key: ' \ --data-raw '{ "licenseKey": "" }' ``` @@ -966,7 +934,6 @@ curl --location --request PUT ^{coreInfo.uri}/ee/license \ ### Docker compose file - ```bash version: '3' @@ -1014,11 +981,9 @@ networks: ``` -:::important -If you are running the backend process that integrates with the backend SDK as part of the docker compose file as well, make sure to use `http://supertokens:3567` as the connection URI instead of `http://localhost:3567`. +:::note[If you are running the backend process that integrates with the backend SDK as part of the docker compose file as well, make sure to use `http://supertokens:3567` as the connection URI instead of `http://localhost:3567`.] ::: ### Helm charts for Kubernetes - For [PostgreSQL image](https://github.com/supertokens/supertokens-docker-postgresql/tree/master/helm-chart) - diff --git a/docs/deployment/telemetry.mdx b/docs/deployment/telemetry.mdx index 1c45a37f45..aa74d4d6c9 100644 --- a/docs/deployment/telemetry.mdx +++ b/docs/deployment/telemetry.mdx @@ -1,13 +1,11 @@ --- -sidebar_position: 6 title: OpenTelemetry Integration -hide_title: true description: Add OpenTelemetry logging to all SuperTokens APIs and function calls using the plugin -page_type: tutorial +sidebar: + order: 6 + badge: New --- -# OpenTelemetry Integration - ## Overview This tutorial shows you how to add **OpenTelemetry** logging to all the **SuperTokens** APIs and function calls using the **OpenTelemetry plugin**. The guide makes use of the plugins functionality to automatically instrument your authentication flows with distributed tracing. @@ -22,7 +20,7 @@ The OpenTelemetry plugin supports only the `NodeJS` SDK. Support for other platf Make sure you have the OpenTelemetry SDK installed and configured in your application. For detailed instructions, see the [OpenTelemetry Node.js Getting Started Guide](https://opentelemetry.io/docs/languages/js/getting-started/nodejs/#instrumentation). -The implementation is in early stages and APIs might change. For more information on how plugins work, refer to the [references page](/docs/references/plugins/introduction). +The implementation is in early stages and APIs might change. For more information on how plugins work, refer to the [references page](/references/plugins/introduction). ## Steps @@ -58,7 +56,7 @@ const sdk = new NodeSDK({ sdk.start(); ``` -:::note no-title +:::note For a more thorough explanation on how to setup OpenTelemetry please refer to the [official documentation](https://opentelemetry.io/docs/languages/js/getting-started/nodejs). ::: @@ -215,40 +213,20 @@ SuperTokens.init({ Besides OpenTelemetry integration, you can also look into other deployment and monitoring features: - - - - Self-Hosting - - - Self-host SuperTokens in your own infrastructure. - - - - - - Rate Limiting - - - Configure rate limits to protect your authentication endpoints. - - - - - - Scalability - - - Scale SuperTokens for high-traffic applications. - - - - - - Plugins Reference - - - General information on how plugins work. - - - + + +Self-host SuperTokens in your own infrastructure. + + + +Configure rate limits to protect your authentication endpoints. + + + +Scale SuperTokens for high-traffic applications. + + + +General information on how plugins work. + + diff --git a/docs/index.mdx b/docs/index.mdx index 4cd0730d14..02ed8a7997 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -1,164 +1,88 @@ --- -id: index title: Overview -sidebar_position: 1 -pagination_next: null -show_feedback: false -hide_table_of_contents: true -skip_llms: true -description: >- - Discover how you can integrate and use SuperTokens effectively in your - applications. -page_type: overview +description: Discover how you can integrate and use SuperTokens effectively in your applications. +sidebar: + order: 1 --- +Explore our guides and examples on how you can use **SuperTokens**. -# Documentation - - - Explore our guides and examples on how you can use **SuperTokens**. - +--- - ## Getting Started - + See how you can get up and running with our product. - - - - - - Quickstart - - - Go through a quick tutorial that will show you how to integrate SuperTokens with your app. - - - - - Example Applications - - - Use our CLI to generate a boilerplate app that you can use as a starting point. - - - + + + + +Go through a quick tutorial that will show you how to integrate SuperTokens with your app. + + +Use our CLI to generate a boilerplate app that you can use as a starting point. + + ## Features - + Discover the different features exposed by **SuperTokens**. - - - - - - Authentication Methods - - - We support various authentication methods that you can configure to fit your needs. - - - - - Multi-Factor Authentication - - - Set up additional verification layers in your sign-in process. - - - + + + + +We support various authentication methods that you can configure to fit your needs. + + +Set up additional verification layers in your sign-in process. + - - - Multi-Tenancy - - - Use SuperTokens to manage multiple organizations and apps. - - + +Use SuperTokens to manage multiple organizations and apps. + - - - Attack Protection Suite - - - Enable additional security features that shield your app. - - - - + +Enable additional security features that shield your app. + - - - Self Hosting - - - Deploy SuperTokens in your own infrastructure. - - + +Deploy SuperTokens in your own infrastructure. + - - - Migration Guide - - - Learn how to migrate from an existing authentication provider. - - + +Learn how to migrate from an existing authentication provider. + - - + ## References - + Get an in-depth understanding of how SDKs and APIs work. - - - - - - Frontend SDK Reference - - - Information on how the frontend SDKs are structured and how to use them. - - - - - Backend SDK Reference - - - Information on how the backend SDKs are structured and how to use them. - - - - - - FDI Reference - - - Details about the endpoints exposed by the **Frontend Driver Interface**. + + + + +Information on how the frontend SDKs are structured and how to use them. + + +Information on how the backend SDKs are structured and how to use them. + + +Details about the endpoints exposed by the **Frontend Driver Interface**. This is the API enabled by the backend SDKs. - - - - - - CDI Reference - - - Details about the endpoints exposed by the **Core Driver Interface**. + + + +Details about the endpoints exposed by the **Core Driver Interface**. This is the API enabled by the SuperTokens Core Service. - - + - + diff --git a/docs/legacy/core/v10/self-host-supertokens.mdx b/docs/legacy/core/v10/self-host-supertokens.mdx index e2691d9733..3d3c0a52e3 100644 --- a/docs/legacy/core/v10/self-host-supertokens.mdx +++ b/docs/legacy/core/v10/self-host-supertokens.mdx @@ -1,20 +1,12 @@ --- title: Self-host SuperTokens -hide_title: true -sidebar_position: 1 -toc_max_heading_level: 4 -description: >- - Run SuperTokens on your infrastructure, control authentication data, and scale - as needed. -page_type: guide -recipe: emailpassword -category: authentication +description: Run SuperTokens on your infrastructure, control authentication data, and scale as needed. +sidebar: + order: 1 + hidden: true --- - -# Self-host a legacy SuperTokens Core version - - +--- ## Overview @@ -33,7 +25,7 @@ To deploy the Core Service you must configure two things: the actual API and the ## Steps -:::warning no-title +:::warning This guide is only relevant if you are using a legacy **SuperTokens Core** version, `<= 10.0.1`. **MySQL** is no longer available as a storage option starting with the **11.0.0** version. @@ -45,29 +37,29 @@ This guide is only relevant if you are using a legacy **SuperTokens Core** versi #### With docker - - + + ```bash docker run -p 3567:3567 -d supertokens/supertokens-mysql@10.1 ``` -- To see all the environment variables available, please see [the README file](https://github.com/supertokens/supertokens-docker-mysql/blob/master/README.md). +- To see all the environment variables available, please see [the README file](https://github.com/supertokens/supertokens-docker-mysql/blob/master/README). - The above command starts the container with an in-memory database. This means you **do not need to connect it to MySQL to test out SuperTokens**. - + - + ```bash -docker run -p 3567:3567 -d supertokens/supertokens-postgresql^{docker_version_postgresql} +docker run -p 3567:3567 -d supertokens/supertokens-postgresql ``` -- To see all the environment variables available, please see [the README file](https://github.com/supertokens/supertokens-docker-postgresql/blob/master/README.md). +- To see all the environment variables available, please see [the README file](https://github.com/supertokens/supertokens-docker-postgresql/blob/master/README). - The above command starts the container with an in-memory database. This means you **do not need to connect it to PostgreSQL to test out SuperTokens**. - - + + #### Without docker @@ -84,8 +76,8 @@ Once downloaded, remove the zip, and you see a folder named `supertokens`. ##### 2. Install SuperTokens - - + + ```bash # sudo is required so that the supertokens @@ -94,9 +86,9 @@ Once downloaded, remove the zip, and you see a folder named `supertokens`. cd supertokens sudo ./install ``` - + - + ```bash @@ -104,13 +96,12 @@ cd supertokens ./install ``` -:::caution -You may get an error like `java cannot be opened because the developer cannot be verified`. To solve this, visit System Preferences > Security & Privacy > General Tab, and then click on the Allow button at the bottom. Then retry the command above. +:::warning[You may get an error like `java cannot be opened because the developer cannot be verified`. To solve this, visit System Preferences > Security & Privacy > General Tab, and then click on the Allow button at the bottom. Then retry the command above.] ::: - + - + ```batch @@ -121,11 +112,10 @@ cd supertokens install.bat ``` - - + + -:::important -After installing, you can delete the downloaded folder as you no longer need it. +:::note[After installing, you can delete the downloaded folder as you no longer need it.] Make any changes to the configuration in the `config.yaml` file in the installation directory, as specified in the output of the `supertokens --help` command. ::: @@ -139,7 +129,7 @@ supertokens start [--host=...] [--port=...] - The above command starts the container with an in-memory database. - To see all available options please run `supertokens start --help` -:::info Tip +:::info[Tip] To stop the service, run the following command: ```bash supertokens stop @@ -153,32 +143,28 @@ Open a browser and visit `http://localhost:3567/hello`. If you see a page that s If you are having issues with starting the docker image, please feel free to reach out [over email](mailto:support@supertokens.com) or [via Discord](https://supertokens.com/discord). -:::tip -The `/hello` route checks whether the database connection is correctly set up and only returns a 200 status code if there is no issue. +:::tip[The `/hello` route checks whether the database connection is correctly set up and only returns a 200 status code if there is no issue.] If you are using Kubernetes or docker swarm, this endpoint is perfect for doing readiness and liveness probes. ::: - ### 3. Connect the backend SDK with SuperTokens - The default `port` for SuperTokens is `3567`. You can change this by binding a different port in the `docker run` command. For example, `docker run -p 8080:3567` runs SuperTokens on port `8080` on your machine. - The connection info goes in the `supertokens` object in the `init` function on your backend: - - + + -```tsx +```tsx {4,5,6,7} import supertokens from "supertokens-node"; supertokens.init({ - // highlight-start supertokens: { connectionURI: "http://localhost:3567", apiKey: "someKey" // OR can be undefined }, - // highlight-end appInfo: { apiDomain: "...", appName: "...", @@ -188,73 +174,69 @@ supertokens.init({ }); ``` - - + + -```go +```go {5,6,7,8} import "github.com/supertokens/supertokens-golang/supertokens" func main() { supertokens.Init(supertokens.TypeInput{ - // highlight-start Supertokens: &supertokens.ConnectionInfo{ ConnectionURI: "http://localhost:3567", APIKey: "someKey", }, - // highlight-end }) } ``` - - + + -```python +```python {5,6,7,8} from supertokens_python import init, InputAppInfo, SupertokensConfig init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - # highlight-start supertokens_config=SupertokensConfig( connection_uri='http://localhost:3567', api_key='someKey' ), - # highlight-end - framework='...', # type: ignore + framework='...', recipe_list=[ #... ] ) ``` - - + + -:::info Security +:::info[Security] No API key exists by default. -Check [the API keys documentation](/docs/platform-configuration/supertokens-core/api-keys) to see how to add one. +Check [the API keys documentation](/platform-configuration/supertokens-core/api-keys) to see how to add one. ::: ### 4. Set up the database -#### 4.1 Create a database {{optional}} +#### 4.1 Create a database (optional) - - + + ```sql CREATE DATABASE SuperTokens; ``` - - + + ```sql CREATE DATABASE supertokens; ``` - + - + You can skip this step if you want SuperTokens to write to your own database. In this case, you need to provide your database's name as shown in the step below. @@ -263,20 +245,18 @@ In this case, you need to provide your database's name as shown in the step belo ##### With docker - - -:::caution -Host being `localhost` / `127.0.0.1` does not work in a docker image. Instead, please provide the database's local / public host name or IP address. + + +:::warning[Host being `localhost` / `127.0.0.1` does not work in a docker image. Instead, please provide the database's local / public host name or IP address.] You also need to make the database listen on all the IPs of the local machine. Edit the `mysqld.cnf` configuration file and set the value of `bind-address` to `0.0.0.0`. ::: -```bash +```bash {4,11,12,13,14,15} docker run \ -p 3567:3567 \ -//highlight-next-line -e MYSQL_CONNECTION_URI="mysql://username:pass@host/dbName" \ -d supertokens/supertokens-mysql @@ -284,31 +264,27 @@ docker run \ docker run \ -p 3567:3567 \ -//highlight-start -e MYSQL_USER="username" \ -e MYSQL_PASSWORD="password" \ -e MYSQL_HOST="host" \ -e MYSQL_PORT="3306" \ -e MYSQL_DATABASE_NAME="supertokens" \ -//highlight-end -d supertokens/supertokens-mysql ``` - + - + -:::caution -Host being `localhost` / `127.0.0.1` does not work in a docker image. Instead, please provide the database's local / public host name or IP address. +:::warning[Host being `localhost` / `127.0.0.1` does not work in a docker image. Instead, please provide the database's local / public host name or IP address.] You also need to make the database listen on all the IPs of the local machine. Edit the `postgresql.conf` configuration file and set the value of `listen_addresses` to `0.0.0.0`. ::: -```bash +```bash {4,11,12,13,14,15} docker run \ -p 3567:3567 \ - // highlight-next-line -e POSTGRESQL_CONNECTION_URI="postgresql://username:pass@host/dbName" \ -d supertokens/supertokens-postgresql @@ -316,27 +292,24 @@ docker run \ docker run \ -p 3567:3567 \ - // highlight-start -e POSTGRESQL_USER="username" \ -e POSTGRESQL_PASSWORD="password" \ -e POSTGRESQL_HOST="host" \ -e POSTGRESQL_PORT="5432" \ -e POSTGRESQL_DATABASE_NAME="supertokens" \ - // highlight-end -d supertokens/supertokens-postgresql ``` -:::tip -You can also provide the table schema by setting the `POSTGRESQL_TABLE_SCHEMA` option. +:::tip[You can also provide the table schema by setting the `POSTGRESQL_TABLE_SCHEMA` option.] ::: - - + + ##### Without docker - - + + ```yaml # You need to add the following to the config.yaml file. @@ -357,9 +330,9 @@ mysql_port: 3306 mysql_database_name: "supertokens" ``` - + - + ```yaml # You need to add the following to the config.yaml file. # The file path can be found by running the "supertokens --help" command @@ -382,11 +355,10 @@ postgresql_database_name: "supertokens" You can also provide the table schema by setting the `postgresql_table_schema` option. - - + + -:::info -The required tables should create automatically if the database user has table creation permission. +:::info[The required tables should create automatically if the database user has table creation permission.] If not, you can create them manually using the following snippet. @@ -1361,10 +1333,9 @@ SELECT * FROM key_value; If you see at least one row, it means that the connection has been successfully completed! -#### 4.4 Rename database tables {{optional}} +#### 4.4 Rename database tables (optional) -:::caution -If you already have tables created by SuperTokens, and then you rename them, SuperTokens creates new tables. Please be sure to migrate the data from the existing one to the new one. +:::warning[If you already have tables created by SuperTokens, and then you rename them, SuperTokens creates new tables. Please be sure to migrate the data from the existing one to the new one.] ::: You can add a prefix to all table names that SuperTokens manages. This way, all will be renamed in a way that has no clashes with your tables. @@ -1373,19 +1344,18 @@ For example, two tables created by SuperTokens have the names `emailpassword_use ##### For MySQL - - + + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-next-line -e MYSQL_TABLE_NAMES_PREFIX="my_prefix" \ -d supertokens/supertokens-mysql ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -1393,24 +1363,23 @@ docker run \ mysql_table_names_prefix: "my_prefix" ``` - - + + ##### For PostgreSQL - - + + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-next-line -e POSTGRESQL_TABLE_NAMES_PREFIX="my_prefix" \ -d supertokens/supertokens-postgresql ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -1418,8 +1387,8 @@ docker run \ postgresql_table_names_prefix: "my_prefix" ``` - - + + ### 5. Add license keys @@ -1430,10 +1399,10 @@ You can sign up on [**SuperTokens**](https://supertokens.com/auth) to receive on Once you have the license key you need to manually add it to your **SuperTokens Core Instance**. To do this you have to call the Core API with the following request: -```bash title="Add License Key" showAppTypeSelect -curl --location --request PUT ^{coreInfo.uri}/ee/license \ +```bash title="Add License Key" +curl --location --request PUT /ee/license \ --header 'Content-Type: application/json' \ - --header 'api-key: ^{coreInfo.key}' \ + --header 'api-key: ' \ --data-raw '{ "licenseKey": "" }' ``` @@ -1442,8 +1411,8 @@ curl --location --request PUT ^{coreInfo.uri}/ee/license \ ### Docker compose file - - + + ```bash version: '3' @@ -1490,9 +1459,9 @@ networks: driver: bridge ``` - + - + ```bash version: '3' @@ -1517,7 +1486,7 @@ services: retries: 5 supertokens: - image: supertokens/supertokens-postgresql^{docker_version_postgresql} + image: supertokens/supertokens-postgresql depends_on: db: condition: service_healthy @@ -1540,12 +1509,11 @@ networks: driver: bridge ``` - + - + -:::important -If you are running the backend process that integrates with the backend SDK as part of the docker compose file as well, make sure to use `http://supertokens:3567` as the connection URI instead of `http://localhost:3567`. +:::note[If you are running the backend process that integrates with the backend SDK as part of the docker compose file as well, make sure to use `http://supertokens:3567` as the connection URI instead of `http://localhost:3567`.] ::: ### Helm charts for Kubernetes @@ -1553,4 +1521,3 @@ If you are running the backend process that integrates with the backend SDK as p - For [MySQL image](https://github.com/supertokens/supertokens-docker-mysql/tree/master/helm-chart) - For [PostgreSQL image](https://github.com/supertokens/supertokens-docker-postgresql/tree/master/helm-chart) - diff --git a/docs/migration/_blocks/add-users-for-bulk-import-request.mdx b/docs/migration/_blocks/add-users-for-bulk-import-request.mdx deleted file mode 100644 index 44ca9784eb..0000000000 --- a/docs/migration/_blocks/add-users-for-bulk-import-request.mdx +++ /dev/null @@ -1,195 +0,0 @@ - - - - Stages users to be imported by a background cron job. - - - **Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. - - - - - -

Request

- -

Body Schema

- -| Name | Type | Description | Required | -|----------------|---------------------|-----------------------------------|----------| -| users | `Array` of `User` objects | The users that you want to import. The array has a limit of 10000 items. | Yes | - - -

User

- -| Name | Type | Description | Required | -|----------------|------------------------|-------------------------------------------------------------------------------------------------|----------| -| externalUserId | `string` | ID that can be used to reference the users from your previous provider | No | -| `userMetadata` | `object` | An object with custom user information that can be used later on | No | -| `userRoles` | `array` of `UserRole` | The roles that will be used for authorization | No | -| `totpDevices` | `array` of `TotpDevice` | Time-based One-time Password device (TOTP) used for Multi-Factor Authentication | Yes | -| `loginMethods` | `array` of `LoginMethod` | The actual authentication methods and credentials | Yes | - -##### TotpDevice - -| Name | Type | Description | Required | -|------------|---------------------|-----------------------------------------------------------------------------|----------| -| `secretKey` | `string` | The secret key used to generate the TOTP codes. | Yes | -| period | `number` | The time period in seconds for which a TOTP code is valid. | Yes | -| skew | `number` | The allowable time skew to account for clock differences between the server and device. | Yes | -| `deviceName` | `string` | The name assigned to the TOTP device for identification purposes. | No | - - -

UserRole

- -| Name | Type | Description | Required | -|------------|---------------------|-----------------------------------------------------------------------------|----------| -| role | `string` | The actual role name | Yes | -| tenantIds | Array of `string` | The tenants that use this role. If you are not using the `multi-tenancy` just pass an empty array. | Yes | - -##### LoginMethod - -`LoginMethod` is a polymorphic type with multiple variants based on the `recipeId`. Each variant includes shared and specific fields. - -###### EmailPassword - -###### With Encrypted Password - -| Name | Type | Description | Required | -|-------------------------|-----------------------|-------------------------------------------------------------------------------------------------|----------| -| email | `string` | User's email address | Yes | -| `passwordHash` | `string` | Hashed password | Yes | -| `hashingAlgorithm` | `enum` (`"bcrypt"`, `"argon2"`, `"firebase_scrypt"`) | Hashing algorithm used. | Yes | -| `recipeId` | `string` | Must be `emailpassword` | Yes | -| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | -| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | -| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | -| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | -| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | - -###### With Plain Password - -| Name | Type | Description | Required | -|-------------------------|-----------------------|-------------------------------------------------------------------------------------------------|----------| -| email | `string` | User's email address | Yes | -| `plaintextPassword` | `string` | A plain text password that will be hashed based on the configured hashing algorithm | Yes | -| `recipeId` | `string` | Must be `emailpassword` | Yes | -| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | -| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | -| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | -| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | -| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | - -##### ThirdParty - | Name | Type | Description | Required | - |------------------|--------|-------------------------------|----------| - | `recipeId` | `string` | Must be `"thirdparty"` | Yes | - | email | `string` | User's email address | Yes | - | thirdPartyId | `string` | Identifier for the third party provider | Yes | - | thirdPartyUserId | `string` | User identifier from the third party provider | Yes | -| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | -| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | -| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | -| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | -| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | - -##### Passwordless - - | Name | Type | Description | Required | - |----------|--------|-----------------------|----------| - | `recipeId` | `string` | Must be `"passwordless"` | Yes | - | email | `string` | User's email address | One of `email` or `phoneNumber` must be provided | - | `phoneNumber` | `string` | User's phone number | One of `email` or `phoneNumber` must be provided | -| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | -| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | -| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | -| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | -| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | - - -

Example

- -```bash -curl --location --request POST '^{coreInfo.uri}/bulk-import/users' \ - --header 'api-key: ^{coreInfo.key}' \ - --header 'Content-Type: application/json; charset=utf-8' \ - --data-raw '{ - users: [ - { - "externalUserId": "user_2", - "userMetadata": { - "firstName": "John", - "lastName": "Doe", - "department": "Marketing" - }, - "userRoles": [{ "role": "editor", "tenantIds": [] }], - "loginMethods": [ - { - "isVerified": true, - "isPrimary": true, - "timeJoinedInMSSinceEpoch": 1672617599000, - "recipeId": "thirdparty", - "email": "john.doe@gmail.com", - "thirdPartyId": "google", - "thirdPartyUserId": "google_987654321" - } - ] - } - ] -} -``` - -

Response

- -

200

-All the users have been added to the `bulk_import_users` table. - -

Example

- -```json -{ - "status": "OK", -} -``` - -

400

- -The request body was invalid. - -

Example

- -```json -```json -{ - error: "Failed to add users for the bulk import. Please fix the error in the following users", - users: [ - { - index: 11, - errors: ["No two loginMethods can have isPrimary as true."] - }, - { - index: 15, - errors: ["email is required for recipeId emailpassword", "hashingAlgorithm must be one of 'bcrypt', 'argon2', or 'firebase_scrypt'."] - } - ] -} -``` - -##### Errors - -- Account linking must be enabled if more than one login method is provided for a user. -- Multitenancy must be enabled if a `tenantId` is other than `public.` -- No two `loginMethods` can have `isPrimary` as `true`. -- Invalid `appId` or `tenantId`. -- A valid `email` is required. -- A valid `passwordHash` is required. -- `hashingAlgorithm` must be one of 'bcrypt', 'argon2', or `firebase_scrypt`. -- A valid `email` is required. -- `thirdPartyUserId` is required. -- A valid `email` or `phoneNumber` is required. - - -

500

- -An internal server error occurred. - -
diff --git a/docs/migration/_blocks/bulk-import-user-request.mdx b/docs/migration/_blocks/bulk-import-user-request.mdx deleted file mode 100644 index 06e2520106..0000000000 --- a/docs/migration/_blocks/bulk-import-user-request.mdx +++ /dev/null @@ -1,172 +0,0 @@ - - - - Creates one user at a time based on the request body. - - - - -**Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. - - - - - - -

Request

- -

Body Schema

- -| Name | Type | Description | Required | -|----------------|------------------------|-------------------------------------------------------------------------------------------------|----------| -| externalUserId | `string` | ID that can be used to reference the users from your previous provider | No | -| `userMetadata` | `object` | An object with custom user information that can be used later on | No | -| `userRoles` | `array` of `UserRole` | The roles that will be used for authorization | No | -| `totpDevices` | `array` of `TotpDevice` | Time-based One-time Password device (TOTP) used for Multi-Factor Authentication | Yes | -| `loginMethods` | `array` of `LoginMethod` | The actual authentication methods and credentials | Yes | - -

TotpDevice

- -| Name | Type | Description | Required | -|------------|---------------------|-----------------------------------------------------------------------------|----------| -| `secretKey` | `string` | The secret key used to generate the TOTP codes. | Yes | -| period | `number` | The time period in seconds for which a TOTP code is valid. | Yes | -| skew | `number` | The allowable time skew to account for clock differences between the server and device. | Yes | -| `deviceName` | `string` | The name assigned to the TOTP device for identification purposes. | No | - -

UserRole

- -| Name | Type | Description | Required | -|------------|---------------------|-----------------------------------------------------------------------------|----------| -| role | `string` | The actual role name | Yes | -| tenantIds | Array of `string` | The tenants that use this role. If you are not using the `multi-tenancy` just pass an empty array. | Yes | - -

LoginMethod

- -`LoginMethod` is a polymorphic type with multiple variants based on the `recipeId`. Each variant includes shared and specific fields. - -##### EmailPassword - -###### With Encrypted Password - -| Name | Type | Description | Required | -|-------------------------|-----------------------|-------------------------------------------------------------------------------------------------|----------| -| email | `string` | User's email address | Yes | -| `passwordHash` | `string` | Hashed password | Yes | -| `hashingAlgorithm` | `enum` (`"bcrypt"`, `"argon2"`, `"firebase_scrypt"`) | Hashing algorithm used. | Yes | -| `recipeId` | `string` | Must be `emailpassword` | Yes | -| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | -| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | -| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | -| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | -| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | - -###### With Plain Password - -| Name | Type | Description | Required | -|-------------------------|-----------------------|-------------------------------------------------------------------------------------------------|----------| -| email | `string` | User's email address | Yes | -| `plaintextPassword` | `string` | A plain text password that will be hashed based on the configured hashing algorithm | Yes | -| `recipeId` | `string` | Must be `emailpassword` | Yes | -| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | -| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | -| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | -| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | -| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | - - -##### ThirdParty - | Name | Type | Description | Required | - |------------------|--------|-------------------------------|----------| - | `recipeId` | `string` | Must be `"thirdparty"` | Yes | - | email | `string` | User's email address | Yes | - | thirdPartyId | `string` | Identifier for the third party provider | Yes | - | thirdPartyUserId | `string` | User identifier from the third party provider | Yes | -| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | -| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | -| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | -| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | -| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | - -##### Passwordless - - | Name | Type | Description | Required | - |----------|--------|-----------------------|----------| - | `recipeId` | `string` | Must be `"passwordless"` | Yes | - | email | `string` | User's email address | One of `email` or `phoneNumber` must be provided | - | `phoneNumber` | `string` | User's phone number | One of `email` or `phoneNumber` must be provided | -| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | -| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | -| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | -| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | -| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | - -

Example

- -```bash -curl --location --request POST '^{coreInfo.uri}/bulk-import/import' \ - --header 'api-key: ^{coreInfo.key}' \ - --header 'Content-Type: application/json; charset=utf-8' \ - --data ' - { - "externalUserId": "user_12345", - "userMetadata": { - "firstName": "Jane", - "lastName": "Doe", - "department": "Engineering" - }, - "userRoles": [{ "role": "admin", "tenantIds": [] }], - "totpDevices": [ - { - "secretKey": "JBSWY3DPEHPK3PXP", - "period": 30, - "skew": 1, - "deviceName": "Main Device" - } - ], - "loginMethods": [ - { - "isVerified": true, - "isPrimary": true, - "timeJoinedInMSSinceEpoch": 1672531199000, - "recipeId": "emailpassword", - "email": "jane.doe@example.com", - "passwordHash": "$2b$12$KIXQeFz...", - "hashingAlgorithm": "bcrypt" - } - ] - } -' -``` - -

Response

- -

200

-The user has been successfully created. - -

Example

- -```json -{ - "status": "OK", - "user": { /* User Object */ } -} -``` - -

400

- -The request body was invalid. - -

Example

- -```json -{ - "errors": ["No two loginMethods can have isPrimary as true.", "email is required for recipeId emailpassword", "hashingAlgorithm must be one of 'bcrypt', 'argon2', or 'firebase_scrypt'."]} -} -``` - -

500

- -An internal server error occurred. - -
diff --git a/docs/migration/_blocks/count-staged-users-request.mdx b/docs/migration/_blocks/count-staged-users-request.mdx deleted file mode 100644 index df3433b2ba..0000000000 --- a/docs/migration/_blocks/count-staged-users-request.mdx +++ /dev/null @@ -1,53 +0,0 @@ - - - - Returns the total number of users that were staged for import. - The value can be filtered by status. - - - **Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. - - - - - -

Request

- -

Query Parameters

- -| Name | Type | Description | Required | -|----------------|---------------------|-----------------------------------|----------| -| status | `enum` (`"NEW"`, `"PROCESSING"`, `"FAILED"`) | Can be used to count only users with a specific status. | No | - -

Example

- -```bash - curl --location --request GET '^{coreInfo.uri}/bulk-import/users/count?status=PROCESSING' \ - --header 'api-key: ^{coreInfo.key}' \ - --header 'Content-Type: application/json; charset=utf-8' \ -``` - -

Response

- -

200

- -The users have been successfully retrieved. - -

Example

- -```json -{ - "status": "OK", - "count": "", -} -``` - -

400

- -The tenant or the specified app have not been found. - -

500

- -An internal server error occurred. - -
diff --git a/docs/migration/_blocks/get-staged-users-request.mdx b/docs/migration/_blocks/get-staged-users-request.mdx deleted file mode 100644 index ff43ff4db0..0000000000 --- a/docs/migration/_blocks/get-staged-users-request.mdx +++ /dev/null @@ -1,61 +0,0 @@ - - - - Retrieves a paginated list of users that have been staged for import (from the `bulk_import_users` table). - - - **Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. - - - - - -

Request

- -

Query Parameters

- -| Name | Type | Description | Required | -|----------------|---------------------|-----------------------------------|----------| -| status | `enum` (`"NEW"`, `"PROCESSING"`, `"FAILED"`) | Can be used to filter the returned values. | No | -| limit | `string` | The number of results that will be return. Defaults to 100 | No | -| `paginationToken` | `string` | String token used to get a new chunk of data | No | - -

Example

- -```bash -curl --location --request GET '^{coreInfo.uri}/bulk-import/users?status=FAILED' \ - --header 'api-key: ^{coreInfo.key}' \ - --header 'Content-Type: application/json; charset=utf-8' \ -``` - -

Response

- -

User Schema

- -| Property | Type | Description | -|-------------|----------------------------------|-----------------------------------------------| -| id | `string` | Unique identifier for the user. | -| `raw_data` | `Object` | The initial data that you have added through the `/bulk-import/add-users` endpoint.| -| status | `string` (`"NEW"`, `"PROCESSING"`, `"FAILED"`) | Current status of the user. | -| `error_msg` | `Array` of `string` | List of error messages associated with the import process.| -| `created_at`| `string` (`date-time` format) | Timestamp when the user was created. | -| `updated_at`| `string` (`date-time` format) | Timestamp when the user was last updated. | - -

200

- -The users have been successfully retrieved. - -

Example

- -```json -{ - "users": [{ /* Array of Users */ }], - "nextPaginationToken": "" -} -``` - -

500

- -An internal server error occurred. - -
diff --git a/docs/migration/_category_.json b/docs/migration/_category_.json deleted file mode 100644 index 2b5ba9642a..0000000000 --- a/docs/migration/_category_.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "label": "Migration", - "collapsible": true, - "collapsed": true, - "customProps": { - "isMainCategory": true - }, - "position": 6 -} diff --git a/docs/migration/account-migration.mdx b/docs/migration/account-migration.mdx index 7a8fa40320..87fc82c953 100644 --- a/docs/migration/account-migration.mdx +++ b/docs/migration/account-migration.mdx @@ -1,26 +1,14 @@ --- title: Account Migration -hide_title: true -sidebar_position: 2 -toc_max_heading_level: 4 description: Migrate your users from a legacy authentication provider to SuperTokens. -page_type: tutorial -category: migration +sidebar: + order: 2 --- +The following guide will show you how to move your users from your current authentication solution to **SuperTokens** -import BulkImportUserRequest from "./_blocks/bulk-import-user-request.mdx" -import BulkImportUsersCountRequest from "./_blocks/count-staged-users-request.mdx" -import BulkImportUsersGetRequest from "./_blocks/get-staged-users-request.mdx" -import BulkImportUsersAddRequest from "./_blocks/add-users-for-bulk-import-request.mdx" - -# Account migration - - - The following guide will show you how to move your users from your current authentication solution to **SuperTokens** - +--- - ## Overview @@ -41,11 +29,10 @@ This happens through the bulk import API. The process is asynchronous and can work with large amounts of data. - ## Before you start This guide assumes that you have already integrated **SuperTokens** with your existing stack. -If you have not, please check the [Quickstart Guide](/docs/quickstart/introduction) and explore all the supported [authentication methods](/docs/authentication/overview). +If you have not, please check the [Quickstart Guide](/quickstart/introduction) and explore all the supported [authentication methods](/authentication/overview). ## Steps @@ -56,11 +43,9 @@ Modify the legacy sign up flow logic to also create new users in **SuperTokens** You can do this through the `Import User` endpoint that allows you to directly create accounts. Call the endpoint from the authentication flow used by your legacy provider. - -## Auth0 Instructions - - -:::warning no-title + + +:::warning Auth0 does not expose password hashes or `TOTP` device information. You will have to contact their support separately if you need this type of data. ::: @@ -180,22 +165,21 @@ function mapProvider(strategy) { return mapping[strategy] || strategy; } ``` - + -
+
-:::info -If your application does not have a sign up process or if new users get created manually you can skip this step +:::info[If your application does not have a sign up process or if new users get created manually you can skip this step] ::: - - + + ```bash -curl --location --request POST '^{coreInfo.uri}/bulk-import/import' \ - --header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/bulk-import/import' \ + --header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data ' { @@ -229,12 +213,12 @@ curl --location --request POST '^{coreInfo.uri}/bulk-import/import' \ ' ``` - - + + ```tsx - const BASE_URL = '^{coreInfo.uri}'; - const API_KEY = '^{coreInfo.key}'; + const BASE_URL = ''; + const API_KEY = ''; const url = `${BASE_URL}/bulk-import/import`; const options = { @@ -279,8 +263,8 @@ curl --location --request POST '^{coreInfo.uri}/bulk-import/import' \ .catch(err => console.error(err)); ``` - - + + ```go @@ -292,8 +276,8 @@ curl --location --request POST '^{coreInfo.uri}/bulk-import/import' \ ) func main() { - baseUrl := "^{coreInfo.uri}" - apiKey := "^{coreInfo.key}" + baseUrl := "" + apiKey := "" url := fmt.Sprintf("%s/bulk-import/import", baseUrl) payload := `{ "externalUserId": "user_12345", @@ -339,15 +323,15 @@ curl --location --request POST '^{coreInfo.uri}/bulk-import/import' \ } ``` - - + + ```python import requests from typing import Dict, Any - BASE_URL = "^{coreInfo.uri}" - API_KEY = "^{coreInfo.key}" + BASE_URL = "" + API_KEY = "" url = f"{BASE_URL}/bulk-import/import" @@ -390,21 +374,190 @@ curl --location --request POST '^{coreInfo.uri}/bulk-import/import' \ print(response.json()) ``` - - - - - + + + + + Creates one user at a time based on the request body. + + + + +**Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. + + + + + + + ## Request + + ### Body Schema + +| Name | Type | Description | Required | +|----------------|------------------------|-------------------------------------------------------------------------------------------------|----------| +| externalUserId | `string` | ID that can be used to reference the users from your previous provider | No | +| `userMetadata` | `object` | An object with custom user information that can be used later on | No | +| `userRoles` | `array` of `UserRole` | The roles that will be used for authorization | No | +| `totpDevices` | `array` of `TotpDevice` | Time-based One-time Password device (TOTP) used for Multi-Factor Authentication | Yes | +| `loginMethods` | `array` of `LoginMethod` | The actual authentication methods and credentials | Yes | + +#### TotpDevice + +| Name | Type | Description | Required | +|------------|---------------------|-----------------------------------------------------------------------------|----------| +| `secretKey` | `string` | The secret key used to generate the TOTP codes. | Yes | +| period | `number` | The time period in seconds for which a TOTP code is valid. | Yes | +| skew | `number` | The allowable time skew to account for clock differences between the server and device. | Yes | +| `deviceName` | `string` | The name assigned to the TOTP device for identification purposes. | No | + +#### UserRole + +| Name | Type | Description | Required | +|------------|---------------------|-----------------------------------------------------------------------------|----------| +| role | `string` | The actual role name | Yes | +| tenantIds | Array of `string` | The tenants that use this role. If you are not using the `multi-tenancy` just pass an empty array. | Yes | + +#### LoginMethod + +`LoginMethod` is a polymorphic type with multiple variants based on the `recipeId`. Each variant includes shared and specific fields. + +##### EmailPassword +###### With Encrypted Password + +| Name | Type | Description | Required | +|-------------------------|-----------------------|-------------------------------------------------------------------------------------------------|----------| +| email | `string` | User's email address | Yes | +| `passwordHash` | `string` | Hashed password | Yes | +| `hashingAlgorithm` | `enum` (`"bcrypt"`, `"argon2"`, `"firebase_scrypt"`) | Hashing algorithm used. | Yes | +| `recipeId` | `string` | Must be `emailpassword` | Yes | +| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | +| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | +| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | +| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | +| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | + +###### With Plain Password + +| Name | Type | Description | Required | +|-------------------------|-----------------------|-------------------------------------------------------------------------------------------------|----------| +| email | `string` | User's email address | Yes | +| `plaintextPassword` | `string` | A plain text password that will be hashed based on the configured hashing algorithm | Yes | +| `recipeId` | `string` | Must be `emailpassword` | Yes | +| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | +| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | +| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | +| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | +| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | + + +##### ThirdParty + | Name | Type | Description | Required | + |------------------|--------|-------------------------------|----------| + | `recipeId` | `string` | Must be `"thirdparty"` | Yes | + | email | `string` | User's email address | Yes | + | thirdPartyId | `string` | Identifier for the third party provider | Yes | + | thirdPartyUserId | `string` | User identifier from the third party provider | Yes | +| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | +| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | +| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | +| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | +| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | + +##### Passwordless + + | Name | Type | Description | Required | + |----------|--------|-----------------------|----------| + | `recipeId` | `string` | Must be `"passwordless"` | Yes | + | email | `string` | User's email address | One of `email` or `phoneNumber` must be provided | + | `phoneNumber` | `string` | User's phone number | One of `email` or `phoneNumber` must be provided | +| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | +| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | +| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | +| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | +| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | + +### Example + +```bash +curl --location --request POST '/bulk-import/import' \ + --header 'api-key: ' \ + --header 'Content-Type: application/json; charset=utf-8' \ + --data ' + { + "externalUserId": "user_12345", + "userMetadata": { + "firstName": "Jane", + "lastName": "Doe", + "department": "Engineering" + }, + "userRoles": [{ "role": "admin", "tenantIds": [] }], + "totpDevices": [ + { + "secretKey": "JBSWY3DPEHPK3PXP", + "period": 30, + "skew": 1, + "deviceName": "Main Device" + } + ], + "loginMethods": [ + { + "isVerified": true, + "isPrimary": true, + "timeJoinedInMSSinceEpoch": 1672531199000, + "recipeId": "emailpassword", + "email": "jane.doe@example.com", + "passwordHash": "$2b$12$KIXQeFz...", + "hashingAlgorithm": "bcrypt" + } + ] + } +' +``` + +## Response + +### 200 +The user has been successfully created. + +#### Example + +```json +{ + "status": "OK", + "user": { /* User Object */ } +} +``` + +### 400 + +The request body was invalid. + +#### Example + +```json +{ + "errors": ["No two loginMethods can have isPrimary as true.", "email is required for recipeId emailpassword", "hashingAlgorithm must be one of 'bcrypt', 'argon2', or 'firebase_scrypt'."]} +} +``` + +### 500 + +An internal server error occurred. + + + + ### 2. Export the accounts from your legacy provider Export the users from your legacy authentication provider and adjust the data to match the request body schema used in the [**`Add Users for Bulk Import`**](#add-users-for-bulk-import-http-request) endpoint. - -## Auth0 Instructions -:::warning no-title + + +:::warning Auth0 does not export password hashes or `TOTP` device information. You will have to contact their support and request them. ::: @@ -489,7 +642,7 @@ cat auth0_users.json | jq -s '.' > auth0_users_array.json #### 6. Transform the data to the SuperTokens format -:::warning no-title +:::warning Auth0 does not expose password hashes or `TOTP` device information. You will have to contact their support separately if you need this type of data. ::: @@ -584,7 +737,7 @@ function mapProvider(auth0Provider) { console.log(`Transformed ${superTokensUsers.length} users`); ``` - + ### 3. Perform the bulk migration process @@ -605,12 +758,12 @@ This step stages the data that the background job imports later. Keep in mind that the endpoint has a limit of **10000 users** per request. - - + + ```bash -curl --location --request POST '^{coreInfo.uri}/bulk-import/users' \ - --header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/bulk-import/users' \ + --header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ users: [ @@ -638,12 +791,12 @@ curl --location --request POST '^{coreInfo.uri}/bulk-import/users' \ } ``` - - + + ```tsx - const BASE_URL = '^{coreInfo.uri}'; - const API_KEY = '^{coreInfo.key}'; + const BASE_URL = ''; + const API_KEY = ''; const url = `${BASE_URL}/bulk-import/users`; const options = { @@ -684,8 +837,8 @@ curl --location --request POST '^{coreInfo.uri}/bulk-import/users' \ .catch(err => console.error(err)); ``` - - + + ```go import ( @@ -696,8 +849,8 @@ curl --location --request POST '^{coreInfo.uri}/bulk-import/users' \ ) func main() { - baseUrl := "^{coreInfo.uri}" - apiKey := "^{coreInfo.key}" + baseUrl := "" + apiKey := "" url := fmt.Sprintf("%s/bulk-import/users", baseUrl) payload := `{ "users": [ @@ -738,15 +891,15 @@ curl --location --request POST '^{coreInfo.uri}/bulk-import/users' \ } ``` - - + + ```python import requests from typing import Dict, Any - BASE_URL = "^{coreInfo.uri}" - API_KEY = "^{coreInfo.key}" + BASE_URL = "" + API_KEY = "" url = f"{BASE_URL}/bulk-import/users" @@ -785,13 +938,206 @@ curl --location --request POST '^{coreInfo.uri}/bulk-import/users' \ print(response.json()) ``` - - - - - + + + + + Stages users to be imported by a background cron job. + + + **Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. + + + + + + ## Request + + ### Body Schema + +| Name | Type | Description | Required | +|----------------|---------------------|-----------------------------------|----------| +| users | `Array` of `User` objects | The users that you want to import. The array has a limit of 10000 items. | Yes | + + +#### User + +| Name | Type | Description | Required | +|----------------|------------------------|-------------------------------------------------------------------------------------------------|----------| +| externalUserId | `string` | ID that can be used to reference the users from your previous provider | No | +| `userMetadata` | `object` | An object with custom user information that can be used later on | No | +| `userRoles` | `array` of `UserRole` | The roles that will be used for authorization | No | +| `totpDevices` | `array` of `TotpDevice` | Time-based One-time Password device (TOTP) used for Multi-Factor Authentication | Yes | +| `loginMethods` | `array` of `LoginMethod` | The actual authentication methods and credentials | Yes | + +##### TotpDevice + +| Name | Type | Description | Required | +|------------|---------------------|-----------------------------------------------------------------------------|----------| +| `secretKey` | `string` | The secret key used to generate the TOTP codes. | Yes | +| period | `number` | The time period in seconds for which a TOTP code is valid. | Yes | +| skew | `number` | The allowable time skew to account for clock differences between the server and device. | Yes | +| `deviceName` | `string` | The name assigned to the TOTP device for identification purposes. | No | + + +#### UserRole + +| Name | Type | Description | Required | +|------------|---------------------|-----------------------------------------------------------------------------|----------| +| role | `string` | The actual role name | Yes | +| tenantIds | Array of `string` | The tenants that use this role. If you are not using the `multi-tenancy` just pass an empty array. | Yes | + +##### LoginMethod + +`LoginMethod` is a polymorphic type with multiple variants based on the `recipeId`. Each variant includes shared and specific fields. + +###### EmailPassword + +###### With Encrypted Password + +| Name | Type | Description | Required | +|-------------------------|-----------------------|-------------------------------------------------------------------------------------------------|----------| +| email | `string` | User's email address | Yes | +| `passwordHash` | `string` | Hashed password | Yes | +| `hashingAlgorithm` | `enum` (`"bcrypt"`, `"argon2"`, `"firebase_scrypt"`) | Hashing algorithm used. | Yes | +| `recipeId` | `string` | Must be `emailpassword` | Yes | +| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | +| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | +| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | +| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | +| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | + +###### With Plain Password -:::info The Bulk Import Cron Job +| Name | Type | Description | Required | +|-------------------------|-----------------------|-------------------------------------------------------------------------------------------------|----------| +| email | `string` | User's email address | Yes | +| `plaintextPassword` | `string` | A plain text password that will be hashed based on the configured hashing algorithm | Yes | +| `recipeId` | `string` | Must be `emailpassword` | Yes | +| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | +| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | +| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | +| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | +| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | + +##### ThirdParty + | Name | Type | Description | Required | + |------------------|--------|-------------------------------|----------| + | `recipeId` | `string` | Must be `"thirdparty"` | Yes | + | email | `string` | User's email address | Yes | + | thirdPartyId | `string` | Identifier for the third party provider | Yes | + | thirdPartyUserId | `string` | User identifier from the third party provider | Yes | +| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | +| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | +| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | +| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | +| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | + +##### Passwordless + + | Name | Type | Description | Required | + |----------|--------|-----------------------|----------| + | `recipeId` | `string` | Must be `"passwordless"` | Yes | + | email | `string` | User's email address | One of `email` or `phoneNumber` must be provided | + | `phoneNumber` | `string` | User's phone number | One of `email` or `phoneNumber` must be provided | +| tenantIds | Array of `string` | The tenant IDs that the user belongs to (if you are using the `multi-tenancy` feature) | No | +| externalUserId | `string` | ID that can be used to reference the users from your previous provider only for this authentication method | No | +| `isVerified` | `boolean` | Indicates whether the user's email has been verified | No | +| `isPrimary` | `boolean` | Indicates whether this is the user's primary authentication method | No | +| timeJoinedInMSSinceEpoch| `number` | Timestamp representing when the user joined, in milliseconds since the Unix epoch | No | + + +### Example + +```bash +curl --location --request POST '/bulk-import/users' \ + --header 'api-key: ' \ + --header 'Content-Type: application/json; charset=utf-8' \ + --data-raw '{ + users: [ + { + "externalUserId": "user_2", + "userMetadata": { + "firstName": "John", + "lastName": "Doe", + "department": "Marketing" + }, + "userRoles": [{ "role": "editor", "tenantIds": [] }], + "loginMethods": [ + { + "isVerified": true, + "isPrimary": true, + "timeJoinedInMSSinceEpoch": 1672617599000, + "recipeId": "thirdparty", + "email": "john.doe@gmail.com", + "thirdPartyId": "google", + "thirdPartyUserId": "google_987654321" + } + ] + } + ] +} +``` + +## Response + +### 200 +All the users have been added to the `bulk_import_users` table. + +#### Example + +```json +{ + "status": "OK", +} +``` + +### 400 + +The request body was invalid. + +#### Example + +```json +```json +{ + error: "Failed to add users for the bulk import. Please fix the error in the following users", + users: [ + { + index: 11, + errors: ["No two loginMethods can have isPrimary as true."] + }, + { + index: 15, + errors: ["email is required for recipeId emailpassword", "hashingAlgorithm must be one of 'bcrypt', 'argon2', or 'firebase_scrypt'."] + } + ] +} +``` + +##### Errors + +- Account linking must be enabled if more than one login method is provided for a user. +- Multitenancy must be enabled if a `tenantId` is other than `public.` +- No two `loginMethods` can have `isPrimary` as `true`. +- Invalid `appId` or `tenantId`. +- A valid `email` is required. +- A valid `passwordHash` is required. +- `hashingAlgorithm` must be one of 'bcrypt', 'argon2', or `firebase_scrypt`. +- A valid `email` is required. +- `thirdPartyUserId` is required. +- A valid `email` or `phoneNumber` is required. + + +### 500 + +An internal server error occurred. + + + + + +:::info[The Bulk Import Cron Job] Every 5 minutes the **SuperTokens** core service runs a cron job that goes through the staged users and tries to import them. If a user gets imported successfully it gets removed from the staged list. @@ -821,21 +1167,21 @@ Given that information, to check if your import is complete do the following: 3. If the only rows that remain are the ones with the `FAILED` status, then proceed to step `3.3`. There you can see how to debug those issues. - - + + ```bash - curl --location --request GET '^{coreInfo.uri}/bulk-import/users/count?status=PROCESSING' \ - --header 'api-key: ^{coreInfo.key}' \ + curl --location --request GET '``/bulk-import/users/count?status=PROCESSING' \ + --header 'api-key: ``' \ --header 'Content-Type: application/json; charset=utf-8' \ ``` - - + + ```tsx - const BASE_URL = '^{coreInfo.uri}'; - const API_KEY = '^{coreInfo.key}'; + const BASE_URL = `''`; + const API_KEY = `''`; const url = `${BASE_URL}/bulk-import/users/count?status=PROCESSING`; const options = { @@ -852,8 +1198,8 @@ Given that information, to check if your import is complete do the following: .catch(err => console.error(err)); ``` - - + + ```go import ( @@ -863,8 +1209,8 @@ Given that information, to check if your import is complete do the following: ) func main() { - baseUrl := "^{coreInfo.uri}" - apiKey := "^{coreInfo.key}" + baseUrl := "``" + apiKey := "``" url := fmt.Sprintf("%s/bulk-import/users/count?status=PROCESSING", baseUrl) req, _ := http.NewRequest("GET", url, nil) @@ -882,14 +1228,14 @@ Given that information, to check if your import is complete do the following: } ``` - - + + ```python import requests - BASE_URL = "^{coreInfo.uri}" - API_KEY = "^{coreInfo.key}" + BASE_URL = "``" + API_KEY = "``" url = f"{BASE_URL}/bulk-import/users/count?status=PROCESSING" @@ -903,12 +1249,63 @@ Given that information, to check if your import is complete do the following: print(response.json()) ``` - + - - - - + + + + Returns the total number of users that were staged for import. + The value can be filtered by status. + + + **Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. + + + + + + ## Request + + ### Query Parameters + +| Name | Type | Description | Required | +|----------------|---------------------|-----------------------------------|----------| +| status | `enum` (`"NEW"`, `"PROCESSING"`, `"FAILED"`) | Can be used to count only users with a specific status. | No | + +### Example + +```bash + curl --location --request GET '``/bulk-import/users/count?status=PROCESSING' \ + --header 'api-key: ``' \ + --header 'Content-Type: application/json; charset=utf-8' \ +``` + +## Response + +### 200 + +The users have been successfully retrieved. + +#### Example + +```json +{ + "status": "OK", + "count": "", +} +``` + +### 400 + +The tenant or the specified app have not been found. + +### 500 + +An internal server error occurred. + + + + #### 3.3 Handle staged users that failed to import @@ -921,21 +1318,21 @@ This can happen for a number of reasons. Some common ones: If at the end of the previous step you have determined that you have staged users that failed to import debug the issues with the `get users` API. - - + + ```bash - curl --location --request GET '^{coreInfo.uri}/bulk-import/users?status=FAILED' \ - --header 'api-key: ^{coreInfo.key}' \ + curl --location --request GET '``/bulk-import/users?status=FAILED' \ + --header 'api-key: ``' \ --header 'Content-Type: application/json; charset=utf-8' \ ``` - - + + ```tsx - const BASE_URL = '^{coreInfo.uri}'; - const API_KEY = '^{coreInfo.key}'; + const BASE_URL = `''`; + const API_KEY = `''`; const url = `${BASE_URL}/bulk-import/users?status=FAILED`; const options = { @@ -952,8 +1349,8 @@ If at the end of the previous step you have determined that you have staged user .catch(err => console.error(err)); ``` - - + + ```go import ( @@ -963,8 +1360,8 @@ If at the end of the previous step you have determined that you have staged user ) func main() { - baseUrl := "^{coreInfo.uri}" - apiKey := "^{coreInfo.key}" + baseUrl := "``" + apiKey := "``" url := fmt.Sprintf("%s/bulk-import/users?status=FAILED", baseUrl) req, _ := http.NewRequest("GET", url, nil) @@ -982,14 +1379,14 @@ If at the end of the previous step you have determined that you have staged user } ``` - - + + ```python import requests - BASE_URL = "^{coreInfo.uri}" - API_KEY = "^{coreInfo.key}" + BASE_URL = "``" + API_KEY = "``" url = f"{BASE_URL}/bulk-import/users?status=FAILED" @@ -1003,12 +1400,70 @@ If at the end of the previous step you have determined that you have staged user print(response.json()) ``` - - - - - + + + + + Retrieves a paginated list of users that have been staged for import (from the `bulk_import_users` table). + + + **Authorization**: Set the `api-key` header to the value of your **SuperTokens** Core API key. + + + + + + ## Request + + ### Query Parameters + +| Name | Type | Description | Required | +|----------------|---------------------|-----------------------------------|----------| +| status | `enum` (`"NEW"`, `"PROCESSING"`, `"FAILED"`) | Can be used to filter the returned values. | No | +| limit | `string` | The number of results that will be return. Defaults to 100 | No | +| `paginationToken` | `string` | String token used to get a new chunk of data | No | + +### Example + +```bash +curl --location --request GET '``/bulk-import/users?status=FAILED' \ + --header 'api-key: ``' \ + --header 'Content-Type: application/json; charset=utf-8' \ +``` +## Response + +### User Schema + +| Property | Type | Description | +|-------------|----------------------------------|-----------------------------------------------| +| id | `string` | Unique identifier for the user. | +| `raw_data` | `Object` | The initial data that you have added through the `/bulk-import/add-users` endpoint.| +| status | `string` (`"NEW"`, `"PROCESSING"`, `"FAILED"`) | Current status of the user. | +| `error_msg` | `Array` of `string` | List of error messages associated with the import process.| +| `created_at`| `string` (`date-time` format) | Timestamp when the user was created. | +| `updated_at`| `string` (`date-time` format) | Timestamp when the user was last updated. | + +### 200 + +The users have been successfully retrieved. + +#### Example + +```json +{ + "users": [{ /* Array of Users */ }], + "nextPaginationToken": "" +} +``` + +### 500 + +An internal server error occurred. + + + + The response includes the import error messages for each specific user. @@ -1016,22 +1471,20 @@ Use them to determine what you need to correct in your import data. After you have fixed the issues, run the process again, from step `3.1`, only for the corrected data. - -:::success You have successfully migrated your accounts +:::success[You have successfully migrated your accounts] If all your data has imported then you can consider the account migration process complete. -Go on to the [session migration](/docs/migration/session-migration) step to complete the entire migration flow. +Go on to the [session migration](/migration/session-migration) step to complete the entire migration flow. ::: ## See also - - - - - - - + + + + + + diff --git a/docs/migration/legacy/_category_.json b/docs/migration/legacy/_category_.json deleted file mode 100644 index 588fbdf24f..0000000000 --- a/docs/migration/legacy/_category_.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "label": "Legacy Method", - "collapsible": true, - "collapsed": true, - "customProps": {}, - "position": 4 -} diff --git a/docs/migration/legacy/about.mdx b/docs/migration/legacy/about.mdx index c72f329045..fdbdab862a 100644 --- a/docs/migration/legacy/about.mdx +++ b/docs/migration/legacy/about.mdx @@ -1,14 +1,9 @@ --- -id: about title: About -hide_title: true -sidebar_position: 1 -page_type: overview -category: migration +sidebar: + order: 1 --- -# About - In this guide we will be going through the process of migrating users from an external Authentication provider to SuperTokens. User migration involves 3 steps: @@ -47,16 +42,16 @@ User migration involves 3 steps: You can learn more about how to implement these changes in the [Session Migration](./session-migration) section. ## Step 4. MFA migration -If you are using MFA in your app, checkout the MFA migration section [here](/docs/additional-verification/mfa/migration/legacy-to-new) after you have gone through the above migration steps. +If you are using MFA in your app, checkout the MFA migration section [here](/additional-verification/mfa/migration/legacy-to-new) after you have gone through the above migration steps. --- ## See also - - - - - - - + + + + + + + diff --git a/docs/migration/legacy/account-creation/_category_.json b/docs/migration/legacy/account-creation/_category_.json deleted file mode 100644 index 7f6ff1cac7..0000000000 --- a/docs/migration/legacy/account-creation/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Step 1: Account Creation", - "position": 2 -} diff --git a/docs/migration/legacy/account-creation/email-verification.mdx b/docs/migration/legacy/account-creation/email-verification.mdx index 399d794e5a..baded390a5 100644 --- a/docs/migration/legacy/account-creation/email-verification.mdx +++ b/docs/migration/legacy/account-creation/email-verification.mdx @@ -1,14 +1,9 @@ --- -id: email-verification title: Mark email as verified -hide_title: true -sidebar_position: 3 -page_type: guide -category: migration +sidebar: + order: 3 --- -# Mark email as verified - Once a SuperTokens user has been created and their userId has been mapped, you need to mark their email as verified, if their email was verified in the old auth provider. ## Step 1. Generating the email verification token: @@ -16,8 +11,8 @@ Once a SuperTokens user has been created and their userId has been mapped, you n For example with the email as `johnDoe@gmail.com` and userId as `056f4b02-c992-42ed-a8af-cb709669bbd` ```bash -curl --location --request POST '^{coreInfo.uri}/recipe/user/email/verify/token' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/recipe/user/email/verify/token' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "email": "johnDoe@gmail.com", @@ -39,8 +34,8 @@ Successfully generating an email verification token will result in the following Retrieve the token from the response of the previous request and set it in the body of the email verification request. ```bash -curl --location --request POST '^{coreInfo.uri}/recipe/user/email/verify' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/recipe/user/email/verify' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "method": "token", diff --git a/docs/migration/legacy/account-creation/ep-migration-without-password-hash.mdx b/docs/migration/legacy/account-creation/ep-migration-without-password-hash.mdx index 0bb01568aa..dfca6ff76f 100644 --- a/docs/migration/legacy/account-creation/ep-migration-without-password-hash.mdx +++ b/docs/migration/legacy/account-creation/ep-migration-without-password-hash.mdx @@ -1,16 +1,10 @@ --- -id: ep-migration-without-password-hash title: User Creation without password hashes -hide_title: true -sidebar_position: 4 -page_type: guide -category: migration +sidebar: + order: 4 --- - -# User Creation without password hashes - -:::caution +:::warning The recommended method for migrating users to SuperTokens is by [importing users with their password hashes](./user-creation). You should only use the following method if you do not have access to your user's password hashes and still have access to your previous identity provider. ::: @@ -36,8 +30,8 @@ We need to make the following customizations to SuperTokens authentication flows To implement this change we override the API that handles email-password login when initializing the recipe on the backend. - - + + ```tsx import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -69,9 +63,9 @@ async function doesUserExistInExternalProvider(email: string): Promise } ``` - + - + ```python from typing import Any, Dict, List, Union @@ -127,7 +121,7 @@ async def does_user_exist_in_external_provider(email: str): init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( override=emailpassword.InputOverrideConfig( @@ -138,9 +132,9 @@ init( ) ``` - + - + ```go import ( @@ -196,9 +190,9 @@ func doesUserExistInExternalProvider(email string) bool { } ``` - + - + We modify the `signUpPOST` API to first check if the user signing up has an account with the external provider. If they do we return a `EMAIL_ALREADY_EXISTS_ERROR` @@ -206,8 +200,8 @@ We modify the `signUpPOST` API to first check if the user signing up has an acco To implement this flow we override the API that handles email-password login when initializing the recipe on the backend. - - + + ```tsx import SuperTokens from "supertokens-node" @@ -284,9 +278,9 @@ async function validateAndGetUserInfoFromExternalProvider(email: string, passwor } ``` - + - + ```python from typing import Any, Dict, List, Union @@ -424,7 +418,7 @@ async def validate_and_get_user_info_from_external_provider( init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( override=emailpassword.InputOverrideConfig(apis=override_emailpassword_apis) @@ -433,9 +427,9 @@ init( ) ``` - + - + ```go import ( @@ -547,9 +541,9 @@ func validateAndGetUserInfoFromExternalProvider(email string, password string) * } ``` - + - + The code above overrides the `signInPOST` API with the following changes to achieve "**in time**" migration: - The first step is to determine if the user signing in needs to be migrated or not. We do this by checking if a user with the input email exists in the external auth provider and SuperTokens. @@ -565,8 +559,8 @@ If the credentials are valid we can call the SuperTokens login function with the Some users who do not have an account with SuperTokens but have an existing account with the external provider may have forgotten their passwords and initiate a password reset. Since password resets require an existing SuperTokens account to send the password reset email to, the password reset flow needs to be modified to create a SuperTokens account if the user exists in the external provider. - - + + ```tsx import SuperTokens from "supertokens-node" @@ -651,9 +645,9 @@ async function retrieveUserDataFromExternalProvider(email: string): Promise<{ return undefined; } ``` - + - + ```python from typing import Any, Dict, List, Union @@ -794,7 +788,7 @@ async def generate_password(): init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( override=emailpassword.InputOverrideConfig(apis=override_emailpassword_apis) @@ -803,9 +797,9 @@ init( ) ``` - + - + ```go import ( @@ -934,9 +928,9 @@ func generatePassword() string { } ``` - + - + The code above overrides the `generatePasswordResetTokenPOST` API. This is the first step in the password reset flow and is responsible for generating the password reset token to be sent with the reset password email. @@ -950,8 +944,8 @@ The code above overrides the `generatePasswordResetTokenPOST` API. This is the f If the password reset flow is successfully completed we need to check if the user has `isUsingTemporaryPassword` set in their metadata and remove it if it exists. - - + + ```tsx import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -979,9 +973,9 @@ EmailPassword.init({ } }) ``` - + - + ```python from typing import Any, Dict, List @@ -1036,7 +1030,7 @@ def override_emailpassword_apis(original_implementation: APIInterface): init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( override=emailpassword.InputOverrideConfig(apis=override_emailpassword_apis) @@ -1045,9 +1039,9 @@ init( ) ``` - + - + ```go import ( @@ -1106,9 +1100,9 @@ func main() { } ``` - + - + The code above overrides the `passwordResetPOST` API and is a continuation of the password reset flow: @@ -1122,10 +1116,10 @@ Apart from the changes we made in Step 1, we also need to account for users who - If a user initiates a password reset but remembers their password, they should be able to sign in. - In this case the user should be able to login and the database should be updated to reflect the new password. - - + + -```tsx +```tsx {58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword" import EmailVerification from "supertokens-node/recipe/emailverification"; @@ -1183,7 +1177,6 @@ EmailPassword.init({ } emailPasswordUser = signUpResponse.user; } - // highlight-start // Check if the user signing in has a temporary password let userMetadata = await UserMetadata.getUserMetadata(emailPasswordUser.id, input.userContext) if (userMetadata.status === "OK" && userMetadata.metadata.isUsingTemporaryPassword) { @@ -1206,7 +1199,6 @@ EmailPassword.init({ } } } - // highlight-end return originalImplementation.signInPOST!(input) }, @@ -1223,11 +1215,11 @@ async function validateAndGetUserInfoFromExternalProvider(email: string, passwor return undefined } ``` - + - + -```python +```python {117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152} from typing import Any, Dict, List, Union from supertokens_python import InputAppInfo, init @@ -1344,7 +1336,6 @@ def override_emailpassword_apis(original_implementation: APIInterface): ) emailpassword_user = response.user - # highlight-start # Check if the user signing in has a temporary password metadata_result = await get_user_metadata(emailpassword_user.id) if ( @@ -1381,7 +1372,6 @@ def override_emailpassword_apis(original_implementation: APIInterface): ) else: return WrongCredentialsError() - # highlight-end return await original_emailpassword_sign_in( form_fields, @@ -1410,7 +1400,7 @@ async def validate_and_get_user_info_from_external_provider( init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ emailpassword.init( override=emailpassword.InputOverrideConfig(apis=override_emailpassword_apis) @@ -1419,9 +1409,9 @@ init( ) ``` - + - + ```go import ( @@ -1570,9 +1560,9 @@ func validateAndGetUserInfoFromExternalProvider(email string, password string) * } ``` - + - + The code above adds the following changes to the `signInPOST` API: diff --git a/docs/migration/legacy/account-creation/meta.ts b/docs/migration/legacy/account-creation/meta.ts new file mode 100644 index 0000000000..b5907c81e0 --- /dev/null +++ b/docs/migration/legacy/account-creation/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Step 1: Account Creation", + "icon": "user-check", + "order": 2 +}); diff --git a/docs/migration/legacy/account-creation/user-creation.mdx b/docs/migration/legacy/account-creation/user-creation.mdx index c639d95243..c1d575ecde 100644 --- a/docs/migration/legacy/account-creation/user-creation.mdx +++ b/docs/migration/legacy/account-creation/user-creation.mdx @@ -1,18 +1,12 @@ --- -id: user-creation title: User Creation -hide_title: true -sidebar_position: 1 -page_type: guide -category: migration +sidebar: + order: 1 --- - -# User Creation - ## Email Password Migration -:::important +:::note If you do not have access to your user's password hashes, you can use our [guide for migrating them dynamically during login](./ep-migration-without-password-hash). ::: @@ -24,8 +18,8 @@ You can find the API spec [here](https://app.swaggerhub.com/apis/supertokens/CDI For users with `BCrypt` or `Argon2` password hashes you can use the following curl command to import your user. ```bash -curl --location --request POST '^{coreInfo.uri}/recipe/user/passwordhash/import' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/recipe/user/passwordhash/import' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "email": "johndoe@example.com", @@ -33,8 +27,7 @@ curl --location --request POST '^{coreInfo.uri}/recipe/user/passwordhash/import' }' ``` -:::important -SuperTokens accepts `BCrypt` and `Argon2` hashes in standard format. When exporting password hashes from authentication providers the structure might be changed. For example, Auth0 adds an identifier to the exported password hashes which needs to be removed before importing into SuperTokens. +:::note[SuperTokens accepts `BCrypt` and `Argon2` hashes in standard format. When exporting password hashes from authentication providers the structure might be changed. For example, Auth0 adds an identifier to the exported password hashes which needs to be removed before importing into SuperTokens.] Sample password hashes for `BCrypt` and Argon2 in standard format: @@ -49,7 +42,7 @@ Importing users from Firebases requires an update to your SuperTokens core confi #### Step 1: Retrieve your Firebase password hashing parameters from your dashboard. -Firebase password hashing details modal +Firebase password hashing details modal #### Step 2: Update the SuperTokens core to use the `base64_signer_key` @@ -60,21 +53,19 @@ Importing users from Firebases requires an update to your SuperTokens core confi - Set the `firebase_password_hashing_signer_key` field in the config to the `base64_signer_key` retrieved from your firebase hashing parameters. + - - - + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-next-line -e FIREBASE_PASSWORD_HASHING_SIGNER_KEY="gRhC3eDeQOdyEn4bMd9c6kxguWVmcIVq/HbJKnCXdWscZx0l2WbCJ1wbg==" \ -d supertokens/supertokens- ``` - - + + ```yaml # Add your base64_signer_key to the following in the config.yaml file. @@ -83,9 +74,8 @@ Importing users from Firebases requires an update to your SuperTokens core confi firebase_password_hashing_signer_key: "gRhC3eDeQOdyEn4bMd9c6kxguWVmcIVq/HbJKnCXdWscZx0l2WbCJ1wbg==" ``` - - - + + #### Step 3: SuperTokens requires firebase password hashes to be in a specific format to be parsed. @@ -122,9 +112,9 @@ firebase_password_hashing_signer_key: "gRhC3eDeQOdyEn4bMd9c6kxguWVmcIVq/HbJKnCXd #### Step 4: Run the following `curl` command to import the user ```bash -curl --location --request POST '^{coreInfo.uri}/recipe/user/passwordhash/import' \ +curl --location --request POST '/recipe/user/passwordhash/import' \ --header 'Content-Type: application/json; charset=utf-8' \ ---header 'api-key: ^{coreInfo.key}' \ +--header 'api-key: ' \ --data-raw '{ "email": "test@example.com", "passwordHash": "$f_scrypt$9Y8ICWcqbzmI42DxV1jpyEjbrJPG8EQ6nI6oC32JYz+/dd7aEjI/R7jG9P5kYh8v9gyqFKaXMDzMg7eLCypbOA==$/cj0jC1br5o4+w==$m=14$r=8$s=Bw==", @@ -142,8 +132,8 @@ To migrate a Passwordless user from your previous authentication provider to Sup **With Email** ```bash -curl --location --request POST '^{coreInfo.uri}/recipe/signinup/code' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/recipe/signinup/code' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "email": "johndoe@example.com" @@ -153,8 +143,8 @@ curl --location --request POST '^{coreInfo.uri}/recipe/signinup/code' \ **With Phone Number** ```bash -curl --location --request POST '^{coreInfo.uri}/recipe/signinup/code' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/recipe/signinup/code' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "phoneNumber": "+14155552671" @@ -181,8 +171,8 @@ On successfully generating the passwordless code you should see the following re Retrieve the `preAuthSessionId` and `linkCode` from the previous response and set them as request body parameters for the consume code request. ```bash -curl --location --request POST '^{coreInfo.uri}/recipe/signinup/code/consume' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/recipe/signinup/code/consume' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "preAuthSessionId": "d3Zpa9eoyV2Wr7uN5DLr6H1clzbwwGTc_0wIIXJT55M=", @@ -193,8 +183,8 @@ curl --location --request POST '^{coreInfo.uri}/recipe/signinup/code/consume' \ If the user has both email and password associated with them, then you can call the update user API to associate the missing information ```bash -curl --location --request PUT '^{coreInfo.uri}/recipe/user' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request PUT '/recipe/user' \ +--header 'api-key: ' \ --header 'rid: passwordless' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ @@ -214,8 +204,8 @@ For example: If we were importing a user with Google as their provider with their third party userId being `106347997792363870000`, we can run the following curl command to import the user. ```bash -curl --location --request POST '^{coreInfo.uri}/recipe/signinup' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/recipe/signinup' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "thirdPartyId": "google", @@ -231,10 +221,10 @@ curl --location --request POST '^{coreInfo.uri}/recipe/signinup' \ ## See also - - - - - - - + + + + + + + diff --git a/docs/migration/legacy/account-creation/user-id-mapping.mdx b/docs/migration/legacy/account-creation/user-id-mapping.mdx index 098e4f0c06..8e74ac9755 100644 --- a/docs/migration/legacy/account-creation/user-id-mapping.mdx +++ b/docs/migration/legacy/account-creation/user-id-mapping.mdx @@ -1,21 +1,16 @@ --- -id: user-id-mapping title: UserId Mapping -hide_title: true -sidebar_position: 2 -page_type: guide -category: migration +sidebar: + order: 2 --- -# UserId Mapping - UserId Mapping allows you to map existing userIds (from your old auth provider) to the SuperTokens userIds. This prevents you from having to update the existing `userIDs` in your application's table. As an example, if after creating the user in SuperTokens, their userId is `fa7a0841-b533-4478-95533-0fde890c3483` and the existing userId for that user is `customUserId`, then you can map these user IDs by calling the following API: ```bash -curl --location --request POST '^{coreInfo.uri}/recipe/userid/map' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request POST '/recipe/userid/map' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "superTokensUserId": "fa7a0841-b533-4478-95533-0fde890c3483", @@ -25,6 +20,6 @@ curl --location --request POST '^{coreInfo.uri}/recipe/userid/map' \ Now whenever this user signs in, or if you fetch information about this user from SuperTokens, their userID will be `customUserId`. -:::info Note +:::info[Note] The maximum allowed size of the `externalUserId` is 128 characters. ::: diff --git a/docs/migration/legacy/data-migration.mdx b/docs/migration/legacy/data-migration.mdx index d453597823..8f00e235c8 100644 --- a/docs/migration/legacy/data-migration.mdx +++ b/docs/migration/legacy/data-migration.mdx @@ -1,14 +1,9 @@ --- -id: data-migration title: Step 2. User Data Migration -hide_title: true -sidebar_position: 3 -page_type: tutorial -category: migration +sidebar: + order: 3 --- -# User Data Migration - Once your user accounts have been migrated over to SuperTokens, additional information like metadata, roles and permissions can be associated with the user. ## User Metadata Migration @@ -24,8 +19,8 @@ In this example we want to store the following metadata against our user: ``` ```bash -curl --location --request PUT '^{coreInfo.uri}/recipe/user/metadata' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request PUT '/recipe/user/metadata' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "userId": "5acb2dbc-04f0-4c80-822a-7f06cd658f6f", @@ -42,8 +37,8 @@ SuperTokens allows you to assign roles and permissions to a userId. In this example we will be assigning the `admin` role to a user: ```bash -curl --location --request PUT '^{coreInfo.uri}/recipe/user/role' \ ---header 'api-key: ^{coreInfo.key}' \ +curl --location --request PUT '/recipe/user/role' \ +--header 'api-key: ' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "role": "admin", @@ -52,18 +47,18 @@ curl --location --request PUT '^{coreInfo.uri}/recipe/user/role' \ }' ``` -:::info Important -Roles and permissions must be created before they can be assigned to a user. You can follow this [guide](/docs/additional-verification/user-roles/initial-setup) on creating roles and permissions in SuperTokens. +:::info[Important] +Roles and permissions must be created before they can be assigned to a user. You can follow this [guide](/additional-verification/user-roles/initial-setup) on creating roles and permissions in SuperTokens. ::: --- ## See also - - - - - - - + + + + + + + diff --git a/docs/migration/legacy/meta.ts b/docs/migration/legacy/meta.ts new file mode 100644 index 0000000000..b2375e31b0 --- /dev/null +++ b/docs/migration/legacy/meta.ts @@ -0,0 +1,8 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Legacy Method", + "icon": "history", + "order": 4, + "collapsed": true +}); diff --git a/docs/migration/legacy/mfa-migration.mdx b/docs/migration/legacy/mfa-migration.mdx index f84b4074d5..4a9a0191c1 100644 --- a/docs/migration/legacy/mfa-migration.mdx +++ b/docs/migration/legacy/mfa-migration.mdx @@ -1,12 +1,7 @@ --- -id: mfa-migration title: Step 4. MFA migration -hide_title: true -sidebar_position: 5 -page_type: guide -category: migration +sidebar: + order: 5 --- -# MFA migration - -If you are using MFA in your app, checkout the MFA migration section [here](/docs/additional-verification/mfa/migration/legacy-to-new) after you have gone through the previous steps in migration. +If you are using MFA in your app, checkout the MFA migration section [here](/additional-verification/mfa/migration/legacy-to-new) after you have gone through the previous steps in migration. diff --git a/docs/migration/legacy/session-migration.mdx b/docs/migration/legacy/session-migration.mdx index b4e59cfd26..3eb3063570 100644 --- a/docs/migration/legacy/session-migration.mdx +++ b/docs/migration/legacy/session-migration.mdx @@ -1,14 +1,9 @@ --- -id: session-migration title: Step 3. Session Migration -hide_title: true -sidebar_position: 4 -page_type: guide -category: migration +sidebar: + order: 4 --- -# Session Migration - In this section we will go over how to migrate your user sessions from you previous authentication provider to SuperTokens. This process involves two steps. @@ -17,7 +12,7 @@ This process involves two steps. ## Flow -Session migration flow chart +Session migration flow chart ### Backend Changes: @@ -40,7 +35,6 @@ app.post("/migrate-session", async (req, res) => { // create a new SuperTokens session using the customUserId // the createNewSession function will attach the SuperTokens session tokens to the response object. - // @ts-ignore await Session.createNewSession(req, res, customUserId) res.send({ status: "OK" @@ -58,12 +52,12 @@ async function verifyAccessTokenAndRetriveUserId(access_token: string): Promise< ``` -:::info Important +:::info[Important] Verifying the access token will require you to access your previous providers JWKS endpoint, which means that you will have to continue to use your previous auth provider even after switching to SuperTokens. If you want to immediately stop querying your previous authentication provider you can use the JWKS public keys and provide them as a secret to the JWT verification function. -You can follow our [guide](/docs/additional-verification/session-verification/protect-api-routes) on how to do this. +You can follow our [guide](/additional-verification/session-verification/protect-api-routes) on how to do this. ::: ### Frontend Changes: @@ -110,10 +104,10 @@ async function revokeSessionFromOldProvider() { ## See also - - - - - - - + + + + + + + diff --git a/docs/migration/meta.ts b/docs/migration/meta.ts new file mode 100644 index 0000000000..deb10dde6d --- /dev/null +++ b/docs/migration/meta.ts @@ -0,0 +1,8 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Migration", + "icon": "arrow-right", + "order": 6, + "collapsed": true +}); diff --git a/docs/migration/overview.mdx b/docs/migration/overview.mdx index b54432ec84..99e412c078 100644 --- a/docs/migration/overview.mdx +++ b/docs/migration/overview.mdx @@ -1,27 +1,20 @@ --- title: Overview -hide_title: true -sidebar_position: 1 -pagination_prev: null description: Get a high-level overview of the migration process. -page_type: overview -category: migration +sidebar: + order: 1 --- +The **Migration** section covers instructions on how you can move your authentication data from your current authentication solution to **SuperTokens** -# Overview - - - The **Migration** section covers instructions on how you can move your authentication data from your current authentication solution to **SuperTokens** - +--- - ## Before You Start -The migration steps are intended to be executed after you have configured your [initial **SuperTokens** integration](/docs/quickstart/introduction). +The migration steps are intended to be executed after you have configured your [initial **SuperTokens** integration](/quickstart/introduction). Hence, to complete any of the next instructions you will need the following: -- An existing application that has a working **SuperTokens** integration. You can follow the [quickstart guide](/docs/quickstart/introduction) for instructions on how to achieve this. +- An existing application that has a working **SuperTokens** integration. You can follow the [quickstart guide](/quickstart/introduction) for instructions on how to achieve this. - A **SuperTokens** managed service account or a self-hosted **SuperTokens Core** instance. More specifically, you will have to make HTTP requests to your `CORE_API_ENDPOINT` using an `API_KEY`. @@ -31,26 +24,21 @@ More specifically, you will have to make HTTP requests to your `CORE_API_ENDPOIN The entire migration process can be broken down into two steps. Both are required to achieve a seamless transition. -1. [**Account Migration**](/docs/migration/account-migration/) +1. [**Account Migration**](/migration/account-migration/) This is the main part of the migration flow. You will be importing your users, together with their account credentials, from the legacy authentication provider into **SuperTokens**. -2. [**Session Migration**](/docs/migration/session-migration) +2. [**Session Migration**](/migration/session-migration) This step prevents any users with active sessions from experiencing authentication issues. You will extend the **SuperTokens** functionality to create new sessions for users that have authenticated using your legacy provider. -:::info - -You need to keep using your legacy authentication provider until you have implemented all the migration steps. +:::info[You need to keep using your legacy authentication provider until you have implemented all the migration steps.] After that, you can go ahead and switch to **SuperTokens** in your production application. ::: -With that in mind, you can now move to the first step, the [**Account Migration**](/docs/migration/account-migration/) process. - - - +With that in mind, you can now move to the first step, the [**Account Migration**](/migration/account-migration/) process. diff --git a/docs/migration/rownd/_category_.json b/docs/migration/rownd/_category_.json deleted file mode 100644 index d071b7e3f8..0000000000 --- a/docs/migration/rownd/_category_.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "label": "Rownd Migration", - "collapsible": true, - "collapsed": true, - "customProps": {}, - "position": 5 -} diff --git a/docs/migration/rownd/meta.ts b/docs/migration/rownd/meta.ts new file mode 100644 index 0000000000..cf11a7a87b --- /dev/null +++ b/docs/migration/rownd/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Rownd Migration", + "order": 5, + "collapsed": true +}); diff --git a/docs/migration/rownd/migration-steps.mdx b/docs/migration/rownd/migration-steps.mdx index 1d56a5d8da..8983790bbd 100644 --- a/docs/migration/rownd/migration-steps.mdx +++ b/docs/migration/rownd/migration-steps.mdx @@ -1,20 +1,13 @@ --- title: Migration Steps -hide_title: true -sidebar_position: 1 -toc_max_heading_level: 3 description: Understand the Rownd to SuperTokens migration process. -page_type: tutorial -category: migration +sidebar: + order: 1 --- -# Migration steps +Move your Rownd users, sessions, and compatible authentication flows to **SuperTokens** without any breaking changes - - Move your Rownd users, sessions, and compatible authentication flows to **SuperTokens** without any breaking changes - - - +--- ## Overview @@ -33,9 +26,9 @@ Compared to Rownd, in SuperTokens you have to: Each step of the migration process requires an existing SuperTokens backend integration in your application. The following steps give you an overview over the process. -For detailed instructions on how to integrate SDKs you can read [the full guide](/docs/migration/rownd/sdk-integration-guide). +For detailed instructions on how to integrate SDKs you can read [the full guide](/migration/rownd/sdk-integration-guide). -:::info no-title +:::info The migration flow is not designed to be self service. Please get in touch with the [SuperTokens team](mailto:support@supertokens.com) for assistance during the whole process. @@ -58,7 +51,7 @@ The migration will copy all your existing users from the Rownd account to the ne ### 3. Cutover Replace the Rownd client SDKs with the SuperTokens Rownd-compatible clients. -The [SDK integration guide](/docs/migration/rownd/sdk-integration-guide) goes into detail on how to do this. +The [SDK integration guide](/migration/rownd/sdk-integration-guide) goes into detail on how to do this. After cutover, authentication traffic goes through SuperTokens while your application uses Rownd-compatible APIs. @@ -70,7 +63,6 @@ Authentication UIs are preserved as well as the Rownd specific session claims. ## Next steps -Continue with the [SDK Integration Guide](/docs/migration/rownd/sdk-integration-guide). The backend plugin must be deployed before clients can migrate sessions or use SuperTokens-backed Rownd flows. +Continue with the [SDK Integration Guide](/migration/rownd/sdk-integration-guide). The backend plugin must be deployed before clients can migrate sessions or use SuperTokens-backed Rownd flows. After the backend is working, use the same guide to configure your frontend or mobile client platform. - diff --git a/docs/migration/rownd/sdk-integration-guide.mdx b/docs/migration/rownd/sdk-integration-guide.mdx index 646d684cf3..9bed17426a 100644 --- a/docs/migration/rownd/sdk-integration-guide.mdx +++ b/docs/migration/rownd/sdk-integration-guide.mdx @@ -1,20 +1,14 @@ --- title: SDK Integration Guide -hide_title: true -sidebar_position: 2 -toc_max_heading_level: 3 description: Configure the SuperTokens Rownd backend plugin and frontend SDKs. -page_type: tutorial -category: migration +sidebar: + order: 2 --- -# SDK integration guide +Configure the SuperTokens Rownd backend plugin and frontend SDKs to migrate users, create SuperTokens sessions, and keep using Rownd-style APIs. - - Configure the SuperTokens Rownd backend plugin and frontend SDKs to migrate users, create SuperTokens sessions, and keep using Rownd-style APIs. - +--- - ## Overview @@ -27,11 +21,11 @@ These instructions assume that you have already created an account in [the Super After you have done that, select the relevant **Managed** deployment, enable **Account Linking** from **Features**, and copy the core connection information from **Overview**. -:::info no-title +:::info The Rownd compatibility plugin is only available with NodeJS or Python at the moment. If your main backend uses another language or unsupported framework, deploy the NodeJS or Python backend as an authentication sidecar and route Rownd/SuperTokens auth traffic to it. -Read [the complete guide](/docs/references/backend-sdks/other-frameworks) for more information on how to set it up. +Read [the complete guide](/references/backend-sdks/other-frameworks) for more information on how to set it up. ::: @@ -40,57 +34,55 @@ Read [the complete guide](/docs/references/backend-sdks/other-frameworks) for mo ### 1. Configure the backend SDK - + - + #### 1.1 Install the SuperTokens SDK and Rownd plugin Install the base SuperTokens backend SDK together with the Rownd migration plugin. The SuperTokens SDK adds the auth middleware, recipe APIs, and session handling. The Rownd plugin adds the Rownd-compatible migration, Hub, profile, and OAuth compatibility routes. - + - + ```bash npm install supertokens-node @supertokens-plugins/rownd-nodejs ``` - + - + ```bash yarn add supertokens-node @supertokens-plugins/rownd-nodejs ``` - + - + ```bash pnpm add supertokens-node @supertokens-plugins/rownd-nodejs ``` - + - + ```bash bun add supertokens-node @supertokens-plugins/rownd-nodejs ``` - + - + #### 1.2 Initialize SuperTokens Initialize the recipes that map to your Rownd auth methods, then add the Rownd plugin under `experimental.plugins`. -:::info - -Contact the SuperTokens team before finalizing this setup for a complete plugin `appConfig` object based on your existing Rownd configuration. +:::info[Contact the SuperTokens team before finalizing this setup for a complete plugin `appConfig` object based on your existing Rownd configuration.] ::: @@ -222,9 +214,7 @@ SuperTokens.init({ Install SuperTokens middleware after CORS handling. -:::important - -- Add the `middleware` BEFORE all your routes. +:::note[- Add the `middleware` BEFORE all your routes.] - Add the `cors` middleware BEFORE the SuperTokens middleware as shown below. ::: @@ -276,39 +266,39 @@ If no explicit key is sent: - Browser Hub flows use `clientDomains.browser`. - If the selected key is missing, the plugin keeps the link on the Hub URL and only rewrites the path. - + - + #### 1.1 Install the SuperTokens SDK and Rownd plugin Install the base SuperTokens Python SDK together with the Rownd migration plugin from [PyPI](https://pypi.org/project/supertokens-rownd/). - + - + ```bash pip install supertokens-python supertokens-rownd ``` - + - + ```bash uv add supertokens-python supertokens-rownd ``` - + - + #### 1.2 Initialize SuperTokens Python plugin configuration must include `api_base_path`, `api_domain`, `website_domain`, and `app_name` explicitly. Keep these values in sync with `InputAppInfo`. -:::info no-title +:::info Contact the SuperTokens team before finalizing this setup for a complete plugin `app_config` object based on your existing Rownd configuration. @@ -498,11 +488,11 @@ If no explicit key is sent: - Browser Hub flows use `client_domains["browser"]`. - If the selected key is missing, the plugin keeps the link on the Hub URL and only rewrites the path. - + - + -#### 1.5 Configure Apple login for iOS {{optional}} +#### 1.5 Configure Apple login for iOS (optional) If your iOS app uses native Sign in with Apple, configure Apple as multiple SuperTokens clients. Browser and Hub Apple login use the Apple Services ID, but native iOS Apple login returns authorization codes for your app bundle ID. @@ -510,9 +500,9 @@ The iOS bundle ID must therefore be configured as a separate Apple client in the The Rownd plugin maps the Apple sign-in method to those SuperTokens client types. The plugin setting is `iosClientType`, which becomes `ios_client_type` in the Rownd app config. The iOS SDK reads that value and sends it as `clientType` when it exchanges the Apple authorization code with `/signinup`. - + - + ```ts ThirdParty.init({ @@ -558,9 +548,9 @@ RowndMigrationPlugin.init({ }); ``` - + - + ```python thirdparty.init( @@ -606,9 +596,9 @@ RowndPluginConfig( ) ``` - + - + If Android uses a separate Apple client, add another SuperTokens Apple client with `clientType: "android"` and set `androidClientType: "android"` on the Rownd Apple sign-in method. @@ -623,47 +613,47 @@ Every client needs the same values configured on the backend: - `apiBasePath`: the SuperTokens API base path, for example ``. - `clientDomain`: optional key from the backend `clientDomains` map. - + - + #### 2.1 Install the React SDK - + - + ```bash npm install @supertokens/rownd-react ``` - + - + ```bash yarn add @supertokens/rownd-react ``` - + - + ```bash pnpm add @supertokens/rownd-react ``` - + - + ```bash bun add @supertokens/rownd-react ``` - + - + #### 2.2 Add the provider @@ -727,9 +717,9 @@ export function AuthControls() { `requestSignIn()` supports Rownd-style options such as `identifier`, `auto_sign_in`, `init_data`, `post_login_redirect`, `include_user_data`, `redirect`, `intent`, `group_to_join`, `prevent_closing`, `method`, and `method_options`. - + - + #### 2.1 Load the hosted Hub script @@ -777,9 +767,9 @@ Use `window._rphConfig` for optional settings that are easier to set in JavaScri Add `_rphConfig` entries before the Hub script loads. - + - + #### 2.1 Add the Android SDK @@ -821,9 +811,7 @@ android { #### 2.3 Configure deep links -:::important - -Contact the SuperTokens team before configuring production deep links. We need to set up the link asset files for your Hub domain, including Android App Links metadata. +:::note[Contact the SuperTokens team before configuring production deep links. We need to set up the link asset files for your Hub domain, including Android App Links metadata.] ::: @@ -884,9 +872,9 @@ val client = OkHttpClient.Builder() .build() ``` - + - + #### 2.1 Add the iOS SDK @@ -928,9 +916,7 @@ func application( #### 2.3 Configure links -:::important - -Contact the SuperTokens team before configuring production Universal Links. We need to set up the link asset files for your Hub domain, including the Apple App Site Association file. +:::note[Contact the SuperTokens team before configuring production Universal Links. We need to set up the link asset files for your Hub domain, including the Apple App Site Association file.] ::: @@ -980,9 +966,9 @@ func application( The Universal Link domain should match `clientDomains.mobile` on the backend. - + - + #### 2.1 Install the Flutter SDK @@ -1156,55 +1142,53 @@ cd ios && pod update lottie-ios --repo-update #### 2.6 Configure mobile links -:::important - -Contact the SuperTokens team before configuring production deep links or Universal Links. We need to set up the link asset files for your Hub domain for the native platforms your Flutter app supports. +:::note[Contact the SuperTokens team before configuring production deep links or Universal Links. We need to set up the link asset files for your Hub domain for the native platforms your Flutter app supports.] ::: Configure the same native link handling described in the Android and iOS tabs for Flutter's Android and iOS host apps. The HTTPS App Link or Universal Link domain should match `clientDomains.mobile` on the backend. - + - + #### 2.1 Install the React Native SDK - + - + ```bash npm install @supertokens/rownd-react-native ``` - + - + ```bash yarn add @supertokens/rownd-react-native ``` - + - + ```bash pnpm add @supertokens/rownd-react-native ``` - + - + ```bash bun add @supertokens/rownd-react-native ``` - + - + React Native apps must use React Native `0.61` or newer. Native builds also need Android `minSdkVersion` `26` or newer and iOS deployment target `14.0` or newer. @@ -1270,9 +1254,7 @@ The React Native provider accepts `appKey`, `supertokens.appInfo`, `deepLinkSche #### 2.4 Register native links -:::important - -Contact the SuperTokens team before configuring production deep links. We need to set up the link asset files for your Hub domain for the native platforms your React Native app supports. +:::note[Contact the SuperTokens team before configuring production deep links. We need to set up the link asset files for your Hub domain for the native platforms your React Native app supports.] ::: @@ -1392,9 +1374,9 @@ export function AuthControls() { `requestSignIn()` accepts Rownd-style options such as `method`, `postSignInRedirect`, and `intent`. The `guest` method is treated as `anonymous`. On Android, forcing `email` or `phone` currently opens the Hub default flow rather than bypassing the method selector. - + - + ### 3. Validate client flows @@ -1405,7 +1387,7 @@ Test the following flows to validate your client integration: - Existing Rownd sessions migrate without forcing users to sign in again. - Deep links work as expected on mobile -### 4. Migrate OAuth/OIDC clients {{optional}} +### 4. Migrate OAuth/OIDC clients (optional) If your Rownd application acts as an OAuth/OIDC provider, update clients to use SuperTokens discovery and endpoints after the SuperTokens team migrates your Rownd OAuth clients into SuperTokens Core. diff --git a/docs/migration/session-migration.mdx b/docs/migration/session-migration.mdx index bd248ed6ac..a182f4d0a9 100644 --- a/docs/migration/session-migration.mdx +++ b/docs/migration/session-migration.mdx @@ -1,24 +1,14 @@ --- -id: session-migration title: Session Migration -hide_title: true -sidebar_position: 3 -pagination_next: null -description: >- - Migrate user sessions from your previous authentication provider to - SuperTokens using backend and frontend changes. -page_type: tutorial -category: migration +description: Migrate user sessions from your previous authentication provider to SuperTokens using backend and frontend changes. +sidebar: + order: 3 --- +This guide will show you how to migrate your user sessions from you previous authentication provider to **SuperTokens**. -# Session Migration - - - This guide will show you how to migrate your user sessions from you previous authentication provider to **SuperTokens**. - +--- - ## Overview @@ -27,7 +17,7 @@ To do this you should create a new flow that will determine if an existing user You can see a detailed illustration of the process below. -Session migration flow chart +Session migration flow chart ## Steps @@ -53,7 +43,6 @@ app.post("/migrate-session", async (req, res) => { // create a new SuperTokens session using the customUserId // the createNewSession function will attach the SuperTokens session tokens to the response object. - // @ts-ignore await Session.createNewSession(req, res, customUserId) res.send({ status: "OK" @@ -71,13 +60,13 @@ async function verifyAccessTokenAndRetriveUserId(access_token: string): Promise< ``` -:::info Important +:::info[Important] Verifying the access token will require you to access your previous providers JWKS endpoint. This means that you will have to continue to use your previous auth provider even after switching to SuperTokens. If you want to immediately stop querying your previous authentication provider you can use the JWKS public keys and provide them as a secret to the JWT verification function. -You can follow our [guide](/docs/additional-verification/session-verification/protect-api-routes#with-the-public-key-string) on how to do this. +You can follow our [guide](/additional-verification/session-verification/protect-api-routes#with-the-public-key-string) on how to do this. ::: ### 2. Call the migration endpoint from your frontend app @@ -123,10 +112,8 @@ async function revokeSessionFromOldProvider() { ## See also - - - - - - - + + + + + diff --git a/docs/platform-configuration/_category_.json b/docs/platform-configuration/_category_.json deleted file mode 100644 index 3fb78a0e60..0000000000 --- a/docs/platform-configuration/_category_.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "label": "Platform Configuration", - "collapsible": true, - "collapsed": true, - "customProps": { - "isMainCategory": true - }, - "position": 7 -} diff --git a/docs/platform-configuration/email-delivery.mdx b/docs/platform-configuration/email-delivery.mdx index 00e13d9dcc..46764118f7 100644 --- a/docs/platform-configuration/email-delivery.mdx +++ b/docs/platform-configuration/email-delivery.mdx @@ -1,15 +1,10 @@ --- title: Email delivery -hide_title: true -sidebar_position: 3 description: Customize email delivery methods. -page_type: guide -category: platform-configuration +sidebar: + order: 3 --- - -# Email delivery - ## Overview SuperTokens sends emails in different authentication scenarios. @@ -24,8 +19,7 @@ The following page shows you how to configure the email delivery method and adju If you provide no configuration for email delivery, the backend SDK sends emails by talking to the servers on `https://api.supertokens.com` This applies to both self hosted and managed services. -:::important -- No info sent to the API that sends out emails on behalf of your app is logged or stored. +:::note[- No info sent to the API that sends out emails on behalf of your app is logged or stored.] - The system sends emails using `noreply@supertokens.io` email ID. If you want to use your own domain, please see one of the other methods in this section. - You cannot customize the email template when using this method. If you want to customize the emails, please see one of the other methods in this section. - Emails sent via the service are free and may land up in user's spam due to the high number of apps that use the service. If you want to avoid this, we recommend using one of the other methods mentioned in this section. @@ -41,10 +35,10 @@ Use this method if you want to: - Optionally customize the default email template and subject. - - + + -```tsx +```tsx {8,9,10,11,12,13,14,15,16,17,18,28,29,30,36,37,38} import supertokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -52,7 +46,6 @@ import { SMTPService } from "supertokens-node/recipe/emailpassword/emaildelivery import EmailVerification from "supertokens-node/recipe/emailverification" import { SMTPService as EmailVerificationSMTPService } from "supertokens-node/recipe/emailverification/emaildelivery"; -// highlight-start let smtpSettings = { host: "...", authUsername: "...", // this is optional. In case not given, from.email will be used @@ -64,7 +57,6 @@ let smtpSettings = { }, secure: true } -// highlight-end supertokens.init({ appInfo: { @@ -74,30 +66,26 @@ supertokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start emailDelivery: { service: new SMTPService({smtpSettings}) }, - // highlight-end }), // if email verification is enabled.. EmailVerification.init({ mode: "OPTIONAL", - // highlight-start emailDelivery: { service: new EmailVerificationSMTPService({smtpSettings}) } - // highlight-end }), Session.init() ] }); ``` - - + + -```go +```go {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,35,36,37,38,39,44,45,46,47,48} import ( "github.com/supertokens/supertokens-golang/ingredients/emaildelivery" "github.com/supertokens/supertokens-golang/recipe/emailpassword" @@ -110,7 +98,6 @@ import ( ) func main() { - // highlight-start smtpUsername := "..." smtpSettings := emaildelivery.SMTPSettings{ Host: "...", @@ -129,44 +116,38 @@ func main() { // ... }, } - // highlight-end supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ emailpassword.Init(&epmodels.TypeInput{ - // highlight-start EmailDelivery: &emaildelivery.TypeInput{ Service: emailpassword.MakeSMTPService(emaildelivery.SMTPServiceConfig{ Settings: smtpSettings, }), }, - // highlight-end }), // if email verification is enabled emailverification.Init(evmodels.TypeInput{ - // highlight-start EmailDelivery: &emaildelivery.TypeInput{ Service: emailverification.MakeSMTPService(emaildelivery.SMTPServiceConfig{ Settings: smtpSettings, }), }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {6,7,8,9,10,11,12,13,14,15,16,24,25,26,27,28,34,35,36,37,38} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailpassword from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConfig, SMTPSettingsFrom, SMTPSettings from supertokens_python.recipe import emailverification -# highlight-start smtp_settings = SMTPSettings( host="...", port=465, @@ -178,49 +159,44 @@ smtp_settings = SMTPSettings( secure=False, username="..." # this is optional. In case not given, from_.email will be used ) -# highlight-end init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( - # highlight-start email_delivery=EmailDeliveryConfig( service=emailpassword.SMTPService( smtp_settings=smtp_settings ) ) - # highlight-end ), # If email verification is enabled emailverification.init( mode="OPTIONAL", - # highlight-start email_delivery=EmailDeliveryConfig( service=emailverification.SMTPService( smtp_settings=smtp_settings ) ) - # highlight-end ) ] ) ``` - - + + ### Custom method This method allows you to define your own email sending abstraction. - - + + -```tsx +```tsx {14,15,16,17,18,19,20,21,22,23,24,25,26,27,33,34,35,36,37,38,39,40,41,42,43,44,45,46} import supertokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -234,7 +210,6 @@ supertokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start emailDelivery: { override: (originalImplementation) => { return { @@ -249,13 +224,11 @@ supertokens.init({ } } }, - // highlight-end }), // if email verification is enabled EmailVerification.init({ mode: "OPTIONAL", - // highlight-start emailDelivery: { override: (originalImplementation) => { return { @@ -270,16 +243,15 @@ supertokens.init({ } } }, - // highlight-end }), Session.init() ] }); ``` - - + + -```go +```go {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48} import ( "github.com/supertokens/supertokens-golang/ingredients/emaildelivery" "github.com/supertokens/supertokens-golang/recipe/emailpassword" @@ -293,7 +265,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ emailpassword.Init(&epmodels.TypeInput{ - // highlight-start EmailDelivery: &emaildelivery.TypeInput{ Override: func(originalImplementation emaildelivery.EmailDeliveryInterface) emaildelivery.EmailDeliveryInterface { originalSendEmail := *originalImplementation.SendEmail @@ -309,13 +280,11 @@ func main() { return originalImplementation }, }, - // highlight-end }), // if email verification is enabled emailverification.Init(evmodels.TypeInput{ Mode: evmodels.ModeRequired, - // highlight-start EmailDelivery: &emaildelivery.TypeInput{ Override: func(originalImplementation emaildelivery.EmailDeliveryInterface) emaildelivery.EmailDeliveryInterface { originalSendEmail := *originalImplementation.SendEmail @@ -331,16 +300,15 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {41,47} from supertokens_python import init, InputAppInfo from supertokens_python.recipe.emailpassword.types import EmailDeliveryOverrideInput, EmailTemplateVars from supertokens_python.recipe import emailpassword @@ -378,30 +346,28 @@ def custom_emailverification_delivery(original_implementation: EVEmailDeliveryOv init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( - # highlight-next-line email_delivery=EmailDeliveryConfig(override=custom_email_deliver) ), # If email verification is enabled emailverification.init( mode="OPTIONAL", - # highlight-next-line email_delivery=EmailDeliveryConfig(override=custom_emailverification_delivery)) ] ) ``` - - + + If you call the original implementation function for `sendEmail`, it uses the service that you have configured. If you have not configured any service, it uses the default service. Using this method, you can, for example, have your custom way of sending email verification emails, but use the default or SMTP service to send the reset password emails. -:::important Error Management +:::note[Error Management] To handle failures and other types of issues in the `sendEmail` function throw an error. The SDK catches any exception through an upper level error handler. This error is then propagated if this is through an API call or otherwise logged. ::: @@ -410,8 +376,8 @@ To handle failures and other types of issues in the `sendEmail` function throw a ## Email content customization You can access the default email UI through the following links: -- Default [email verification template](/docs/references/frontend-sdks/prebuilt-ui/ui-showcase#email-verification) and its [source code](https://github.com/supertokens/email-sms-templates/blob/master/email-html/email-verification.html). -- Default [password reset template](/docs/references/frontend-sdks/prebuilt-ui/ui-showcase#password-reset) and its [source code](https://github.com/supertokens/email-sms-templates/blob/master/email-html/password-reset.html). +- Default [email verification template](/references/frontend-sdks/prebuilt-ui/ui-showcase#email-verification) and its [source code](https://github.com/supertokens/email-sms-templates/blob/master/email-html/email-verification.html). +- Default [password reset template](/references/frontend-sdks/prebuilt-ui/ui-showcase#password-reset) and its [source code](https://github.com/supertokens/email-sms-templates/blob/master/email-html/password-reset.html). To change the content you can create a custom `SMTPService` like and update the property which builds the content. The method allows you to return an object that has the following properties: @@ -423,10 +389,10 @@ The method allows you to return an object that has the following properties: Other information like which email ID to send from appears in the `smtpSettings` object. - - + + -```tsx +```tsx {19,20,21,22,23,24,25,26,27,28,29,30,31,32,43,44,45,46,47,48,49,50,51,52,53,54,55,56} import supertokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -444,9 +410,7 @@ supertokens.init({ EmailPassword.init({ emailDelivery: { service: new SMTPService({ - // @ts-ignore smtpSettings: { /*...*/ }, - // highlight-start override: (originalImplementation) => { return { ...originalImplementation, @@ -461,7 +425,6 @@ supertokens.init({ } } } - // highlight-end }) } }), @@ -471,9 +434,7 @@ supertokens.init({ mode: "OPTIONAL", emailDelivery: { service: new EmailVerificationSMTPService({ - // @ts-ignore smtpSettings: { /*...*/ }, - // highlight-start override: (originalImplementation) => { return { ...originalImplementation, @@ -488,7 +449,6 @@ supertokens.init({ } } } - // highlight-end }) } }), @@ -496,10 +456,10 @@ supertokens.init({ ] }); ``` - - + + -```go +```go {20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71} import ( "fmt" @@ -515,12 +475,10 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ emailpassword.Init(&epmodels.TypeInput{ - // REMOVE_FROM_OUTPUT EmailDelivery: &emaildelivery.TypeInput{ Service: emailpassword.MakeSMTPService(emaildelivery.SMTPServiceConfig{ Settings: emaildelivery.SMTPSettings{ /* ... */ }, - // highlight-start Override: func(originalImplementation emaildelivery.SMTPInterface) emaildelivery.SMTPInterface { originalGetContent := *originalImplementation.GetContent @@ -542,7 +500,6 @@ func main() { return originalImplementation }, - // highlight-end }), }, }), @@ -553,7 +510,6 @@ func main() { Service: emailverification.MakeSMTPService(emaildelivery.SMTPServiceConfig{ Settings: emaildelivery.SMTPSettings{ /* ... */ }, - // highlight-start Override: func(originalImplementation emaildelivery.SMTPInterface) emaildelivery.SMTPInterface { originalGetContent := *originalImplementation.GetContent @@ -575,7 +531,6 @@ func main() { return originalImplementation }, - // highlight-end }), }, }), @@ -583,10 +538,10 @@ func main() { }) } ``` - - + + -```python +```python {12,13,14,15,16,17,18,19,20,28,29,30,31,32,33,34,35,36,48,49,50,51,52,53,59,60,61,62,63,64} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import emailpassword from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConfig, EmailContent, SMTPSettings @@ -598,7 +553,6 @@ from supertokens_python.recipe import emailverification def custom_smtp_content_override(original_implementation: SMTPOverrideInput) -> SMTPOverrideInput: original_get_content = original_implementation.get_content - # highlight-start async def get_content(template_vars: EmailTemplateVars, user_context: Dict[str, Any]) -> EmailContent: # password reset content _ = template_vars.password_reset_link @@ -608,7 +562,6 @@ def custom_smtp_content_override(original_implementation: SMTPOverrideInput) -> original_content = await original_get_content(template_vars, user_context) original_content.subject = "My custom subject" return original_content - # highlight-end original_implementation.get_content = get_content return original_implementation @@ -616,7 +569,6 @@ def custom_smtp_content_override(original_implementation: SMTPOverrideInput) -> def custom_smtp_email_verification_content_override(original_implementation: EVSMTPOverrideInput) -> EVSMTPOverrideInput: original_get_content = original_implementation.get_content - # highlight-start async def get_content(template_vars: EVEmailTemplateVars, user_context: Dict[str, Any]) -> EmailContent: # email verification content _ = template_vars.email_verify_link @@ -626,7 +578,6 @@ def custom_smtp_email_verification_content_override(original_implementation: EVS original_content = await original_get_content(template_vars, user_context) original_content.subject = "My custom subject" return original_content - # highlight-end original_implementation.get_content = get_content return original_implementation @@ -635,37 +586,33 @@ def custom_smtp_email_verification_content_override(original_implementation: EVS init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( - # highlight-start email_delivery=EmailDeliveryConfig( service=emailpassword.SMTPService( - smtp_settings=SMTPSettings(...), # type: ignore + smtp_settings=SMTPSettings(...), override=custom_smtp_content_override ) ) - # highlight-end ), # If email verification is enabled emailverification.init( mode="OPTIONAL", - # highlight-start email_delivery=EmailDeliveryConfig( service=emailverification.SMTPService( - smtp_settings=SMTPSettings(...), # type: ignore + smtp_settings=SMTPSettings(...), override=custom_smtp_email_verification_content_override ) ) - # highlight-end ) ] ) ``` - - + + ## Overrides @@ -676,10 +623,10 @@ This can include things like: - Spam protection actions - Modifying the email template variables before sending the emails - - + + -```tsx +```tsx {14,15,16,17,18,19,20,21,22,23,24,25,26,27,33,34,35,36,37,38,39,40,41,42,43,44,45,46} import supertokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -693,7 +640,6 @@ supertokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start emailDelivery: { override: (originalImplementation) => { return { @@ -708,13 +654,11 @@ supertokens.init({ } } }, - // highlight-end }), // if email verification is enabled EmailVerification.init({ mode: "OPTIONAL", - // highlight-start emailDelivery: { override: (originalImplementation) => { return { @@ -729,16 +673,15 @@ supertokens.init({ } } }, - // highlight-end }), Session.init() ] }); ``` - - + + -```go +```go {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56} import ( "github.com/supertokens/supertokens-golang/ingredients/emaildelivery" "github.com/supertokens/supertokens-golang/recipe/emailpassword" @@ -752,7 +695,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ emailpassword.Init(&epmodels.TypeInput{ - // highlight-start EmailDelivery: &emaildelivery.TypeInput{ Override: func(originalImplementation emaildelivery.EmailDeliveryInterface) emaildelivery.EmailDeliveryInterface { originalSendEmail := *originalImplementation.SendEmail @@ -772,13 +714,11 @@ func main() { return originalImplementation }, }, - // highlight-end }), // if email verification is enabled emailverification.Init(evmodels.TypeInput{ Mode: evmodels.ModeRequired, - // highlight-start EmailDelivery: &emaildelivery.TypeInput{ Override: func(originalImplementation emaildelivery.EmailDeliveryInterface) emaildelivery.EmailDeliveryInterface { originalSendEmail := *originalImplementation.SendEmail @@ -798,16 +738,15 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {45,51} from supertokens_python import init, InputAppInfo from supertokens_python.recipe.emailpassword.types import EmailDeliveryOverrideInput, EmailTemplateVars from supertokens_python.recipe import emailpassword @@ -849,21 +788,19 @@ def custom_emailverification_delivery(original_implementation: EVEmailDeliveryOv init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ emailpassword.init( - # highlight-next-line email_delivery=EmailDeliveryConfig(override=custom_email_deliver) ), # If email verification is enabled emailverification.init( mode="OPTIONAL", - # highlight-next-line email_delivery=EmailDeliveryConfig(override=custom_emailverification_delivery)) ] ) ``` - - + + diff --git a/docs/platform-configuration/meta.ts b/docs/platform-configuration/meta.ts new file mode 100644 index 0000000000..3f60e7acc5 --- /dev/null +++ b/docs/platform-configuration/meta.ts @@ -0,0 +1,8 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Platform Configuration", + "icon": "settings", + "order": 7, + "collapsed": true +}); diff --git a/docs/platform-configuration/sms-delivery.mdx b/docs/platform-configuration/sms-delivery.mdx index aad2f8c7fa..340dc07a6a 100644 --- a/docs/platform-configuration/sms-delivery.mdx +++ b/docs/platform-configuration/sms-delivery.mdx @@ -1,15 +1,10 @@ --- title: SMS delivery -hide_title: true -sidebar_position: 5 description: Customize SMS delivery process. -page_type: guide -category: platform-configuration +sidebar: + order: 5 --- - -# SMS Delivery - ## Overview SuperTokens sends SMS in different authentication scenarios. @@ -24,7 +19,7 @@ The following page shows you how to configure the SMS delivery method and adjust If you provide no configuration for SMS delivery, the backend SDK sends SMSs by talking to SuperTokens servers on `https://api.supertokens.com`. This applies to both self hosted and managed services. -:::info Important +:::info[Important] - This is a free service and is globally rate limited. This is not suitable for production use. If you do not receive an SMS using this method, then the SDK prints the SMS content on the terminal. - We do not log / store any of the info sent to the API that sends out emails on behalf of your app. - You cannot customize the SMS content when using this method. If you want to customize the content, please see one of the other methods in this section. @@ -34,10 +29,10 @@ This applies to both self hosted and managed services. Using this method, you can provide your own Twilio account details to the backend SDK, and the SMS is sent using those. - - + + -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30} import supertokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; import Session from "supertokens-node/recipe/session"; @@ -53,7 +48,6 @@ supertokens.init({ Passwordless.init({ flowType: "USER_INPUT_CODE", contactMethod: "PHONE", - // highlight-start smsDelivery: { service: new TwilioService({ twilioSettings: { @@ -69,16 +63,15 @@ supertokens.init({ }, }) }, - // highlight-end }), Session.init() ] }); ``` - - + + -```go +```go {10,11,12,13,14,15,16,17,18,19,20,21,26,27,28} import ( "github.com/supertokens/supertokens-golang/ingredients/smsdelivery" "github.com/supertokens/supertokens-golang/recipe/passwordless" @@ -88,7 +81,6 @@ import ( func main() { - // highlight-start smsService, err := passwordless.MakeTwilioService(smsdelivery.TwilioServiceConfig{ Settings: smsdelivery.TwilioSettings{ AccountSid: "...", @@ -101,26 +93,23 @@ func main() { if err != nil { panic(err) } - // highlight-end supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ passwordless.Init(plessmodels.TypeInput{ - // highlight-start SmsDelivery: &smsdelivery.TypeInput{ Service: smsService, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import passwordless from supertokens_python.ingredients.smsdelivery.types import SMSDeliveryConfig, TwilioSettings @@ -129,12 +118,9 @@ from supertokens_python.ingredients.smsdelivery.types import SMSDeliveryConfig, init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ passwordless.init( - contact_config="", # type: ignore # REMOVE_FROM_OUTPUT - flow_type="USER_INPUT_CODE", # REMOVE_FROM_OUTPUT - # highlight-start sms_delivery=SMSDeliveryConfig( service=passwordless.TwilioService( twilio_settings=TwilioSettings( @@ -150,14 +136,13 @@ init( ) ) ) - # highlight-end ) ] ) ``` - - + + To learn about how to customize the SMS templates, please see the next section. @@ -170,8 +155,7 @@ Use this method if: - Reduce SMS cost by picking a local SMS service based on the destination country. - Fight spam / misuse of SMS. -:::important -This is a paid service and charges apply for every SMS based on the cost incurred. +:::note[This is a paid service and charges apply for every SMS based on the cost incurred.] New users receive $10 worth of credits. ::: @@ -184,14 +168,14 @@ New users receive $10 worth of credits. ## Once the production `env` is set up, you can find your SMS API key under the setup section: -SMS API key screen +SMS API key screen #### 2. Set the SMS API key in the backend SDK configuration - - + + -```tsx +```tsx {16,17,18} import supertokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; import Session from "supertokens-node/recipe/session"; @@ -207,20 +191,18 @@ supertokens.init({ Passwordless.init({ flowType: "USER_INPUT_CODE", contactMethod: "PHONE", - // highlight-start smsDelivery: { service: new SupertokensService("") }, - // highlight-end }), Session.init() ] }); ``` - - + + -```go +```go {12,13,14} import ( "github.com/supertokens/supertokens-golang/ingredients/smsdelivery" "github.com/supertokens/supertokens-golang/recipe/passwordless" @@ -232,18 +214,16 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ passwordless.Init(plessmodels.TypeInput{ - // highlight-start SmsDelivery: &smsdelivery.TypeInput{ Service: passwordless.MakeSupertokensSMSService(""), }, - // highlight-end }), }, }) } ``` - - + + ```python from supertokens_python import init, InputAppInfo @@ -253,11 +233,9 @@ from supertokens_python.ingredients.smsdelivery.types import SMSDeliveryConfig init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ passwordless.init( - contact_config="", # type: ignore # REMOVE_FROM_OUTPUT - flow_type="USER_INPUT_CODE", # REMOVE_FROM_OUTPUT sms_delivery=SMSDeliveryConfig( service=passwordless.SuperTokensSMSService("")) ) @@ -265,8 +243,8 @@ init( ) ``` - - + + ### Custom method @@ -278,10 +256,10 @@ Use this method if you are: - You want to do some custom spam protection before sending the SMS. - You already have an SMS sending infrastructure and want to use that. - - + + -```tsx +```tsx {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29} import supertokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; import Session from "supertokens-node/recipe/session"; @@ -296,7 +274,6 @@ supertokens.init({ Passwordless.init({ flowType: "USER_INPUT_CODE", contactMethod: "PHONE", - // highlight-start smsDelivery: { override: (originalImplementation) => { return { @@ -312,16 +289,15 @@ supertokens.init({ } } }, - // highlight-end }), Session.init() ] }); ``` - - + + -```go +```go {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37} import ( "fmt" @@ -335,7 +311,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ passwordless.Init(plessmodels.TypeInput{ - // highlight-start SmsDelivery: &smsdelivery.TypeInput{ Override: func(originalImplementation smsdelivery.SmsDeliveryInterface) smsdelivery.SmsDeliveryInterface { @@ -360,16 +335,15 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {9,10,11,12,13,14,15,16} from supertokens_python import init, InputAppInfo from supertokens_python.recipe.passwordless.types import SMSDeliveryOverrideInput, SMSTemplateVars from supertokens_python.recipe import passwordless @@ -378,7 +352,6 @@ from supertokens_python.ingredients.smsdelivery.types import SMSDeliveryConfig def custom_sms_deliver(original_implementation: SMSDeliveryOverrideInput) -> SMSDeliveryOverrideInput: - # highlight-start async def send_sms(template_vars: SMSTemplateVars, user_context: Dict[str, Any]) -> None: # amount of time the code is alive for (in MS) _ = template_vars.code_life_time @@ -387,34 +360,31 @@ def custom_sms_deliver(original_implementation: SMSDeliveryOverrideInput) -> SMS ____ = template_vars.user_input_code # OTP # TODO: create and send SMS... - # highlight-end original_implementation.send_sms = send_sms return original_implementation init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ passwordless.init( - contact_config="", # type: ignore # REMOVE_FROM_OUTPUT - flow_type="USER_INPUT_CODE", # REMOVE_FROM_OUTPUT sms_delivery=SMSDeliveryConfig(override=custom_sms_deliver) ) ] ) ``` - - + + If you call the original implementation function for `sendSms`, it uses the service that you have configured. If you have not configured any service, it uses the default service. -:::info Important +:::info[Important] When using this callback, you must manage sending the SMS yourself. ::: -:::important Error Management +:::note[Error Management] To handle failures and other types of issues in the `sendSms` function throw an error. The SDK catches any exception through an upper level error handler. This error is then propagated if this is through an API call or otherwise logged. ::: @@ -431,10 +401,10 @@ It allows you to return an object that has the following properties: - `toPhoneNumber`: The phone number where the SMS is sent to. - - + + -```tsx +```tsx {19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53} import supertokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; import Session from "supertokens-node/recipe/session"; @@ -452,9 +422,7 @@ supertokens.init({ contactMethod: "PHONE", smsDelivery: { service: new TwilioService({ - // @ts-ignore twilioSettings: { /*...*/ }, - // highlight-start override: (originalImplementation) => { return { ...originalImplementation, @@ -490,7 +458,6 @@ supertokens.init({ } } } - // highlight-end }) } }), @@ -498,10 +465,10 @@ supertokens.init({ ] }); ``` - - + + -```go +```go {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60} import ( "fmt" @@ -512,7 +479,6 @@ import ( ) func main() { - // highlight-start smsService, err := passwordless.MakeTwilioService(smsdelivery.TwilioServiceConfig{ Settings: smsdelivery.TwilioSettings{ /* ... */ }, Override: func(originalImplementation smsdelivery.TwilioInterface) smsdelivery.TwilioInterface { @@ -556,25 +522,22 @@ func main() { if err != nil { panic(err) } - // highlight-end supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ passwordless.Init(plessmodels.TypeInput{ - // highlight-start SmsDelivery: &smsdelivery.TypeInput{ Service: smsService, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,38,39,40,41,42,43,44} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import passwordless from supertokens_python.recipe.passwordless.types import TwilioOverrideInput, SMSTemplateVars @@ -586,7 +549,6 @@ def custom_sms_content_override(original_implementation: TwilioOverrideInput) -> # original_get_content = original_implementation.get_content - # highlight-start async def get_content(template_vars: SMSTemplateVars, user_context: Dict[str, Any]) -> SMSContent: # amount of time the code is alive for (in MS) _ = template_vars.code_life_time @@ -602,7 +564,6 @@ def custom_sms_content_override(original_implementation: TwilioOverrideInput) -> # original_content = await original_get_content(template_vars, user_context) # original_content.body = "My custom body" # return original_content - # highlight-end original_implementation.get_content = get_content return original_implementation @@ -611,27 +572,23 @@ def custom_sms_content_override(original_implementation: TwilioOverrideInput) -> init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ passwordless.init( - contact_config="", # type: ignore # REMOVE_FROM_OUTPUT - flow_type="USER_INPUT_CODE", # REMOVE_FROM_OUTPUT - # highlight-start sms_delivery=SMSDeliveryConfig( service=passwordless.TwilioService( - # type: ignore - twilio_settings=TwilioSettings(...), # type: ignore + + twilio_settings=TwilioSettings(...), override=custom_sms_content_override ) ) - # highlight-end ) ] ) ``` - - + + ## Overrides @@ -643,10 +600,10 @@ This can include things like: - Modifying the email template variables before sending the emails - - + + -```tsx +```tsx {15,16,17,18,19,20,21,22,23,24,25,26,27,28} import supertokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; import Session from "supertokens-node/recipe/session"; @@ -661,7 +618,6 @@ supertokens.init({ Passwordless.init({ flowType: "USER_INPUT_CODE", contactMethod: "PHONE", - // highlight-start smsDelivery: { override: (originalImplementation) => { return { @@ -676,16 +632,15 @@ supertokens.init({ } } }, - // highlight-end }), Session.init() ] }); ``` - - + + -```go +```go {12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31} import ( "github.com/supertokens/supertokens-golang/ingredients/smsdelivery" "github.com/supertokens/supertokens-golang/recipe/passwordless" @@ -697,7 +652,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ passwordless.Init(plessmodels.TypeInput{ - // highlight-start SmsDelivery: &smsdelivery.TypeInput{ Override: func(originalImplementation smsdelivery.SmsDeliveryInterface) smsdelivery.SmsDeliveryInterface { @@ -718,16 +672,15 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {11,12,13,14,15,16} from supertokens_python import init, InputAppInfo from supertokens_python.recipe.passwordless.types import SMSDeliveryOverrideInput, SMSTemplateVars from supertokens_python.recipe import passwordless @@ -738,14 +691,12 @@ from supertokens_python.ingredients.smsdelivery.types import SMSDeliveryConfig def custom_sms_deliver(original_implementation: SMSDeliveryOverrideInput) -> SMSDeliveryOverrideInput: original_send_sms = original_implementation.send_sms - # highlight-start async def send_sms(template_vars: SMSTemplateVars, user_context: Dict[str, Any]) -> None: # TODO: before sending SMS await original_send_sms(template_vars, user_context) # TODO: after sending SMS - # highlight-end original_implementation.send_sms = send_sms return original_implementation @@ -754,16 +705,14 @@ def custom_sms_deliver(original_implementation: SMSDeliveryOverrideInput) -> SMS init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ passwordless.init( - contact_config="", # type: ignore # REMOVE_FROM_OUTPUT - flow_type="USER_INPUT_CODE", # REMOVE_FROM_OUTPUT sms_delivery=SMSDeliveryConfig(override=custom_sms_deliver) ) ] ) ``` - - + + diff --git a/docs/platform-configuration/supertokens-core/_category_.json b/docs/platform-configuration/supertokens-core/_category_.json deleted file mode 100644 index c837c99d66..0000000000 --- a/docs/platform-configuration/supertokens-core/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "SuperTokens Core", - "position": 1 -} diff --git a/docs/platform-configuration/supertokens-core/add-ssl-via-nginx.mdx b/docs/platform-configuration/supertokens-core/add-ssl-via-nginx.mdx index 79ade640b1..023f40636f 100644 --- a/docs/platform-configuration/supertokens-core/add-ssl-via-nginx.mdx +++ b/docs/platform-configuration/supertokens-core/add-ssl-via-nginx.mdx @@ -1,23 +1,17 @@ --- title: Add SSL via NGINX -hide_title: true -sidebar_position: 5 -description: >- - Set up SSL for secure SuperTokens Core connections using NGINX as a reverse - proxy. -page_type: guide -category: platform-configuration +description: Set up SSL for secure SuperTokens Core connections using NGINX as a reverse proxy. +sidebar: + order: 5 --- -# Add SSL via nginx - ## Overview This section guides you through setting up SSL via Nginx to query the SuperTokens Core with a secure connection. ## Before you start -:::caution no-title +:::warning This page is only relevant if you are self hosting SuperTokens. ::: @@ -50,11 +44,10 @@ In the configuration, scroll down to the `server` directive. - Configure the `server` directive by adding the `location` directive with the following values: - ```text title="/etc/nginx/sites-available/default" + ```text title="/etc/nginx/sites-available/default" {4,5,6,7,8,9,10,11} server { listen 80; server_name localhost; - // highlight-start location / { proxy_pass http://localhost:3567; proxy_http_version 1.1; @@ -63,7 +56,6 @@ In the configuration, scroll down to the `server` directive. proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } - // highlight-end } ``` @@ -93,15 +85,13 @@ Self-signed certificates will be used since development is local. However, certi - Set the values `ssl_certificate` and `ssl_certificate_key` in the Nginx configuration to specify the locations of the newly generated certificates. - ```text title="/etc/nginx/sites-available/default" + ```text title="/etc/nginx/sites-available/default" {5,6} server { listen 80; listen 443 ssl; server_name localhost; - // highlight-start ssl_certificate /etc/nginx/ssl/server.crt; ssl_certificate_key /etc/nginx/ssl/server.key; - // highlight-end location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; @@ -118,4 +108,3 @@ Self-signed certificates will be used since development is local. However, certi ```bash nginx -t && service nginx restart ``` - diff --git a/docs/platform-configuration/supertokens-core/api-keys.mdx b/docs/platform-configuration/supertokens-core/api-keys.mdx index 555c2e5e79..247eb78267 100644 --- a/docs/platform-configuration/supertokens-core/api-keys.mdx +++ b/docs/platform-configuration/supertokens-core/api-keys.mdx @@ -1,17 +1,10 @@ --- title: Add API Keys -hide_title: true -sidebar_position: 1 -description: >- - Authenticate backend SDK requests to SuperTokens core by adding API keys to - configuration. -page_type: guide -category: platform-configuration +description: Authenticate backend SDK requests to SuperTokens core by adding API keys to configuration. +sidebar: + order: 1 --- - -# Add API keys - ## Overview @@ -21,7 +14,7 @@ By default, there is no API key required. If you add an API key to the core's co ## Before you start -:::caution no-title +:::warning This page is only relevant if you are self hosting SuperTokens. ::: @@ -31,8 +24,8 @@ This page is only relevant if you are self hosting SuperTokens. You can set the API by updating the instance parameters. - - + + ```bash docker run \ @@ -40,9 +33,9 @@ You can set the API by updating the instance parameters. -e API_KEYS= \ -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -50,32 +43,30 @@ You can set the API by updating the instance parameters. api_keys: ``` - - + + - The format of the value is `key1,key2,key3`. - Keys can only contain `=`, `-` and alpha-numeric (including capital) chars. - Each key must have a minimum length of 20 chars - An example value is `"Akjnv3iunvsoi8=-sackjij3ncisds,asnj9=asdcda-OI982JIUN=-a"`. Notice the `,` in the string which separates the two keys `"Akjnv3iunvsoi8=-sackjij3ncisds"` and `"asnj9=asdcda-OI982JIUN=-a"`. In the backend SDK, you should only provide one of these keys. -:::info -The reason for having multiple API keys is that it allows for key rotation to occur gradually if you have multiple backend systems querying the core. +:::info[The reason for having multiple API keys is that it allows for key rotation to occur gradually if you have multiple backend systems querying the core.] ::: ### 2. Add the key to your backend code Update the backend SDK initialization code to include the API key. - - + + -```tsx +```tsx {6} import supertokens from "supertokens-node"; supertokens.init({ supertokens: { connectionURI: "", - // highlight-next-line apiKey: "" }, appInfo: { @@ -86,41 +77,39 @@ supertokens.init({ recipeList: [] }); ``` - - + + -```go +```go {7} import "github.com/supertokens/supertokens-golang/supertokens" func main() { supertokens.Init(supertokens.TypeInput{ Supertokens: &supertokens.ConnectionInfo{ ConnectionURI: "", - //highlight-next-line APIKey: "", }, }) } ``` - - + + -```python +```python {7} from supertokens_python import init, InputAppInfo, SupertokensConfig init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), supertokens_config=SupertokensConfig( connection_uri='', - # highlight-next-line api_key='' ), - framework='...', # type: ignore + framework='...', recipe_list=[ #... ] ) ``` - - + + diff --git a/docs/platform-configuration/supertokens-core/base-path.mdx b/docs/platform-configuration/supertokens-core/base-path.mdx index 0301c2a044..6e94ceb3e8 100644 --- a/docs/platform-configuration/supertokens-core/base-path.mdx +++ b/docs/platform-configuration/supertokens-core/base-path.mdx @@ -1,18 +1,10 @@ --- -id: base-path title: Add a base path -hide_title: true -sidebar_position: 6 -description: >- - Configure a base path for self-hosted core APIs by updating core config and - backend SDK. -page_type: guide -category: platform-configuration +description: Configure a base path for self-hosted core APIs by updating core config and backend SDK. +sidebar: + order: 6 --- - -# Adding a base path - ## Overview If you cannot add a dedicated (sub) domain for the core and want to expose it to an external network, you may need to add a base path to all the core APIs. @@ -23,7 +15,7 @@ Consider an example where the core resides on `http://localhost:3567/some-prefix ## Before you start -:::caution no-title +:::warning This page is only relevant if you are self hosting SuperTokens. ::: @@ -34,19 +26,18 @@ The feature is only available for core versions `>= 3.9` ### 1. Change the core configuration - - + + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-next-line -e BASE_PATH="/some-prefix" \ -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -54,20 +45,19 @@ The feature is only available for core versions `>= 3.9` base_path: "/some-prefix" ``` - - + + ### 2. Change the backend SDK initialization - - + + -```tsx +```tsx {5} import supertokens from "supertokens-node"; supertokens.init({ supertokens: { - // highlight-next-line connectionURI: "http://localhost:3567/some-prefix", // ... }, @@ -79,49 +69,44 @@ supertokens.init({ recipeList: [/* ... */ ] }); ``` - - + + -```go +```go {6} import "github.com/supertokens/supertokens-golang/supertokens" func main() { supertokens.Init(supertokens.TypeInput{ Supertokens: &supertokens.ConnectionInfo{ - // highlight-next-line ConnectionURI: "http://localhost:3567/some-prefix", }, }) } ``` - - + + -```python +```python {6} from supertokens_python import init, InputAppInfo, SupertokensConfig init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), supertokens_config=SupertokensConfig( - # highlight-next-line connection_uri='http://localhost:3567/some-prefix', ), - framework='...', # type: ignore + framework='...', recipe_list=[ #... ] ) ``` - - + + -:::note - -You can even set different base paths for different core instances: +:::note[You can even set different base paths for different core instances:] - For each of the core's configs you need to supply their base path as mentioned in step 1 - The connection URI should be something like `"/;/;/;"`. For example, a valid connection URI can be `"http://localhost:3567/some-prefix;http://localhost:3567/some-prefix-2"` ::: - diff --git a/docs/platform-configuration/supertokens-core/cli.mdx b/docs/platform-configuration/supertokens-core/cli.mdx index ca6696e166..eb434a548c 100644 --- a/docs/platform-configuration/supertokens-core/cli.mdx +++ b/docs/platform-configuration/supertokens-core/cli.mdx @@ -1,17 +1,10 @@ --- title: CLI -hide_title: true -toc_max_heading_level: 4 -sidebar_position: 10 -description: >- - Learn to use SuperTokens CLI for starting, listing, stopping, and uninstalling - instances. -page_type: guide -category: platform-configuration +description: Learn to use SuperTokens CLI for starting, listing, stopping, and uninstalling instances. +sidebar: + order: 10 --- -# SuperTokens CLI - ## Overview The SuperTokens CLI has the allows you to manage your core instance from the command line. @@ -20,8 +13,7 @@ The SuperTokens CLI has the allows you to manage your core instance from the com supertokens [command] [--help] [--version] ``` -:::important -If you are using Windows, you can only use the SuperTokens CLI using a terminal with Administrator privilege. +:::note[If you are using Windows, you can only use the SuperTokens CLI using a terminal with Administrator privilege.] ::: ## Commands diff --git a/docs/platform-configuration/supertokens-core/ip-allow-deny.mdx b/docs/platform-configuration/supertokens-core/ip-allow-deny.mdx index 1f3c0ca34c..c1ff2c6bdd 100644 --- a/docs/platform-configuration/supertokens-core/ip-allow-deny.mdx +++ b/docs/platform-configuration/supertokens-core/ip-allow-deny.mdx @@ -1,17 +1,10 @@ --- title: Filter requests based on IP address -hide_title: true -sidebar_position: 2 -description: >- - Configure SuperTokens to allow or deny requests based on specific IP addresses - for enhanced security. -page_type: guide -category: platform-configuration +description: Configure SuperTokens to allow or deny requests based on specific IP addresses for enhanced security. +sidebar: + order: 2 --- - -# Filter requests based on IP address - ## Overview You can set the SuperTokens core's configuration such that it accepts / denies requests that originate from certain IPs. @@ -19,7 +12,7 @@ This ensures that only your backend can query the SuperTokens core - increasing ## Before you start -:::caution no-title +:::warning This page is only relevant if you are self hosting SuperTokens. The option is not available if you are using the managed version of SuperTokens due to security reasons. @@ -31,8 +24,8 @@ In this case, you have to configure the filtering mechanism in your backend serv ## Allow requests - - + + ```bash docker run \ @@ -40,9 +33,9 @@ In this case, you have to configure the filtering mechanism in your backend serv -e IP_ALLOW_REGEX="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" \ -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -50,8 +43,8 @@ In this case, you have to configure the filtering mechanism in your backend serv ip_allow_regex: 127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1 ``` - - + + The above only allows requests that originate from an IP that matches `127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1` regular expression. A breakdown of this regex is: - `127\.\d+\.\d+\.\d+`: IPs that start with `127.`; OR @@ -68,19 +61,18 @@ If this value is not set, then the core allows requests from any IP address. This is the opposite of the above configuration. If you only set this, the core allows requests from any IP other than the one that matches the regular expression corresponding to this setting. - - + + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-next-line -e IP_DENY_REGEX="100.1.1.3" \ -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -88,14 +80,13 @@ This is the opposite of the above configuration. If you only set this, the core ip_deny_regex: 100.1.1.3 ``` - - + + The above setting makes the core accept requests from any IP other than `100.1.1.3`. For `100.1.1.3`, it returns a `403`. -:::info What if you set both the configurations? +:::info[What if you set both the configurations?] In this case, the core allows requests only based on the value of `ip_allow_regex`, as long that request's IP doesn't match the regex of `ip_deny_regex`. For example, if you set `ip_allow_regex: IP1|IP2` and `ip_deny_regex: IP1`, then the core accepts requests only from `IP2`. ::: - diff --git a/docs/platform-configuration/supertokens-core/meta.ts b/docs/platform-configuration/supertokens-core/meta.ts new file mode 100644 index 0000000000..43d9b5f69f --- /dev/null +++ b/docs/platform-configuration/supertokens-core/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "SuperTokens Core", + "icon": "cpu", + "order": 1 +}); diff --git a/docs/post-authentication/_category_.json b/docs/post-authentication/_category_.json deleted file mode 100644 index dd4f9e45f4..0000000000 --- a/docs/post-authentication/_category_.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "label": "Post Authentication", - "collapsible": true, - "collapsed": true, - "customProps": { - "isMainCategory": true - }, - "position": 5 -} diff --git a/docs/post-authentication/account-linking/_blocks/paid-feature-callout.mdx b/docs/post-authentication/account-linking/_blocks/paid-feature-callout.mdx deleted file mode 100644 index ab021fe07f..0000000000 --- a/docs/post-authentication/account-linking/_blocks/paid-feature-callout.mdx +++ /dev/null @@ -1,10 +0,0 @@ - -:::warning Paid Feature - -This is a paid feature. - -For self hosted users, [Sign up](https://supertokens.com/auth) to get a license key and follow the instructions sent by email. Using the `dev` license key is free. Charging only starts once you enable the feature in production using the provided production license key. - -For managed service users, open the [SaaS Dashboard](https://supertokens.com/dashboard), select the relevant **Managed** deployment, and enable this feature from **Features**. Changes are saved automatically. Once enabled, this feature is free on the provided development environment. - -::: diff --git a/docs/post-authentication/account-linking/_category_.json b/docs/post-authentication/account-linking/_category_.json deleted file mode 100644 index a4570ca9fa..0000000000 --- a/docs/post-authentication/account-linking/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Account Linking", - "position": 3 -} diff --git a/docs/post-authentication/account-linking/add-passwords-to-an-existing-account.mdx b/docs/post-authentication/account-linking/add-passwords-to-an-existing-account.mdx index cb90a62df0..90bc84e097 100644 --- a/docs/post-authentication/account-linking/add-passwords-to-an-existing-account.mdx +++ b/docs/post-authentication/account-linking/add-passwords-to-an-existing-account.mdx @@ -1,16 +1,10 @@ --- title: Add passwords to an existing account -hide_title: true -sidebar_position: 7 description: Add a new password to an existing account using the account linking feature. -page_type: guide -recipe: accountlinking -category: account-linking +sidebar: + order: 7 --- - -# Add passwords to an existing account - ## Overview There may be scenarios in which you want to add a password to an account created using a social provider or passwordless login. @@ -22,7 +16,9 @@ Of course, there are security checks done to ensure there is no account takeover ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: We do not provide pre-built UI for this flow since it's probably something you want to add in your settings page or during the sign up process. This guide focuses on which APIs to call from your own UI. @@ -32,10 +28,10 @@ The frontend code snippets below refer to the `supertokens-web-js` SDK. You can ### 1. Enable account linking and `emailpassword` on the backend SDK - - + + -```tsx +```tsx {18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37} import supertokens, { User, RecipeUserId } from "supertokens-node"; import AccountLinking from "supertokens-node/recipe/accountlinking"; import { AccountInfoWithRecipeId } from "supertokens-node/recipe/accountlinking/types"; @@ -53,7 +49,6 @@ supertokens.init({ websiteDomain: "..." }, recipeList: [ - // highlight-start EmailPassword.init(), AccountLinking.init({ shouldDoAutomaticAccountLinking: async (newAccountInfo: AccountInfoWithRecipeId & { recipeUserId?: RecipeUserId }, user: User | undefined, session: SessionContainerInterface | undefined, tenantId: string, userContext: any) => { @@ -74,39 +69,36 @@ supertokens.init({ } } }) - // highlight-end ] }); ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + In the above implementation of `shouldDoAutomaticAccountLinking`, account linking is only allowed if the input session is present. This means that the system links an email password account to an existing session user. Otherwise, account linking is not allowed, which means that first factor account linking is not enabled. If you want to enable that too, you can see the [automatic account linking documentation](./automatic-account-linking). ### 2. Create a UI to show a password input to the user and handle the submit event -:::important -If you want to use password based auth as a second factor, or for step up auth, see the docs in the [MFA recipe](/docs/additional-verification/mfa/introduction) instead. The guide below is only meant for if you want to add a password for a user and allow them to login via email password for first factor login. +:::note +If you want to use password based auth as a second factor, or for step up auth, see the docs in the [MFA recipe](/additional-verification/mfa/introduction) instead. The guide below is only meant for if you want to add a password for a user and allow them to login via email password for first factor login. ::: -First, you need to detect if there already exists a password for the user. You can do this by inspecting the [user object](/docs/references/backend-sdks/user-object) on the backend and checking if there is an `emailpassword` login method. +First, you need to detect if there already exists a password for the user. You can do this by inspecting the [user object](/references/backend-sdks/user-object) on the backend and checking if there is an `emailpassword` login method. -Then, if no such login method exists, you have to show a UI in which the user can add a password to their account. The [password validation documentation](/docs/authentication/email-password/customize-the-sign-up-form#change-field-validators#changing-the-default-email-and-password-validators) contains the default password validation rules. +Then, if no such login method exists, you have to show a UI in which the user can add a password to their account. The [password validation documentation](/authentication/email-password/customize-the-sign-up-form#change-field-validators#changing-the-default-email-and-password-validators) contains the default password validation rules. You also need to fetch the email of the user before you call the email password sign up API. You can fetch this using the user object. If the `user` object does not have an email (which can only happen if the first factor is phone OTP), then you should ask the user to go through an email OTP flow via the passwordless recipe. This step should occur before asking them to set a password. The email OTP flow also results in creating a passwordless user account and linking it to the session user. @@ -117,10 +109,10 @@ Once you have the email on the frontend, you should call the sign up API. The tw ### 3. Check for email match in the backend sign up API Since the frontend specifies the email, verify it in the backend API before using it (since the frontend shouldn't be trusted). You can do this by overriding the email password sign up API: - - + + -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -136,7 +128,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start override: { apis: (originalImplementation) => { return { @@ -160,37 +151,34 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init({ /* ... */ }) ] }); ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + --- ## See also - - - - - - + + + + + + diff --git a/docs/post-authentication/account-linking/automatic-account-linking.mdx b/docs/post-authentication/account-linking/automatic-account-linking.mdx index a4edbb8a92..ed28c5a0b3 100644 --- a/docs/post-authentication/account-linking/automatic-account-linking.mdx +++ b/docs/post-authentication/account-linking/automatic-account-linking.mdx @@ -1,20 +1,10 @@ --- title: Automatic account linking -hide_title: true -sidebar_position: 3 -toc_max_heading_level: 4 -description: >- - Enable automatic account linking for multiple login methods with SuperTokens, - ensuring secure account management. -page_type: guide -recipe: accountlinking -category: account-linking +description: Enable automatic account linking for multiple login methods with SuperTokens, ensuring secure account management. +sidebar: + order: 3 --- - - -# Automatic account linking - ## Overview Automatic account linking is a feature that allows users to automatically sign in to their existing account using more than one login method. On a high level, SuperTokens automatically links the accounts for the different login methods provided that: @@ -26,7 +16,9 @@ SuperTokens ensures that accounts are automatically linked only if there is no r ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: ## Steps @@ -35,10 +27,10 @@ SuperTokens ensures that accounts are automatically linked only if there is no r You can enable this feature by providing the following callback implementation on the backend SDK: - - + + -```tsx +```tsx {27,28,29,30,31,32,33,34,35,36,37,38,39,40,41} import supertokens, { User, RecipeUserId } from "supertokens-node"; import AccountLinking from "supertokens-node/recipe/accountlinking"; import { AccountInfoWithRecipeId } from "supertokens-node/recipe/accountlinking/types"; @@ -65,7 +57,6 @@ supertokens.init({ websiteDomain: "..." }, recipeList: [ - // highlight-start AccountLinking.init({ shouldDoAutomaticAccountLinking: async (newAccountInfo: AccountInfoWithRecipeId & { recipeUserId?: RecipeUserId }, user: User | undefined, session: SessionContainerInterface | undefined, tenantId: string, userContext: any) => { // This step is required if you are saving user information in your own database. @@ -81,20 +72,18 @@ supertokens.init({ } } }) - // highlight-end ] }); ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -139,20 +128,18 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework='...', # type: ignore + framework='...', recipe_list=[ accountlinking.init(should_do_automatic_account_linking=should_do_automatic_account_linking) ], ) ``` - - + + - -## Input - + | Argument | Type | Description | |----------|------|-------------| | `newAccountInfo` | `AccountInfoWithRecipeId & { recipeUserId?: RecipeUserId }` | Contains information about the user whose account is going to link or become a primary user. Includes email, social login info, phone number, and login method (`emailpassword`, `thirdparty`, or `passwordless`). May contain `recipeUserId` during account linking. Note: When `newAccountInfo.recipeUserId !== undefined && user !== undefined`, extra logic checks if the user ID has associated data in your application db to prevent data loss. | @@ -160,20 +147,19 @@ init( | `session` | `SessionContainerInterface \| undefined` | Session object of the user who is linking. `undefined` for first factor login. Defined if user completed first factor and calls sign up/in API again (MFA or social login linking). | | `tenant` | `string` | ID of the tenant the user is signing in/up to. | | `userContext` | `any` | User defined context object. | - -## Output - + + | Argument | Type | Description | |----------|------|-------------| | `shouldAutomaticallyLink` | `boolean` | If `true`, `newAccountInfo` links or becomes primary user during API call (subject to security checks). If `false`, no account linking operation occurs. | | `shouldRequireVerification` | `boolean` | If `true`, account linking only happens if `newAccountInfo` verifies. **Strongly recommended to keep as `true` for security.** | - +
-:::important -If you are returning `shouldRequireVerification` as `true`, then you need to also [enable the email verification recipe](/docs/additional-verification/email-verification/initial-setup) in `REQUIRED` mode. This means that if the login method does not inherently verify the email (like for email password login), SuperTokens requires the user to go through the email verification flow first. Then, it attempts auto linking of the account. For other login methods like sign in with Google, the email is already verified during login. The user does not need to verify the email again, and account linking occurs immediately. +:::note +If you are returning `shouldRequireVerification` as `true`, then you need to also [enable the email verification recipe](/additional-verification/email-verification/initial-setup) in `REQUIRED` mode. This means that if the login method does not inherently verify the email (like for email password login), SuperTokens requires the user to go through the email verification flow first. Then, it attempts auto linking of the account. For other login methods like sign in with Google, the email is already verified during login. The user does not need to verify the email again, and account linking occurs immediately. If you enable email verification in `OPTIONAL` mode, the user can access the account after email password login. However, account linking only occurs after they verify their email later on. This is risky because while the user had access to their email password account after sign up, they could lose access after verification and account linking completes due to the change in the primary user ID. A callback is available to help migrate data from one user ID to another. ::: @@ -204,7 +190,7 @@ If the current user is not already linked and if there exists another user with If the current user whose email got verified is not a primary user, and there exists another primary user in the same tenant with the same email, then the two accounts link if: - Your implementation for `shouldDoAutomaticAccountLinking` returns `true` for the `shouldAutomaticallyLink` boolean. -:::info no-title +:::info For a primary user, if two login methods (L1 & L2) share the same email, but L1's email verifies and L2's does not, SuperTokens automatically verifies L2's email under these conditions: - The user logs in with L2. - The `updateEmailOrPassword` (email password recipe) or `updateUser` (passwordless recipe) function calls to update L2's email to match L1's. @@ -217,7 +203,7 @@ If there already exists a user with the same email in a non email password recip - Your implementation for `shouldDoAutomaticAccountLinking` returns `true` for the `shouldAutomaticallyLink` boolean. -:::info Email update implications +:::info[Email update implications] When updating a user's login email, SuperTokens ensures account linking conditions remain valid. A primary user's email cannot update to match another primary user's email. @@ -248,7 +234,7 @@ To prevent this scenario, you should: This appears in the [code snippet above](#enabling-automatic-account-linking). - If you do not want to return `false` in this case, and want the accounts to link, then make sure to implement the `onAccountLinked` callback:
- ```tsx + ```tsx {24,25,26,27,28,29} import supertokens, { User, RecipeUserId } from "supertokens-node" import AccountLinking from "supertokens-node/recipe/accountlinking"; import { AccountInfoWithRecipeId, RecipeLevelUser } from "supertokens-node/recipe/accountlinking/types"; @@ -272,31 +258,26 @@ This appears in the [code snippet above](#enabling-automatic-account-linking). shouldRequireVerification: true } }, - // highlight-start onAccountLinked: async (user: User, newAccountInfo: RecipeLevelUser, userContext: any) => { let olderUserId = newAccountInfo.recipeUserId.getAsString() let newUserId = user.id; // TODO: migrate data from olderUserId to newUserId in your database... } - // highlight-end }) ] }); ``` -:::caution -If your logic in `onAccountLinked` throws an error, then it is not called again, and still results in linking the accounts. However, the end user would see an error on the UI as the API returns a `500` status code. They can retry the login action and log into the primary user's account as expected. +:::warning[If your logic in `onAccountLinked` throws an error, then it is not called again, and still results in linking the accounts. However, the end user would see an error on the UI as the API returns a `500` status code. They can retry the login action and log into the primary user's account as expected.] ::: ### Error status codes The following is a list of error status codes that the end user might see during their interaction with the login UI (as a general error message in the pre-built UI). - - -## `ERR_CODE_001` - + + - This can happen during creating a password reset code in the email password flow: - API path and method: `/user/password/reset/token POST` - Output JSON: @@ -309,7 +290,7 @@ The following is a list of error status codes that the end user might see during ``` - The pre-built UI on the frontend displays this error in the following way: - pre-built UI screenshot showing error message for ERR_CODE_001. + pre-built UI screenshot showing error message for ERR_CODE_001. - Below is the scenario for when this status returns: @@ -318,9 +299,8 @@ A malicious user, User A, which is a primary user, has login methods with email To prevent this scenario, enforcement ensures that the password link is only generated if the primary user has at least one login method that has the input email ID and verifies it, or if not, checks that the primary user has no other login method with a different email, or phone number. If these cases are not satisfied, then the system returns the error code `ERR_CODE_001`. - To resolve this, you would have to manually verify the user's identity and check that they own each of the emails / phone numbers associated with the primary user. Once verified, you can manually mark the email from the email password account as verified, and then ask them to go through the password reset flow once again. If they do not own each of the emails / phone numbers associated with the account, you can manually unlink the login methods which they do not own, and then ask them to go through the password reset flow once again. **You can do these actions using the user management dashboard.** - -## `ERR_CODE_002` - + + - This can happen during the passwordless recipe's create or consume code API (during sign up): - API path and method: `/signinup/code POST` or `/signinup/code/consume POST` - Output JSON: @@ -332,7 +312,7 @@ To prevent this scenario, enforcement ensures that the password link is only gen ``` - The pre-built UI on the frontend displays this error in the following way: - pre-built UI screenshot showing error message for ERR_CODE_002. + pre-built UI screenshot showing error message for ERR_CODE_002. - Below is an example scenario for when this status returns (one amongst many): A user is trying to sign up using passwordless login method with email `e1`. There exists an email password login method with `e1`, which remains unverified (owned by an attacker). If this scenario occurs, and then the attacker initiates the email verification flow for the email password method, the real user might click on the verification email (since they signed up, they do not get suspicious), and then the attacker's login method links to the passwordless login method. This way, the attacker gains access to the user's account. @@ -340,14 +320,11 @@ A user is trying to sign up using passwordless login method with email `e1`. The To prevent this, sign up with passwordless login is not allowed in case there exists another account with the same email and remains unverified. - To resolve this issue, you should ask the user to try another login method (which already has their email), or then mark their email as verified in the other account that has the same email, before asking them to retry passwordless login. **You can do these actions using the user management dashboard.** - - -## `ERR_CODE_003` - + + This used to be an error code which is no longer valid and you can ignore it. - -## `ERR_CODE_004` - + + - This can happen during the third party recipe's `/signinup` API (during sign in): - API path and method: `/signinup POST` - Output JSON: @@ -358,15 +335,14 @@ This used to be an error code which is no longer valid and you can ignore it. } ``` - The pre-built UI on the frontend displays this error in the following way: - Pre-built UI screenshot showing error for message ERR_CODE_004. + Pre-built UI screenshot showing error for message ERR_CODE_004. - Below is an example scenario for when this status returns (one amongst many): There exists a `thirdparty` user with email `e1`, sign in with Google (owned by the victim, and the email is verified). There exists another `thirdparty` login method with email, `e2` (owned by an attacker), such as login with GitHub. The attacker then goes to their GitHub and changes their email to `e1` (which is in unverified state). The next time the attacker tries to login, via GitHub, they see this error code. Login is prevented, because if it wasn't, then the attacker might send an email verification link to `e1`, and if the victim clicks on it, then the attacker's account will link to the victim's account. - To resolve this issue, you can delete the login method that has the unverified email, or if manually mark the unverified account as verified (if you confirm the identity of its owner). **You can do these actions using the user management dashboard.** - -## `ERR_CODE_005` - + + - This can happen during the third party recipe's `signinup` API (during sign in): - API path and method: `/signinup POST` - Output JSON: @@ -377,15 +353,14 @@ There exists a `thirdparty` user with email `e1`, sign in with Google (owned by } ``` - The pre-built UI on the frontend displays this error in the following way: - Pre-built UI screenshot showing error message for ERR_CODE_005. + Pre-built UI screenshot showing error message for ERR_CODE_005. - Below is as example scenario for when this status returns (one amongst many): There exists a primary, third party user with email `e1`, sign in with Google. There exists another email password user with email `e2`, which is a primary user. If the user changes their email on Google to `e2`, and then try logging in via Google, they see this error code. This occurs because if it wasn't, then it would result in two primary users having the same email, which violates one of the account linking rules. - To resolve this issue, you can make one of the primary users as non primary (use the unlink button against the login method on the user management dashboard). Once the user is not a primary user, you can ask the user to re-login with that method, and it should auto link that account with the existing primary user. - -## `ERR_CODE_006` - + + - This can happen during the third party recipe's `signinup` API (during sign up): - API path and method: `/signinup POST` - Output JSON: @@ -396,7 +371,7 @@ There exists a primary, third party user with email `e1`, sign in with Google. T } ``` - The pre-built UI on the frontend displays this error in the following way: - Pre-built UI screenshot showing error message for ERR_CODE_006. + Pre-built UI screenshot showing error message for ERR_CODE_006. - Below is as example scenario for when this status returns (one amongst many): A user is trying to sign up using third party login method with email `e1`. There exists an email password login method with `e1`, which remains unverified (owned by an attacker). If the third party sign up is allowed, and then the attacker initiates the email verification flow for the email password method, the real user might click on the verification email (since they signed up, they do not get suspicious), and then the attacker's login method links to the third party login method. This way, the attacker has access to the user's account. @@ -404,9 +379,8 @@ A user is trying to sign up using third party login method with email `e1`. Ther To prevent this, sign up with third party login is not allowed in case there exists another account with the same email and remains unverified. - To resolve this issue, you should ask the user to try another login method (which already has their email), or then manually mark their email as verified in the other account that has the same email, before asking them to retry third party login. **You can do these actions using the user management dashboard.** - -## `ERR_CODE_007` - + + - This can happen during the email password sign up API: - API path and method: `/signup POST` - Output JSON: @@ -417,15 +391,14 @@ A user is trying to sign up using third party login method with email `e1`. Ther } ``` - The pre-built UI on the frontend displays this error in the following way: - Pre-built UI screenshot showing error message for ERR_CODE_007. + Pre-built UI screenshot showing error message for ERR_CODE_007. - Below is as example scenario for when this status returns (one amongst many): There exists a primary, social login account with email `e1`, sign in with Google. If an attacker tries to sign up with email password with email `e1`, the system sends an email verification email to the victim, and they may click it since they had previously signed up with Google. This links the attacker's account to the victim's account. - To resolve this issue, you can ask the user to try and login, or go through the reset password flow. - -## `ERR_CODE_008` - + + - This can happen during the email password sign in API: - API path and method: `/signin POST` - Output JSON: @@ -436,15 +409,14 @@ There exists a primary, social login account with email `e1`, sign in with Googl } ``` - The pre-built UI on the frontend displays this error in the following way: - Pre-built UI screenshot showing error message for ERR_CODE_008. + Pre-built UI screenshot showing error message for ERR_CODE_008. - Below is as example scenario for when this status returns (one amongst many): There exists a primary, social login account with email `e1`, sign in with Google. There also exists an email password account (owned by the attacker) that remains unverified with the same email `e1` (this is not a primary user). If the attacker tries to sign in with email password, they see this error. This occurs because if it wasn't, then the attacker might send an email verification email on sign in, and the actual user may click on it (since they had previously signed up). Upon verifying that account, the system links the attacker's account to the victim's account. - To resolve this issue, you can ask the user to try the reset password flow. - -## `ERR_CODE_014` - + + - This can happen when adding a password to an existing session user: - API Path is `/signup POST`. - Output JSON: @@ -460,9 +432,8 @@ There exists a primary, social login account with email `e1`, sign in with Googl - The user logs out, and then creates a social login account with email `e1`. Then, they receive a request to add a password to this account. Since an email password account with `e1` already exists, SuperTokens tries and links that to this new account, but fails, since the email password account with `e1` is already a primary user. - To resolve this, it is recommended to manually link the `e1` social login account with the `e1` email password account. Alternatively, enable automatic account linking for first factor to prevent the above scenario. - -## `ERR_CODE_015` - + + - This can happen when adding a password to an existing session user: - API Path is `/signup POST`. - Output JSON: @@ -479,9 +450,8 @@ There exists a primary, social login account with email `e1`, sign in with Googl - This causes this type of error since the linking of the new social login and email account fails since there already exists another primary user with the same (`e1`) email. - To resolve this, it is recommended not allowing users to specify an email when asking them to add a password for their account. - -## `ERR_CODE_016` - + + - This can happen when adding a password to an existing session user: - API Path is `/signup POST`. - Output JSON: @@ -497,9 +467,8 @@ There exists a primary, social login account with email `e1`, sign in with Googl - The user logs out and creates another social login account with email `e1` (say GitHub), and then tries and adds a password to this account with email `e1`. Here, SuperTokens tries and makes the GitHub login a primary user, but fails, since the email `e1` is already a primary user (with Google login). - To resolve this, it is recommended that you manually link the `e1` GitHub social login account with the `e1` Google social login account. Or you can enable automatic account linking for first factor and this way, the above scenario will not happen. - -## `ERR_CODE_020` - + + - This can happen during association of a third party login to an existing session's account. - API Path is `/signinup POST`. - Output JSON: @@ -511,9 +480,8 @@ There exists a primary, social login account with email `e1`, sign in with Googl ``` - This can happen when the third party account that is trying to link to the session's account is not verified. It could happen when you are trying to associate a social login account to a user, but that social account's email is not verified (and if the email of that account is not the same as the current session's account's email). - To resolve this, you can return `shouldRequireVerification` as `false` in the `shouldDoAutomaticAccountLinking` function implementation, or you can only allow users to link social login accounts that give verified accounts. - -## `ERR_CODE_021` - + + - This can happen during association of a third party login to an existing session's account. - API Path is `/signinup POST`. - Output JSON: @@ -524,9 +492,8 @@ There exists a primary, social login account with email `e1`, sign in with Googl } ``` - This can happen when the third party account that is trying to link to the session's account is already linked with another primary user. - -## `ERR_CODE_022` - + + - This can happen during association of a third party login to an existing session's account. - API Path is `/signinup POST`. - Output JSON: @@ -536,10 +503,9 @@ There exists a primary, social login account with email `e1`, sign in with Googl "reason": "Cannot sign in / up due to security reasons. Please contact support. (ERR_CODE_022)" } ``` -- This can happen when the third party account that is trying to link to the session's account has the same email as another primary user. - -## `ERR_CODE_023` - +- This can happen when the third party account that is trying to link to the session's account has the same email as another primary user. + + - This can happen during association of a third party login to an existing session's account. - API Path is `/signinup POST`. - Output JSON: @@ -550,9 +516,8 @@ There exists a primary, social login account with email `e1`, sign in with Googl } ``` - To link the third party user with the session user, we need to make sure that the session user is a primary user. However, that can fail if there exists another primary user with the same email as the session user, and in this case, this error returns to the frontend. - -## `ERR_CODE_024` - + + - This happens during third party sign in, when the user is trying to sign in with a non-primary user, and the third party provider does not verify their email, and their exists a primary user with the same email. This can also happen the other way around wherein the user is trying to sign in with the primary user (unverified email), and there exists a non-primary user with the same email. - API Path is `/signinup POST`. - Output JSON: @@ -563,22 +528,21 @@ There exists a primary, social login account with email `e1`, sign in with Googl } ``` - You can resolve this by deleting the (non primary) user that has the same email ID, or by manually marking the email of the user as verified for the login method that they are trying to sign in with. - - + #### Changing the error message on the frontend -If you want to display a different message to the user, or use a different status code, you can change them on the frontend via [the language translation feature](/docs/references/frontend-sdks/prebuilt-ui/translations). +If you want to display a different message to the user, or use a different status code, you can change them on the frontend via [the language translation feature](/references/frontend-sdks/prebuilt-ui/translations). --- ## See also - - - - - - - + + + + + + + diff --git a/docs/post-authentication/account-linking/important-concepts.mdx b/docs/post-authentication/account-linking/important-concepts.mdx index 7031941945..09a9681aaa 100644 --- a/docs/post-authentication/account-linking/important-concepts.mdx +++ b/docs/post-authentication/account-linking/important-concepts.mdx @@ -1,17 +1,10 @@ --- title: Important concepts -hide_title: true -sidebar_position: 2 -description: >- - Link multiple authentication methods to a single account, ensuring security - and user management. -page_type: guide -recipe: accountlinking -category: account-linking +description: Link multiple authentication methods to a single account, ensuring security and user management. +sidebar: + order: 2 --- -# Important concepts - ## Overview The following page describes concepts that are relevant towards understanding how account linking works in **SuperTokens**. @@ -28,7 +21,7 @@ The primary user ID remains constant when accounts link to it. A user can become a primary user only if no other primary users share the same email, third-party information, or phone number across all tenants. This applies to all tenants to which the user belongs. Hence, two primary users with the same email address, one using email/password login and the other using social login. -:::info Multi-tenancy +:::info[Multi-tenancy] Additionally, the following scenario is not permitted in a multi-tenant context: - User A is a primary user with email `test@example.com` and belongs to tenants `t1` and `t2`. - User B is a primary user with email `test@example.com` and belongs to tenant `t2`. @@ -72,8 +65,7 @@ Only User B remains, which is a social login user, and its primary user ID equal Any metadata, role, sessions info continues to exist. 3. If unlinking a User A which is a primary user ID, but it has not linked users, it results in this user becoming a non-primary user. -:::important -All the above checks happen automatically. You don't need to worry about them. But it is important to understand what's happening. +:::note[All the above checks happen automatically. You don't need to worry about them. But it is important to understand what's happening.] ::: ## Security @@ -186,9 +178,9 @@ This causes the system to link the new, malicious account, thereby giving the ma ## See also - - - - - - + + + + + + diff --git a/docs/post-authentication/account-linking/introduction.mdx b/docs/post-authentication/account-linking/introduction.mdx index 6035f39408..4104ba03cd 100644 --- a/docs/post-authentication/account-linking/introduction.mdx +++ b/docs/post-authentication/account-linking/introduction.mdx @@ -1,17 +1,10 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -skip_llms_txt: true description: 'Learn how to manage users in SuperTokens ' -page_type: overview -recipe: accountlinking -category: account-linking +sidebar: + order: 1 --- - -# User management - ## Overview Account linking is the process of associating multiple authentication methods with the same account. @@ -25,7 +18,9 @@ The other one involves you setting up the linking process yourself. ## Prerequisites - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: ## Getting started @@ -33,51 +28,26 @@ Before you going into the tutorials, read through the **Important concepts** pag It teaches you about the main things that you need to know in the context of account linking. After that, based on your use case, check either the automatic or manual account linking guides. - - - - Important concepts - - - Learn about the main concepts that you need to know in the context of account linking. - - - - - Automatic account linking - - - See how to enable and use the automatic account linking feature. - - - - - Manual account linking - - - Implement the account linking feature manually. - - - + + +Learn about the main concepts that you need to know in the context of account linking. + + +See how to enable and use the automatic account linking feature. + + +Implement the account linking feature manually. + + ## Customization - - - - Link social accounts - - - See how you can manually link multiple social accounts under the same user. - - - - - Add passwords to an existing account - - - See how you can add passwords to an existing account. - - - + + +See how you can manually link multiple social accounts under the same user. + + +See how you can add passwords to an existing account. + + diff --git a/docs/post-authentication/account-linking/link-social-accounts.mdx b/docs/post-authentication/account-linking/link-social-accounts.mdx index 99b9bf73a9..e9b9df53b3 100644 --- a/docs/post-authentication/account-linking/link-social-accounts.mdx +++ b/docs/post-authentication/account-linking/link-social-accounts.mdx @@ -1,16 +1,10 @@ --- title: Link social accounts -hide_title: true -sidebar_position: 6 description: Link social accounts accounts using the account linking feature. -page_type: guide -recipe: accountlinking -category: account-linking +sidebar: + order: 6 --- - -# Link social accounts - ## Overview The following guide shows you how to link a social account to an existing user account. @@ -22,22 +16,23 @@ Of course, there are security checks done to ensure there is no account takeover ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: We do not provide pre-built UI for this flow since it's probably something you want to add in your settings page or during the sign up process. This guide focuses on which APIs to call from your own UI. The frontend code snippets below refer to the `supertokens-web-js` SDK. You can continue to use this even if you have initialised the `supertokens-auth-react` SDK, on the frontend. - ## Steps ### 1. Enable account linking on the backend SDK - - + + -```tsx +```tsx {17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35} import supertokens, { User, RecipeUserId } from "supertokens-node"; import AccountLinking from "supertokens-node/recipe/accountlinking"; import { AccountInfoWithRecipeId } from "supertokens-node/recipe/accountlinking/types"; @@ -54,7 +49,6 @@ supertokens.init({ websiteDomain: "..." }, recipeList: [ - // highlight-start AccountLinking.init({ shouldDoAutomaticAccountLinking: async (newAccountInfo: AccountInfoWithRecipeId & { recipeUserId?: RecipeUserId }, user: User | undefined, session: SessionContainerInterface | undefined, tenantId: string, userContext: any) => { if (user === undefined) { @@ -74,37 +68,34 @@ supertokens.init({ } } }) - // highlight-end ] }); ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + In the above implementation of `shouldDoAutomaticAccountLinking`, account linking is only allowed if the input session is present. This means that the process is trying to link a social login account to an existing session user. Otherwise, account linking is not allowed, which means that first factor account linking does not occur. If you want to enable that too, you can see [the automatic account linking page](./automatic-account-linking). ### 2. Create a UI to show social login buttons and handle login -First, you need to detect which social login methods are already linked to the user. You can do this by inspecting the [user object](/docs/references/backend-sdks/user-object) on the backend and checking the `thirdParty.id` property (the values are like `google`, `facebook` etc). +First, you need to detect which social login methods are already linked to the user. You can do this by inspecting the [user object](/references/backend-sdks/user-object) on the backend and checking the `thirdParty.id` property (the values are like `google`, `facebook` etc). Then you have to create your own UI which asks the user to pick a social login provider to connect to. Once they click on one, redirect them to that provider's page. After login, the provider redirects the user back to your application (on the same path as the first factor login). You then call the APIs to consume the OAuth tokens and link the user. -The exact implementation of the above is available [in the initial setup documentation](/docs/authentication/social/initial-setup). The two big differences in the implementation are: +The exact implementation of the above is available [in the initial setup documentation](/authentication/social/initial-setup). The two big differences in the implementation are: - When you call the `signinup` API, you need to provide the session's access token in the request. If you are using the frontend SDK, the frontend network interceptors automatically handle this. The access token enables the backend to get a session and then link the social login account to session user. - New types of failure scenarios exist when calling the `signinup` API which are impossible during first factor login. To learn more about them, see the [error codes section](./automatic-account-linking#err_code_001) (> `ERR_CODE_008`). @@ -114,10 +105,10 @@ Once you call the `signinup` API from the frontend, SuperTokens verifies the OAu To fetch the new user object and also the third party profile, you can override the `signinup` recipe function: - - + + -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51} import SuperTokens, { User } from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty"; import Session from "supertokens-node/recipe/session"; @@ -133,7 +124,6 @@ SuperTokens.init({ }, recipeList: [ ThirdParty.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -170,29 +160,26 @@ SuperTokens.init({ } } } - // highlight-end }), Session.init({ /* ... */ }) ] }); ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + Notice in the above snippet that the check is for `input.session !== undefined && response.user.id === input.session.getUserId()`. This ensures that the custom logic runs only if it's linking a social account to your session account, and not during first factor login. @@ -200,11 +187,10 @@ Notice in the above snippet that the check is for `input.session !== undefined & ## See also - - - - - - - - + + + + + + + diff --git a/docs/post-authentication/account-linking/manual-account-linking.mdx b/docs/post-authentication/account-linking/manual-account-linking.mdx index ca5fb8c2f4..c4249d816c 100644 --- a/docs/post-authentication/account-linking/manual-account-linking.mdx +++ b/docs/post-authentication/account-linking/manual-account-linking.mdx @@ -1,18 +1,10 @@ --- title: Manual account linking -hide_title: true -sidebar_position: 4 -description: >- - Manual account linking enables control over linking accounts with different - identifiers or post-login. -page_type: guide -recipe: accountlinking -category: account-linking +description: Manual account linking enables control over linking accounts with different identifiers or post-login. +sidebar: + order: 4 --- - -# Manual account linking - ## Overview Manual account linking allows you to take control of when and which accounts link. @@ -23,17 +15,19 @@ With this, you can implement flows like: ## Before you start - +:::info[Managed service feature] +This feature is available for managed SuperTokens deployments. +::: ## Steps ### 1. Initialize the account linking recipe - - + + -```tsx +```tsx {17} import supertokens, { User, RecipeUserId } from "supertokens-node"; import AccountLinking from "supertokens-node/recipe/accountlinking"; import { AccountInfoWithRecipeId } from "supertokens-node/recipe/accountlinking/types"; @@ -50,22 +44,19 @@ supertokens.init({ websiteDomain: "..." }, recipeList: [ - // highlight-start AccountLinking.init() - // highlight-end ] }); ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python import init, InputAppInfo, SupertokensConfig @@ -81,15 +72,15 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", ), - framework='...', # type: ignore + framework='...', recipe_list=[ accountlinking.init() ], ) ``` - - + + In the above, SuperTokens does not automatically link accounts (during sign up or sign in APIs) by returning `shouldAutomaticallyLink: false`. Initializing the recipe is still important to use the functions from the SDK as shown below. @@ -99,8 +90,8 @@ It is of course possible to [enable auto account linking](./automatic-account-li To link two accounts, you first need to make one of them a primary user: - - + + ```tsx import AccountLinking from "supertokens-node/recipe/accountlinking"; @@ -125,18 +116,17 @@ async function makeUserPrimary(recipeUserId: RecipeUserId) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.accountlinking.asyncio import create_primary_user @@ -162,8 +152,8 @@ async def make_user_primary(recipe_user_id: RecipeUserId): pass ``` - - + + ```python from supertokens_python.recipe.accountlinking.syncio import create_primary_user @@ -189,18 +179,18 @@ def make_user_primary(recipe_user_id: RecipeUserId): pass ``` - - + + - - + + ### 3. Link accounts Once a user has become a primary user, you can link other accounts to this user: - - + + ```tsx import AccountLinking from "supertokens-node/recipe/accountlinking"; @@ -230,18 +220,17 @@ async function linkAccounts(primaryUserId: string, recipeUserId: RecipeUserId) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.accountlinking.asyncio import link_accounts @@ -272,8 +261,8 @@ async def link_accounts_helper(primary_user_id: str, recipe_user_id: RecipeUserI pass ``` - - + + ```python from supertokens_python.recipe.accountlinking.syncio import link_accounts @@ -304,18 +293,18 @@ def link_accounts_helper(primary_user_id: str, recipe_user_id: RecipeUserId): pass ``` - - + + - - + + ### 4. Unlink accounts If you want to unlink an account from its primary user ID, you can use the following function: - - + + ```tsx import AccountLinking from "supertokens-node/recipe/accountlinking"; @@ -346,18 +335,17 @@ async function unlinkAccount(recipeUserId: RecipeUserId) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + - - + + ```python from supertokens_python.recipe.accountlinking.asyncio import unlink_account @@ -386,8 +374,8 @@ async def unlink_account_helper(recipe_user_id: RecipeUserId): pass ``` - - + + ```python from supertokens_python.recipe.accountlinking.syncio import unlink_account @@ -416,19 +404,19 @@ def unlink_account_helper(recipe_user_id: RecipeUserId): pass ``` - - + + - - + + ### 5. Convert a `userId` into a `recipeUserId` If you notice, the input to a lot of the functions above is of type `RecipeUserId`. You can convert a string userID into a `RecipeUserId` in the following way: - - + + ```tsx import SuperTokens from "supertokens-node"; @@ -438,15 +426,14 @@ async function getAsRecipeUserIdType(userId: string) { } ``` - - + + -:::note -At the moment this feature is not supported through the Go SDK. +:::note[At the moment this feature is not supported through the Go SDK.] ::: - - + + ```python from supertokens_python.types import RecipeUserId @@ -455,8 +442,8 @@ user_id = "some_user_id"; recipe_user_id = RecipeUserId(user_id) ``` - - + + The reason for this type is that it prevents bugs wherein a function expects a recipe user ID (like `createNewSession`, or `updateEmailOrPassword` from email password recipe). However, you might pass in the primary user ID instead. @@ -484,9 +471,9 @@ Our SDK also exposes other helper functions: ## See also - - - - - - + + + + + + diff --git a/docs/post-authentication/account-linking/meta.ts b/docs/post-authentication/account-linking/meta.ts new file mode 100644 index 0000000000..9c26a2a152 --- /dev/null +++ b/docs/post-authentication/account-linking/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Account Linking", + "icon": "file-user", + "order": 3 +}); diff --git a/docs/post-authentication/dashboard/_category_.json b/docs/post-authentication/dashboard/_category_.json deleted file mode 100644 index 78534d5630..0000000000 --- a/docs/post-authentication/dashboard/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Dashboard", - "position": 4 -} diff --git a/docs/post-authentication/dashboard/initial-setup.mdx b/docs/post-authentication/dashboard/initial-setup.mdx index a75afbe045..e95e01e34a 100644 --- a/docs/post-authentication/dashboard/initial-setup.mdx +++ b/docs/post-authentication/dashboard/initial-setup.mdx @@ -1,36 +1,23 @@ --- title: Initial setup -hide_title: true -sidebar_position: 2 -description: >- - Set up and manage your user management dashboard with SuperTokens integration - and configuration instructions. -page_type: tutorial -recipe: dashboard -category: dashboard +description: Set up and manage your user management dashboard with SuperTokens integration and configuration instructions. +sidebar: + order: 2 --- - -# Setting up the dashboard - ## Overview The following page shows you how to set up the dashboard recipe and access the web interface. You can check the next diagram to understand how the dashboard integrates with your application. - - -Flowchart of architecture when using SuperTokens managed service - - -Flowchart of architecture when self-hosting SuperTokens - + + +Flowchart of architecture when using SuperTokens managed service + + +Flowchart of architecture when self-hosting SuperTokens + @@ -38,14 +25,13 @@ values={[ ### 1. Initialize the `Dashboard` recipe - To get started, initialize the Dashboard recipe in the `recipeList`. - - + + -```tsx +```tsx {12} import SuperTokens from "supertokens-node"; import Dashboard from "supertokens-node/recipe/dashboard"; @@ -57,17 +43,15 @@ SuperTokens.init({ }, recipeList: [ // TODO: Initialise other recipes - // highlight-start Dashboard.init(), - // highlight-end ], }); ``` - - + + -```go +```go {10} import ( "github.com/supertokens/supertokens-golang/recipe/dashboard" "github.com/supertokens/supertokens-golang/supertokens" @@ -77,45 +61,41 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ // TODO: Initialise other recipes - // highlight-start dashboard.Init(nil), - // highlight-end }, }); } ``` - - + + -```python +```python {10} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import dashboard init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ # TODO: Initialise other recipes - # highlight-start dashboard.init(), - # highlight-end ] ) ``` - - + + -#### Update your content security policy {{optional}} +#### Update your content security policy (optional) - - + + If your backend returns a `Content-Security-Policy` header, you encounter the following UI displaying the Content Security Policy violation details. Follow the instructions provided in this UI to make necessary adjustments to your backend Content Security Policy configuration. -![Content Security Policy error handled UI](/img/dashboard/csp-error.png) +![Content Security Policy error handled UI](/docs/img/dashboard/csp-error.png) For example, to address the error message displayed in the above screenshot, you need to modify your `original policy`. In the given example, it appears as follows: @@ -145,8 +125,8 @@ img-src: ``` Essentially, you need to include the domain listed as the `Blocked URI` in your violated directive block within your original policy. - - + + If you return a `Content-Security-Policy` header from your backend, you need to include the following directives for the user management dashboard to work correctly. @@ -160,8 +140,8 @@ img-src: https://purecatamphetamine.github.io/ ``` - - + + If you return a `Content-Security-Policy` header from your backend, you need to include the following directives for the user management dashboard to work correctly. @@ -175,26 +155,24 @@ img-src: https://purecatamphetamine.github.io/ ``` - - + + ### 2. Access the dashboard -:::important -The backend SDK serves the user management dashboard, and you have to use your API domain when trying to visit the dashboard. +:::note[The backend SDK serves the user management dashboard, and you have to use your API domain when trying to visit the dashboard.] ::: -Navigate to `^{appInfo.apiDomain}^{appInfo.apiBasePath}/dashboard` to view the dashboard. +Navigate to `/auth/dashboard` to view the dashboard. -:::note -If you are using Next.js, upon integrating the backend SDK into your Next.js API folder, the dashboard becomes accessible by default at `^{appInfo.apiDomain}/api/auth/dashboard`. For frameworks other than Next.js, access it at `^{appInfo.apiDomain}/auth/dashboard`. Should you have customized the `apiBasePath` configuration property, navigate to `^{appInfo.apiDomain}^{appInfo.apiBasePath}/dashboard` to access the dashboard. +:::note[If you are using Next.js, upon integrating the backend SDK into your Next.js API folder, the dashboard becomes accessible by default at `/api/auth/dashboard`. For frameworks other than Next.js, access it at `/auth/dashboard`. Should you have customized the `apiBasePath` configuration property, navigate to `/auth/dashboard` to access the dashboard.] ::: -Dashboard login screen UI +Dashboard login screen UI ### 3. Create dashboard credentials -:::info Paid Feature +:::info[Paid Feature] You can create 3 dashboard users* for free. If you need to create additional users: @@ -207,7 +185,7 @@ If you need to create additional users: When you first set up SuperTokens, there are no credentials created for the dashboard. If you click the "Add a new user" button in the dashboard login screen you can see the command you need to execute to create credentials. -Dashboard sign up screen UI +Dashboard sign up screen UI To create credentials you need to make a request to SuperTokens core. @@ -215,8 +193,7 @@ To create credentials you need to make a request to SuperTokens core. - Replace `` with your API key. If you are using a self hosted SuperTokens core there is no API key by default. In that case you can either skip or ignore the `api-key` header. - Replace `` and `` with the appropriate values. -:::caution -If using self-hosted SuperTokens core, you need to make sure that you add an API key to the core in case it's exposed to the internet. Otherwise, anyone can create or modify dashboard users. +:::warning[If using self-hosted SuperTokens core, you need to make sure that you add an API key to the core in case it's exposed to the internet. Otherwise, anyone can create or modify dashboard users.] You can add an API key to the core by following the instructions "Auth flow customizations" > "SuperTokens core settings" > "Adding API keys" page. ::: @@ -225,7 +202,7 @@ You can add an API key to the core by following the instructions "Auth flow cust You can update the email or password of existing credentials by using the "Forgot Password" button on the dashboard login page. -Reset your password screen UI +Reset your password screen UI To update credentials you need to make a request to SuperTokens core. @@ -239,15 +216,14 @@ When using the dashboard recipe, you can restrict access to certain features by You can provide an array of emails to the backend SDK when initialising the dashboard recipe: -:::important -- Not providing an admins array results in all dashboard users having both read and write operations. +:::note[- Not providing an admins array results in all dashboard users having both read and write operations.] - Providing an empty array as admins results in all dashboard users having only read access. ::: - - + + -```tsx +```tsx {12,13,14,15,16} import SuperTokens from "supertokens-node"; import Dashboard from "supertokens-node/recipe/dashboard"; @@ -259,21 +235,19 @@ SuperTokens.init({ }, recipeList: [ // TODO: Initialise other recipes - // highlight-start Dashboard.init({ admins: [ "johndoe@gmail.com", ], }), - // highlight-end ], }); ``` - - + + -```go +```go {11,12,13,14,15} import ( "github.com/supertokens/supertokens-golang/recipe/dashboard" "github.com/supertokens/supertokens-golang/supertokens" @@ -284,41 +258,37 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ // TODO: Initialise other recipes - // highlight-start dashboard.Init(&dashboardmodels.TypeInput{ Admins: &[]string{ "johndoe@gmail.com", }, }), - // highlight-end }, }); } ``` - - + + -```python +```python {10,11,12,13,14} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import dashboard init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ # TODO: Initialise other recipes - # highlight-start dashboard.init( admins=[ "johndoe@gmail.com", ], ), - # highlight-end ] ) ``` - - + + diff --git a/docs/post-authentication/dashboard/introduction.mdx b/docs/post-authentication/dashboard/introduction.mdx index 5274512f41..1084e231ac 100644 --- a/docs/post-authentication/dashboard/introduction.mdx +++ b/docs/post-authentication/dashboard/introduction.mdx @@ -1,17 +1,10 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -skip_llms_txt: true description: 'Learn how to manage users in SuperTokens ' -page_type: overview -recipe: dashboard -category: dashboard +sidebar: + order: 1 --- - -# Dashboard - ## Overview With the user management dashboard, you can perform actions through a user interface. @@ -22,32 +15,16 @@ This allows you to view and modify tenants and users through different web actio To get a quick understanding of how the dashboard looks and what it can do you can visit the [live demo](https://dashboard.demo.supertokens.com/api/auth/dashboard). The credentials for logging in are: `email: demo@supertokens.com` and `password: abcd1234`. -Alternatively, you can follow the [quickstart guide](/docs/post-authentication/dashboard/initial-setup) to configure the dashboard in your **SuperTokens** integration. - - - - - Initial setup - - - See how you can initialize the dashboard in your application. - - - - - User management - - - Work with users through the dashboard. - - - - - Tenant management - - - Work with tenants through the dashboard. - - - - +Alternatively, you can follow the [quickstart guide](/post-authentication/dashboard/initial-setup) to configure the dashboard in your **SuperTokens** integration. + + + +See how you can initialize the dashboard in your application. + + +Work with users through the dashboard. + + +Work with tenants through the dashboard. + + diff --git a/docs/post-authentication/dashboard/meta.ts b/docs/post-authentication/dashboard/meta.ts new file mode 100644 index 0000000000..102248e044 --- /dev/null +++ b/docs/post-authentication/dashboard/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Dashboard", + "icon": "layout-dashboard", + "order": 4 +}); diff --git a/docs/post-authentication/dashboard/tenant-management.mdx b/docs/post-authentication/dashboard/tenant-management.mdx index 8894639e7c..5bd92161c9 100644 --- a/docs/post-authentication/dashboard/tenant-management.mdx +++ b/docs/post-authentication/dashboard/tenant-management.mdx @@ -1,29 +1,21 @@ --- title: Tenant Management -hide_title: true -sidebar_position: 4 -toc_max_heading_level: 4 -description: >- - Manage tenants, login methods, and multi-factor authentication using the - tenant management dashboard. -page_type: guide -recipe: dashboard -category: dashboard +description: Manage tenants, login methods, and multi-factor authentication using the tenant management dashboard. +sidebar: + order: 4 --- -# Tenant management - ## Overview This page shows you what actions you can perform on tenants through the dashboard. -:::info Caution +:::info[Caution] This is only available with Node and Python SDKs. ::: -Tenant Management Landing +Tenant Management Landing --- @@ -31,20 +23,20 @@ This is only available with Node and Python SDKs. Clicking on `Add Tenant` prompts you to enter the tenant id. Once you enter the tenant id, click on `Create Now` to create the tenant. You then proceed to the Tenant Details page where you can further manage the newly created tenant. -Create Tenant +Create Tenant ## View tenant details Upon selection or creation of a tenant, the Tenant Details page appears. The sections appear below. -Tenant details +Tenant details ### Tenant ID and users -The first section shows the tenant ID and the number of users in that tenant. Clicking on `See Users` takes you to the [user management page](/docs/post-authentication/dashboard/user-management) where you can view and manage the users for the selected tenant. +The first section shows the tenant ID and the number of users in that tenant. Clicking on `See Users` takes you to the [user management page](/post-authentication/dashboard/user-management) where you can view and manage the users for the selected tenant. -Tenant users +Tenant users ### Enabled login methods @@ -57,36 +49,34 @@ Appropriate recipes must be active to turn on the login methods. For example, :::info -If you are using the Auth React SDK, make sure to enable [usesDynamicLoginMethods](/docs/authentication/enterprise/common-domain-login#3-tell-supertokens-about-the-saved-tenantid-from-the-previous-step) to ensure the frontend automatically shows the login methods based on the selection here. +If you are using the Auth React SDK, make sure to enable [usesDynamicLoginMethods](/authentication/enterprise/common-domain-login#3-tell-supertokens-about-the-saved-tenantid-from-the-previous-step) to ensure the frontend automatically shows the login methods based on the selection here. ::: -Login Methods +Login Methods ### Secondary factors -This section displays the secondary factors available for the tenant. By enabling these toggles, the corresponding factor becomes active for all users of the tenant. Refer to [MultiFactor Authentication docs](/docs/additional-verification/mfa/introduction) for more information. +This section displays the secondary factors available for the tenant. By enabling these toggles, the corresponding factor becomes active for all users of the tenant. Refer to [MultiFactor Authentication docs](/additional-verification/mfa/introduction) for more information. -[MultiFactorAuth](/docs/additional-verification/mfa/initial-setup) recipe must initialize to enable Secondary Factors. +[MultiFactorAuth](/additional-verification/mfa/initial-setup) recipe must initialize to enable Secondary Factors. Also, initialize appropriate recipes in the backend SDK to use a secondary factor. For example, - to turn on TOTP, initialize the TOTP recipe in the backend. - to turn on `OTP Phone`, initialize the Passwordless recipe with `flowType` `USER_INPUT_CODE` and contactMethod `PHONE` -Secondary Factors +Secondary Factors ### Core configuration -Core Configuration +Core Configuration This section shows the current configuration values in core for the tenant. You can edit some of these settings by clicking the `pencil` icon next to the property. -Edit Core Configuration - -:::caution +Edit Core Configuration -Some configuration values may not be editable since they inherit from the App. If using SuperTokens managed hosting, you can modify deployment-level values on the **Configuration** page in the SaaS Dashboard. Else, if you are self-hosting the SuperTokens core, edit them via Docker environment variables or the `configuration.yaml` file. +:::warning[Some configuration values may not be editable since they inherit from the App. If using SuperTokens managed hosting, you can modify deployment-level values on the **Configuration** page in the SaaS Dashboard. Else, if you are self-hosting the SuperTokens core, edit them via Docker environment variables or the `configuration.yaml` file.] ::: @@ -98,27 +88,27 @@ The Social/Enterprise providers section becomes available once `Third Party` log Initially, configure a new provider. -Add provider prompt +Add provider prompt Later on, you can configure new or existing third-party providers from the **Social/Enterprise providers** section. -Social/Enterprise providers +Social/Enterprise providers ### Configure a new provider When adding a new third-party provider, you receive a list of available options, including built-in enterprise and social providers, custom, and SAML. -New Provider +New Provider Upon selection of the desired provider, provide further details such as `Client ID`, `Client Secret`, etc. -New Provider Details +New Provider Details #### Enterprise providers For the Enterprise providers, provide certain extra information before proceeding to the Provider details. For example, Active Directory provider requires a `Directory ID` before editing further details. -Additional configuration for Active Directory +Additional configuration for Active Directory #### Custom providers @@ -126,32 +116,28 @@ If a Social/Enterprise provider is not available in the list of built-in provide Start off by providing `ThirdParty ID`, `Name` and Client details such as `Client ID`, `Secret`, `Scope`, etc. -Custom Provider basic details +Custom Provider basic details If using an OpenID compliant provider, you could add the `OIDC Discovery Endpoint`. Otherwise, configure the provider by manually providing `Authorization Endpoint`, `Token Endpoint`, `User Info Endpoint`, etc. -OpenID configuration +OpenID configuration Finally, clicking on `Save` adds the Social/enterprise provider for the tenant. #### SAML providers -To add a SAML provider, use the `Add SAML Provider` option. For more information on what is SAML and how it works with SuperTokens, refer [SAML docs](/docs/authentication/enterprise/saml). +To add a SAML provider, use the `Add SAML Provider` option. For more information on what is SAML and how it works with SuperTokens, refer [SAML docs](/authentication/enterprise/saml). Upon selection, provide the `Boxy URL` and the `Boxy API Key`. -:::important - -To use SAML providers, an additional Boxy HQ service is necessary. You can either self-host yourself or email for a managed instance. Details for them are also available on this page. +:::note[To use SAML providers, an additional Boxy HQ service is necessary. You can either self-host yourself or email for a managed instance. Details for them are also available on this page.] ::: -Boxy SAML Prompt +Boxy SAML Prompt On continuing, you are further asked for the SAML configuration. You have an option to either provide SAML XML directly or via the Metadata URL from the Provider. Also, fill in other details such as `Suffix`, `Name`, `Redirect URLs` and click on `Save` to add the SAML provider. -:::caution - -Adding ThirdParty suffix is not compulsory, however if you wish to add multiple SAML providers for a tenant, you need to add unique suffixes for each of them. +:::warning[Adding ThirdParty suffix is not compulsory, however if you wish to add multiple SAML providers for a tenant, you need to add unique suffixes for each of them.] ::: diff --git a/docs/post-authentication/dashboard/user-management.mdx b/docs/post-authentication/dashboard/user-management.mdx index 7ab1b33afd..4d9d8c5cb4 100644 --- a/docs/post-authentication/dashboard/user-management.mdx +++ b/docs/post-authentication/dashboard/user-management.mdx @@ -1,17 +1,10 @@ --- title: User management -hide_title: true -sidebar_position: 3 -description: >- - View and manage user details, edit information, and perform actions in the - user dashboard. -page_type: guide -recipe: dashboard -category: dashboard +description: View and manage user details, edit information, and perform actions in the user dashboard. +sidebar: + order: 3 --- -# User management - ## Overview With the user management dashboard you can view the list of users and their details. @@ -23,13 +16,13 @@ You can also perform different operations on these users as mentioned below. If you have created your app, you may not have any users to show on the dashboard. -Empty dashboard screen UI +Empty dashboard screen UI ## List users Navigate to your frontend app and create a user (via the sign-up flow). On creation, if you head back to the dashboard and refresh the page, you see that user: -One user in dashboard screen UI +One user in dashboard screen UI --- @@ -37,9 +30,9 @@ Navigate to your frontend app and create a user (via the sign-up flow). On creat When you select a user you can view detailed information about the user such as email, phone number, user metadata, etc. -User details page screen UI part one +User details page screen UI part one -User details page screen UI part two +User details page screen UI part two --- @@ -47,9 +40,9 @@ When you select a user you can view detailed information about the user such as You can edit user information and perform actions such as resetting a user's password or revoking sessions for a user. -Change password modal UI +Change password modal UI -:::info Note +:::info[Note] Enable some features such as user metadata and email verification in your backend before you can use them in the user management dashboard. ::: @@ -57,13 +50,13 @@ Enable some features such as user metadata and email verification in your backen ## Create user roles and permissions -:::caution no-title +:::warning This feature is only available through the Node.js SDK. ::: When you first use the `UserRoles` recipe, the list of roles is empty. To create roles, click on the "Add Role" button. -No roles created +No roles created This action opens a modal, enabling you to create a role along with its associated permissions. Permissions are essentially a list of strings assigned to a specific role. @@ -71,25 +64,25 @@ This action opens a modal, enabling you to create a role along with its associat ## List user roles -:::caution no-title +:::warning This feature is only available through the Node.js SDK. ::: -Create role +Create role After creating a role, the UI should display a list of all roles in your app. -Roles list +Roles list You can preview the role you created by clicking on the role row. The modal provides options to edit or delete the role. -Preview role +Preview role --- ## Assign user roles -:::caution no-title +:::warning This feature is only available through the Node.js SDK. ::: @@ -97,21 +90,21 @@ To assign a specific role to a user, start by finding the user in the dashboard. If the selected user has associations with multiple tenants, you can choose a `tenantId` from the dropdown menu to specify the tenant for which you'd like to assign roles. -Select tenant +Select tenant Click the edit button to start assigning roles. Then, select the "Assign Role" button, and a modal appears with a list of available roles for assignment to this user. -Assign role +Assign role --- ## Remove user roles -:::caution no-title +:::warning This feature is only available through the Node.js SDK. ::: To remove a role assigned to a user, click on the "X" icon next to that specific role. -View assigned role +View assigned role diff --git a/docs/post-authentication/meta.ts b/docs/post-authentication/meta.ts new file mode 100644 index 0000000000..0fc4126744 --- /dev/null +++ b/docs/post-authentication/meta.ts @@ -0,0 +1,8 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Post Authentication", + "icon": "users", + "order": 5, + "collapsed": true +}); diff --git a/docs/post-authentication/post-login-redirect.mdx b/docs/post-authentication/post-login-redirect.mdx index cd8a09ebcf..6d09b2a790 100644 --- a/docs/post-authentication/post-login-redirect.mdx +++ b/docs/post-authentication/post-login-redirect.mdx @@ -1,25 +1,18 @@ --- title: Post Login Redirect -hide_title: true -sidebar_position: 1 -description: >- - Change post-login redirection paths and configure login screen behavior using - SuperTokens. -page_type: guide -category: post-authentication +description: Change post-login redirection paths and configure login screen behavior using SuperTokens. +sidebar: + order: 1 --- - -# Post login redirection - ## Change redirection path post login - - + + By default, the user is redirected to the the `/` route on your website post login. To change this, you can use the `getRedirectionURL` function on the frontend as shown below: -```tsx +```tsx {9,10,11,12,13,14,15,16,17,18,19,20,21,22,23} import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ @@ -28,7 +21,6 @@ SuperTokens.init({ appName: "...", websiteDomain: "...", }, - // highlight-start getRedirectionURL: async (context) => { if (context.action === "SUCCESS" && context.newSessionCreated) { if (context.redirectToPath !== undefined) { @@ -44,20 +36,18 @@ SuperTokens.init({ } return undefined; }, - // highlight-end recipeList: [ /* Recipe list */] }); ``` - + - + By default, the user is redirected the the `/` route on your website post login. To change this, you can use the `getRedirectionURL` function on the frontend as shown below: -```tsx +```tsx {9,10,11,12,13,14,15,16,17,18,19,20,21,22,23} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -65,7 +55,6 @@ supertokensUIInit({ appName: "...", websiteDomain: "...", }, - // highlight-start getRedirectionURL: async (context) => { if (context.action === "SUCCESS" && context.newSessionCreated) { if (context.redirectToPath !== undefined) { @@ -81,14 +70,13 @@ supertokensUIInit({ } return undefined; }, - // highlight-end recipeList: [ /* Recipe list */] }); ``` - + - + The user will be redirected to the provided URL on: - Successful sign up. @@ -99,30 +87,27 @@ The user will be redirected to the provided URL on: If you want to redirect the user to a different domain, then you can first redirect them to a specific path using the function above, which further redirects them to the final domain. :::info -Please refer to [this page](/docs/references/frontend-sdks/hooks#redirection-callback-hook) to learn more about the `getRedirectionURL` hook. +Please refer to [this page](/references/frontend-sdks/hooks#redirection-callback-hook) to learn more about the `getRedirectionURL` hook. ::: ## Redirect user to the login page - - + + Use the `redirectToAuth({show?: "signin" | "signup", redirectBack?: boolean}?)` function to redirect the user to the login screen. For example, you may want to call this function when the user clicks on the login button. -```tsx -// highlight-next-line +```tsx {1,6,11} import React from "react"; import { redirectToAuth } from "supertokens-auth-react"; function NavBar () { async function onLogin () { - // highlight-next-line redirectToAuth(); } return (
  • Home
  • - // highlight-next-line
  • Login
@@ -134,12 +119,12 @@ function NavBar () { - Call `redirectToAuth({show: "signup"})` to take them to the sign up screen - If you do not want the user to be redirected to the current page post sign in, use `redirectToAuth({redirectBack: false})` -
- + + Redirect the user to the `/auth` (this is the default path for the pre-built UI) -```ts +```ts {8,14} import { Component } from "@angular/core"; @Component({ @@ -147,14 +132,12 @@ import { Component } from "@angular/core"; template: `
  • Home
  • - // highlight-next-line
  • Login
`, }) export class NavBarComponent { async onLogin () { - // highlight-next-line window.location.href = "/auth?show=signin&redirectToPath=" + encodeURIComponent(window.location.pathname); } } @@ -164,17 +147,16 @@ export class NavBarComponent { - Set `show=signup` to take them to the sign up screen - Set `redirectToPath` to redirect the user to a specific page after they have signed in, or you can skip it to take them to the `/` route (which is the default one). -
+ - + Redirect the user to the `/auth` (this is the default path for the pre-built UI) -```html +```html {4,14} @@ -185,7 +167,6 @@ export default { name: "NavBarComponent", methods: { async onLogin() { - // highlight-next-line window.location.href = "/auth?show=signin&redirectToPath=" + encodeURIComponent(window.location.pathname); } } @@ -197,17 +178,17 @@ export default { - Set `show=signup` to take them to the sign up screen - Set `redirectToPath` to redirect the user to a specific page after they have signed in, or you can skip it to take them to the `/` route (which is the default one). - -
+ + ## Showing sign up by default The login screen shows the sign in UI by default, to change that, you can set the following config: - - + + -```tsx +```tsx {9} import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ @@ -216,19 +197,17 @@ SuperTokens.init({ appName: "...", websiteDomain: "..." }, - // highlight-next-line defaultToSignUp: true, recipeList: [ /* ... */] }); ``` - + - + -```tsx +```tsx {9} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -236,23 +215,22 @@ supertokensUIInit({ appName: "...", websiteDomain: "..." }, - // highlight-next-line defaultToSignUp: true, recipeList: [ /* ... */] }); ``` - - + + --- ## See also - - - - - - - + + + + + + + diff --git a/docs/post-authentication/session-management/_category_.json b/docs/post-authentication/session-management/_category_.json deleted file mode 100644 index 2e192d6606..0000000000 --- a/docs/post-authentication/session-management/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Session Management", - "position": 1.1 -} diff --git a/docs/post-authentication/session-management/access-session-data.mdx b/docs/post-authentication/session-management/access-session-data.mdx index 4b92890eac..d871e0f97c 100644 --- a/docs/post-authentication/session-management/access-session-data.mdx +++ b/docs/post-authentication/session-management/access-session-data.mdx @@ -1,20 +1,12 @@ --- title: Access Session Data -hide_title: true -sidebar_position: 2 -toc_max_heading_level: 4 description: >- - Learn how to access session data including JWT tokens, tenant IDs, and user - sessions across different programming languages and frameworks. -page_type: guide -recipe: session -category: session-management + Learn how to access session data including JWT tokens, tenant IDs, and user sessions across different programming + languages and frameworks. +sidebar: + order: 2 --- - - -# Access session data - ## Overview The session data is accessible, both in the backend and on the frontend, after a user has successfully logged in. @@ -23,7 +15,7 @@ This guide shows you how to access different session properties. ## Before you start - +:::info[Access token guidance] --- @@ -32,12 +24,12 @@ This guide shows you how to access different session properties. ### On the backend - - - - + + + + -```tsx +```tsx {10} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; @@ -47,17 +39,15 @@ app.get("/getJWT", verifySession(), async (req, res) => { let session = req.session; - // highlight-start let jwt = session.getAccessToken(); - // highlight-end res.json({ token: jwt }) }); ``` - - + + -```tsx +```tsx {20} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import { SessionRequest } from "supertokens-node/framework/hapi"; @@ -77,17 +67,15 @@ server.route({ handler: async (req: SessionRequest, res) => { let session = req.session; - // highlight-start let jwt = session!.getAccessToken(); - // highlight-end return res.response({ token: jwt }).code(200); } }) ``` - - + + -```tsx +```tsx {11} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; @@ -98,26 +86,22 @@ fastify.get("/getJWT", { }, (req, res) => { let session = req.session; - // highlight-start let jwt = session.getAccessToken(); - // highlight-end res.send({ token: jwt }); }); ``` - - + + -```tsx +```tsx {7} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; async function getJWT(awsEvent: SessionEvent) { let session = awsEvent.session; - // highlight-start let jwt = session!.getAccessToken(); - // highlight-end return { body: JSON.stringify({ token: jwt }), @@ -128,10 +112,10 @@ async function getJWT(awsEvent: SessionEvent) { exports.handler = verifySession(getJWT); ``` - - + + -```tsx +```tsx {10} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from "supertokens-node/framework/koa"; @@ -141,17 +125,15 @@ let router = new KoaRouter(); router.get("/getJWT", verifySession(), (ctx: SessionContext, next) => { let session = ctx.session; - // highlight-start let jwt = session!.getAccessToken(); - // highlight-end ctx.body = { token: jwt }; }); ``` - - + + -```tsx +```tsx {14} import { inject, intercept } from "@loopback/core"; import { RestBindings, get, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; @@ -165,24 +147,22 @@ class GetJWT { handler() { let session = this.ctx.session; - // highlight-start let jwt = session!.getAccessToken(); - // highlight-end return { token: jwt }; } } ``` - - + + + - - + -```tsx +```tsx {15} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; @@ -197,9 +177,7 @@ export default async function getJWT(req: SessionRequest, res: any) { ) let session = req.session; - // highlight-start let jwt = session!.getAccessToken(); - // highlight-end res.json({ token: jwt }) } ``` @@ -207,11 +185,10 @@ export default async function getJWT(req: SessionRequest, res: any) { -```tsx +```tsx {13} import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -221,9 +198,7 @@ export function POST(request: NextRequest) { if (err) { return NextResponse.json(err, { status: 500 }); } - // highlight-start let jwt = session!.getAccessToken(); - // highlight-end return NextResponse.json({ token: jwt }); }); } @@ -231,13 +206,12 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {10,11} import { Controller, Get, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; @Controller() @@ -245,20 +219,18 @@ export class ExampleController { @Get('example') @UseGuards(new AuthGuard()) async postExample(@Session() session: SessionContainer): Promise<{ token: any }> { - //highlight-start // For more information about "AuthGuard" and the "Session" decorator please read our NestJS guide. const jwt = session.getAccessToken(); - //highlight-end return { token: jwt }; } } ``` - - - - + + + + -```go +```go {13} import ( "fmt" "net/http" @@ -271,60 +243,56 @@ func getJWT(w http.ResponseWriter, r *http.Request) { // retrieve the session object as shown below sessionContainer := session.GetSessionFromRequestContext(r.Context()) - // highlight-start jwt := sessionContainer.GetAccessToken() - // highlight-end fmt.Println(jwt) } ``` - - + + - - + + -```python +```python {9} from fastapi import Depends from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.fastapi import verify_session -@app.get('/getJWT') # type: ignore +@app.get('/getJWT') async def get_jwt(session: SessionContainer = Depends(verify_session())): - # highlight-next-line current_jwt = session.get_access_token() print(current_jwt) # TODO... ``` - - + + -```python +```python {12} from flask import g from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.flask import verify_session -@app.route('/getJWT', methods=['GET']) # type: ignore +@app.route('/getJWT', methods=['GET']) @verify_session() def get_jwt(): - session: SessionContainer = g.supertokens # type: ignore + session: SessionContainer = g.supertokens - # highlight-next-line current_jwt = session.get_access_token() print(current_jwt) # TODO... ``` - - + + -```python +```python {13} from typing import cast from django.http import HttpRequest @@ -335,19 +303,18 @@ from supertokens_python.recipe.session.framework.django.asyncio import verify_se @verify_session() async def get_jwt(request: HttpRequest): - session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore + session: SessionContainer = cast(SessionContainer, request.supertokens) - # highlight-next-line current_jwt = session.get_access_token() print(current_jwt) # TODO... ``` - - + + - - + + ### On the frontend @@ -356,14 +323,13 @@ async def get_jwt(request: HttpRequest): When using cookie based auth, by default, the access token is not readable by the SDK on the frontend (since it's stored as `httpOnly` cookie). To enable this, you need to set the `exposeAccessTokenToFrontendInCookieBasedAuth` parameter to `true`. -:::important -If you are only using header-based sessions, you can skip this step +:::note[If you are only using header-based sessions, you can skip this step] ::: - - + + -```tsx +```tsx {15} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -378,17 +344,15 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - //highlight-start exposeAccessTokenToFrontendInCookieBasedAuth: true, - //highlight-end }) ] }); ``` - - + + -```go +```go {11} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -399,45 +363,42 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - //highlight-start ExposeAccessTokenToFrontendInCookieBasedAuth: true, - //highlight-end }), }, }) } ``` - - + + -```python +```python {10} from supertokens_python import InputAppInfo, init from supertokens_python.recipe import session init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-next-line expose_access_token_to_frontend_in_cookie_based_auth=True ) ] ) ``` - - + + #### 2. Read the access token - + - + - - + + ```tsx import Session from 'supertokens-auth-react/recipe/session'; @@ -450,8 +411,8 @@ async function getJWT() { } ``` - - + + ```tsx import Session from 'supertokens-web-js/recipe/session'; @@ -464,18 +425,18 @@ async function getJWT() { } ``` - - + + - + - + - - + + - - + + ```tsx import Session from 'supertokens-web-js/recipe/session'; @@ -488,11 +449,10 @@ async function getJWT() { } ``` - - + + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; async function getJWT() { if (await supertokensSession.doesSessionExist()) { let userId = await supertokensSession.getUserId(); @@ -501,15 +461,15 @@ async function getJWT() { } ``` - - - + + + - + - + - + ```tsx import SuperTokens from 'supertokens-react-native'; @@ -522,9 +482,9 @@ async function getJWT() { } ``` - + - + ```kotlin import android.app.Application @@ -538,9 +498,9 @@ class MainApplication: Application() { } ``` - + - + ```swift import UIKit @@ -554,9 +514,9 @@ fileprivate class ViewController: UIViewController { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -570,20 +530,20 @@ Future getJWT() async { } ``` - + - + - - + + - + --- ## Access the Tenant ID -:::info Multi Tenancy +:::info[Multi Tenancy] This feature is only relevant if you are using the multi tenancy feature. ::: @@ -591,30 +551,28 @@ The session's access token payload contains the tenant ID in the `tId` claim. Yo ### On the backend - - - - + + + + -```tsx +```tsx {7,8} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; let app = express(); -// highlight-start app.post("/like-comment", verifySession(), (req: SessionRequest, res) => { let tenantId = req.session!.getTenantId(); - // highlight-end //.... }); ``` - - + + -```tsx +```tsx {10,11,12,13,14,15,16,17,18} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import { SessionRequest } from "supertokens-node/framework/hapi"; @@ -624,7 +582,6 @@ let server = Hapi.server({ port: 8000 }); server.route({ path: "/like-comment", method: "post", - //highlight-start options: { pre: [ { @@ -634,35 +591,32 @@ server.route({ }, handler: async (req: SessionRequest, res) => { let tenantId = req.session!.getTenantId(); - //highlight-end //... } }) ``` - - + + -```tsx +```tsx {7,8,9,10} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import { SessionRequest } from "supertokens-node/framework/fastify"; let fastify = Fastify(); -//highlight-start fastify.post("/like-comment", { preHandler: verifySession(), }, (req: SessionRequest, res) => { let tenantId = req.session!.getTenantId(); - //highlight-end //.... }); ``` - - + + -```tsx +```tsx {9} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEventV2 } from "supertokens-node/framework/awsLambda"; @@ -671,66 +625,60 @@ async function likeComment(awsEvent: SessionEventV2) { //.... }; -//highlight-next-line exports.handler = verifySession(likeComment); ``` - - + + -```tsx +```tsx {7,8} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from "supertokens-node/framework/koa"; let router = new KoaRouter(); -//highlight-start router.post("/like-comment", verifySession(), (ctx: SessionContext, next) => { let tenantId = ctx.session!.getTenantId(); - //highlight-end //.... }); ``` - - + + -```tsx +```tsx {7,8,9,10,11,12} import { inject, intercept } from "@loopback/core"; import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; import { SessionContext } from "supertokens-node/framework/loopback"; class LikeComment { - //highlight-start constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { } @post("/like-comment") @intercept(verifySession()) @response(200) handler() { let tenantId = (this.ctx as SessionContext).session!.getTenantId(); - //highlight-end //.... } } ``` - - + + + - - + -```tsx +```tsx {5,6,7,8,9,10,11,12,13,14} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; -// highlight-start export default async function likeComment(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { @@ -741,7 +689,6 @@ export default async function likeComment(req: SessionRequest, res: any) { ) let tenantId = req.session!.getTenantId(); - // highlight-end //.... } ``` @@ -753,7 +700,6 @@ export default async function likeComment(req: SessionRequest, res: any) { import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -771,13 +717,12 @@ export function POST(request: NextRequest) { ``` - - + + -```tsx +```tsx {10,11} import { Controller, Post, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; @Controller() @@ -785,21 +730,19 @@ export class ExampleController { @Post('example') @UseGuards(new AuthGuard()) // For more information about this guard please read our NestJS guide. async postExample(@Session() session: SessionContainer): Promise { - //highlight-start let tenantId = session.getTenantId(); - //highlight-end //.... return true; } } ``` - - - - - - + + + + + + ```go import ( @@ -826,8 +769,8 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + ```go import ( @@ -869,8 +812,8 @@ func likeCommentAPI(c *gin.Context) { } ``` - - + + ```go import ( @@ -898,8 +841,8 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + ```go import ( @@ -927,54 +870,52 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + - - + + -```python +```python {9} from fastapi import Depends from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.fastapi import verify_session -@app.get('/getTenantId') # type: ignore +@app.get('/getTenantId') async def get_tenant_id(session: SessionContainer = Depends(verify_session())): - # highlight-next-line tenant_id = session.get_tenant_id() print(tenant_id) ``` - - + + -```python +```python {12} from flask import g from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.flask import verify_session -@app.route('/getTenantId', methods=['GET']) # type: ignore +@app.route('/getTenantId', methods=['GET']) @verify_session() def get_tenant_id(): - session: SessionContainer = g.supertokens # type: ignore + session: SessionContainer = g.supertokens - # highlight-next-line tenant_id = session.get_tenant_id() print(tenant_id) ``` - - + + -```python +```python {13} from typing import cast from django.http import HttpRequest @@ -985,27 +926,25 @@ from supertokens_python.recipe.session.framework.django.asyncio import verify_se @verify_session() async def get_tenant_id(request: HttpRequest): - session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore + session: SessionContainer = cast(SessionContainer, request.supertokens) - # highlight-next-line tenant_id = session.get_tenant_id() print(tenant_id) ``` - - + + - - + + -:::note -If you are not using the backend SDK and are doing JWT verification yourself, you can fetch the tenant ID from the JWT by reading the `tId` claim. +:::note[If you are not using the backend SDK and are doing JWT verification yourself, you can fetch the tenant ID from the JWT by reading the `tId` claim.] ::: ### On the frontend -You can read the tenant ID on the frontend by adding the `tId` claim from the [access token payload](/docs/additional-verification/session-verification/claim-validation#using-the-access-token-payload). +You can read the tenant ID on the frontend by adding the `tId` claim from the [access token payload](/additional-verification/session-verification/claim-validation#using-the-access-token-payload). --- @@ -1013,17 +952,16 @@ You can read the tenant ID on the frontend by adding the `tId` claim from the [a Given a user ID, you can fetch all sessions that are active for that user in the following way: - - + + -```tsx +```tsx {7} import Session from "supertokens-node/recipe/session"; async function getSessions() { let userId = "someUserId" // fetch somehow // sessionHandles is string[] - // highlight-next-line let sessionHandles = await Session.getAllSessionHandlesForUser(userId); sessionHandles.forEach((handle) => { @@ -1036,10 +974,10 @@ async function getSessions() { }) } ``` - - + + -```go +```go {9} import ( "fmt" @@ -1048,7 +986,6 @@ import ( func main() { // sessionHandles is string[] - // highlight-next-line tenantId := "public" sessionHandles, err := session.GetAllSessionHandlesForUser("someUserId", &tenantId) if err != nil { @@ -1067,18 +1004,17 @@ func main() { } } ``` - - - - + + + + -```python +```python {6} from supertokens_python.recipe.session.asyncio import get_all_session_handles_for_user async def some_func(): # session_handles is List[string] - # highlight-next-line session_handles = await get_all_session_handles_for_user("someUserId") for _ in session_handles: @@ -1091,14 +1027,13 @@ async def some_func(): # ``` - - + + -```python +```python {4} from supertokens_python.recipe.session.syncio import get_all_session_handles_for_user # session_handles is List[string] -# highlight-next-line session_handles = get_all_session_handles_for_user("someUserId") for session_handle in session_handles: @@ -1111,12 +1046,12 @@ for session_handle in session_handles: # ``` - - - - + + + + -:::info Multi Tenancy +:::info[Multi Tenancy] By default, the method returns all the `session handles` for the user across all the tenants. If you want to fetch the sessions for a user in a specific tenant, you can pass the tenant ID as a parameter to the function call. @@ -1127,11 +1062,10 @@ If you want to fetch the sessions for a user in a specific tenant, you can pass ## See also - - - - - - - - + + + + + + + diff --git a/docs/post-authentication/session-management/advanced-workflows/_category_.json b/docs/post-authentication/session-management/advanced-workflows/_category_.json deleted file mode 100644 index 8d19e0a1b6..0000000000 --- a/docs/post-authentication/session-management/advanced-workflows/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Advanced Workflows", - "position": 5 -} diff --git a/docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting.mdx b/docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting.mdx index e5fe2711f5..f7c549822f 100644 --- a/docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting.mdx +++ b/docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting.mdx @@ -1,18 +1,10 @@ --- title: Blacklist access tokens -hide_title: true -sidebar_position: 7 -description: >- - Enable immediate session revocation by implementing access token blacklisting - with database checks. -page_type: guide -recipe: session -category: session-management +description: Enable immediate session revocation by implementing access token blacklisting with database checks. +sidebar: + order: 7 --- - -# Blacklist access tokens - ## Overview By default, session verification is stateless. @@ -24,8 +16,8 @@ Since you can use this feature on a per API basis, we recommend that you only us ## Before you start -:::caution -For managed service users, please check [the rate limit policy](/docs/deployment/rate-limits) before implementing this feature. If you suspect that you might breach the free limit you can: +:::warning +For managed service users, please check [the rate limit policy](/deployment/rate-limits) before implementing this feature. If you suspect that you might breach the free limit you can: - [Email support](mailto:support@supertokens.com) to increase your rate limit. - Use the `checkDatabase` flag only on certain important APIs. For example, omit using it in any `GET` API as those are not state changing. - Implement your own method for keeping track of revoked access tokens by using a cache like Redis. @@ -35,30 +27,28 @@ For managed service users, please check [the rate limit policy](/docs/deployment ## Using `Verify Session` - - - - + + + + -```tsx +```tsx {7,8} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; let app = express(); -// highlight-start app.post("/like-comment", verifySession({ checkDatabase: true }), (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - // highlight-end //.... }); ``` - - + + -```tsx +```tsx {10,11,12,13,14,15,16,17,18} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import { SessionRequest } from "supertokens-node/framework/hapi"; @@ -68,7 +58,6 @@ let server = Hapi.server({ port: 8000 }); server.route({ path: "/like-comment", method: "post", - //highlight-start options: { pre: [ { @@ -78,35 +67,32 @@ server.route({ }, handler: async (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - //highlight-end //... } }) ``` - - + + -```tsx +```tsx {7,8,9,10} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import { SessionRequest } from "supertokens-node/framework/fastify"; let fastify = Fastify(); -//highlight-start fastify.post("/like-comment", { preHandler: verifySession({ checkDatabase: true }), }, (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - //highlight-end //.... }); ``` - - + + -```tsx +```tsx {9} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEventV2 } from "supertokens-node/framework/awsLambda"; @@ -115,66 +101,60 @@ async function likeComment(awsEvent: SessionEventV2) { //.... }; -//highlight-next-line exports.handler = verifySession(likeComment, { checkDatabase: true }); ``` - - + + -```tsx +```tsx {7,8} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from "supertokens-node/framework/koa"; let router = new KoaRouter(); -//highlight-start router.post("/like-comment", verifySession({ checkDatabase: true }), (ctx: SessionContext, next) => { let userId = ctx.session!.getUserId(); - //highlight-end //.... }); ``` - - + + -```tsx +```tsx {7,8,9,10,11,12} import { inject, intercept } from "@loopback/core"; import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; import { SessionContext } from "supertokens-node/framework/loopback"; class LikeComment { - //highlight-start constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { } @post("/like-comment") @intercept(verifySession({ checkDatabase: true })) @response(200) handler() { let userId = (this.ctx as SessionContext).session!.getUserId(); - //highlight-end //.... } } ``` - - + + + - - + -```tsx +```tsx {5,6,7,8,9,10,11,12,13,14} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; -// highlight-start export default async function likeComment(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { @@ -185,7 +165,6 @@ export default async function likeComment(req: SessionRequest, res: any) { ) let userId = req.session!.getUserId(); - // highlight-end //.... } ``` @@ -197,7 +176,6 @@ export default async function likeComment(req: SessionRequest, res: any) { import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -216,13 +194,12 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {10,11} import { Controller, Post, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; @Controller() @@ -230,21 +207,19 @@ export class ExampleController { @Post('example') @UseGuards(new AuthGuard({ checkDatabase: true })) // For more information about this guard please read our NestJS guide. async postExample(@Session() session: SessionContainer): Promise { - //highlight-start let userId = session.getUserId(); - //highlight-end //.... return true; } } ``` - - - - - - + + + + + + ```go import ( @@ -275,8 +250,8 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + ```go import ( @@ -321,8 +296,8 @@ func likeCommentAPI(c *gin.Context) { } ``` - - + + ```go import ( @@ -354,8 +329,8 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + ```go import ( @@ -387,56 +362,52 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + - - + + -```python +```python {7,8,9} from fastapi import Depends from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.fastapi import verify_session -# highlight-start -@app.post('/like_comment') # type: ignore +@app.post('/like_comment') async def like_comment(session: SessionContainer = Depends(verify_session(check_database=True))): user_id = session.get_user_id() - # highlight-end print(user_id) ``` - - + + -```python +```python {7,8,9,10,11,12} from flask import g from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.flask import verify_session -# highlight-start -@app.route('/update-jwt', methods=['POST']) # type: ignore +@app.route('/update-jwt', methods=['POST']) @verify_session(check_database=True) def like_comment(): - session: SessionContainer = g.supertokens # type: ignore + session: SessionContainer = g.supertokens user_id = session.get_user_id() - # highlight-end print(user_id) ``` - - + + -```python +```python {9,10,11,12,13} from typing import cast from django.http import HttpRequest @@ -445,31 +416,29 @@ from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.django.asyncio import verify_session -# highlight-start @verify_session(check_database=True) async def like_comment(request: HttpRequest): - session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore + session: SessionContainer = cast(SessionContainer, request.supertokens) user_id = session.get_user_id() - # highlight-end print(user_id) ``` - - + + - - + + --- ## Using `Get Session` - - - - + + + + ```tsx import express from "express"; @@ -493,8 +462,8 @@ app.post("/like-comment", async (req, res, next) => { }); ``` - - + + ```tsx import Hapi from "@hapi/hapi"; @@ -519,8 +488,8 @@ server.route({ } }) ``` - - + + ```tsx import Fastify from "fastify"; @@ -540,10 +509,10 @@ fastify.post("/like-comment", async (req, res) => { }); ``` - - + + -```tsx +```tsx {17} import Session from "supertokens-node/recipe/session"; import { middleware } from "supertokens-node/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; @@ -560,12 +529,11 @@ async function likeComment(awsEvent: SessionEvent) { //.... }; -//highlight-next-line exports.handler = middleware(likeComment); ``` - - + + ```tsx import KoaRouter from "koa-router"; @@ -586,8 +554,8 @@ router.post("/like-comment", async (ctx, next) => { }); ``` - - + + ```tsx import { inject } from "@loopback/core"; @@ -613,12 +581,12 @@ class LikeComment { } ``` - - + + + - - + @@ -652,7 +620,6 @@ export default async function likeComment(req: SessionRequest, res: any) { import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -671,10 +638,10 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {9,10,11,12,13,14,15,16} import { Controller, Post, UseGuards, Req, Res } from "@nestjs/common"; import type { Request, Response } from "express"; import Session from "supertokens-node/recipe/session"; @@ -683,7 +650,6 @@ import Session from "supertokens-node/recipe/session"; export class ExampleController { @Post('example') async postExample(@Req() req: Request, @Res({ passthrough: true }) res: Response): Promise { - //highlight-start // This should be done inside a parameter decorator, for more information please read our NestJS guide. const session = await Session.getSession(req, res, { checkDatabase: true }) @@ -692,16 +658,15 @@ export class ExampleController { } else { // user is not logged in... } - //highlight-end //.... return true; } } ``` - - - - + + + + ```go import ( @@ -736,20 +701,19 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - - - + + + + -```python +```python {8} from fastapi import Request from supertokens_python.recipe.session.asyncio import get_session -@app.post('/like-comment') # type: ignore +@app.post('/like-comment') async def like_comment(request: Request): - # highlight-next-line session = await get_session(request, check_database=True) if session is not None: @@ -759,18 +723,17 @@ async def like_comment(request: Request): pass # user is not logged in ``` - - + + -```python +```python {8} from flask.wrappers import Request from supertokens_python.recipe.session.syncio import get_session -@app.route('/like-comment', methods=['POST']) # type: ignore +@app.route('/like-comment', methods=['POST']) def like_comment(request: Request): - # highlight-next-line session = get_session(request, check_database=True) if session is not None: @@ -780,17 +743,16 @@ def like_comment(request: Request): pass # user is not logged in ``` - - + + -```python +```python {7} from django.http import HttpRequest from supertokens_python.recipe.session.asyncio import get_session async def like_comment(request: HttpRequest): - # highlight-next-line session = await get_session(request, check_database=True) if session is not None: @@ -800,8 +762,8 @@ async def like_comment(request: HttpRequest): pass # user is not logged in ``` - - + + - - + + diff --git a/docs/post-authentication/session-management/advanced-workflows/anonymous-session.mdx b/docs/post-authentication/session-management/advanced-workflows/anonymous-session.mdx index a125bd9b32..129b0c8ffb 100644 --- a/docs/post-authentication/session-management/advanced-workflows/anonymous-session.mdx +++ b/docs/post-authentication/session-management/advanced-workflows/anonymous-session.mdx @@ -1,18 +1,10 @@ --- title: Implement anonymous sessions -hide_title: true -sidebar_position: 1 -description: >- - Track user actions with anonymous sessions, create and verify JWTs, and - transfer data post-login. -page_type: guide -recipe: session -category: session-management +description: Track user actions with anonymous sessions, create and verify JWTs, and transfer data post-login. +sidebar: + order: 1 --- - -# Implement anonymous sessions - ## Overview With anonymous sessions, you can keep track of user's action / data before they login, and then transfer that data to their post login session. @@ -32,8 +24,8 @@ They can store any information about the user's activity, and they don't occupy Start by creating a JWT like in the next example: - - + + ```tsx import Session from "supertokens-node/recipe/session" @@ -51,8 +43,8 @@ async function createAnonymousJWT(payload: any) { } ``` - - + + ```go import ( @@ -76,11 +68,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.recipe.session import asyncio @@ -99,8 +91,8 @@ async def create_jwt(): raise Exception("Unable to create JWT. Should never come here.") ``` - - + + ```python from supertokens_python.recipe.session.syncio import create_jwt @@ -118,11 +110,11 @@ else: raise Exception("Unable to create JWT. Should never come here.") ``` - - + + - - + + - As shown in the code above, you can add any payload you like to the JWT. You can even add a `sub` (`userId`) payload with a random `UUID` if you like, or some user ID with a prefix like `"G-.."` which indicates this is a guest user ID. - You could create your own application middleware which inspects the request and auto adds a JWT to it in the response cookies. This way, whenever a user visits your website and makes an API call, they get a JWT in their cookies, and you can use that JWT to track their activity. @@ -134,28 +126,25 @@ This way you can use it to track the activity during a session. #### Verify the JWT -To check if an anonymous session is valid read through the [manual JWT verification section](/docs/additional-verification/session-verification/protect-api-routes#using-a-jwt-verification-library). +To check if an anonymous session is valid read through the [manual JWT verification section](/additional-verification/session-verification/protect-api-routes#using-a-jwt-verification-library). On thing to note here is that in the section about verification using the public key string, you do not need to set `useDynamicAccessTokenSigningKey` to `true`. The token creation process in this scenario uses the static signing key (`kid` starting the `s-..`) by default. -:::caution -You **cannot** use the `verifySession` or `getSession` functions to verify JWTs from anonymous sessions. +:::warning[You **cannot** use the `verifySession` or `getSession` functions to verify JWTs from anonymous sessions.] The `verifySession` and `getSession` check for the presence of certain claims in the JWT (`sessionHandle`, `refreshTokenHash` etc...) that the Session recipe adds for authenticated users. ::: - - ### 3. Transfer the data to a logged in session The idea here is to override the `Session` recipe on the `backend`. Whenever the user logs in or signs up, the data from the anonymous session transfers to the logged-in session. The override attempts to read the request header cookie to get the JWT. It assumes that you have added it to the cookies, verifies it, and then adds the payload to the logged-in session. - - + + -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -171,7 +160,6 @@ SuperTokens.init({ recipeList: [ // ... Session.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -212,15 +200,14 @@ SuperTokens.init({ }; }, }, - // highlight-end }) ] }); ``` - - + + -```go +```go {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -231,7 +218,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - // highlight-start Override: &sessmodels.OverrideStruct{ Functions: func(originalImplementation sessmodels.RecipeInterface) sessmodels.RecipeInterface { // First we copy the original implementation func @@ -275,16 +261,15 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {67} from supertokens_python import init, InputAppInfo, get_request_from_user_context from supertokens_python.recipe import session from supertokens_python.recipe.session.interfaces import RecipeInterface @@ -348,21 +333,19 @@ def override_functions(original_implementation: RecipeInterface): init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ session.init( - # highlight-start override=session.InputOverrideConfig(functions=override_functions) - # highlight-end ) ], ) ``` - - + + - In the above code snippet, the system reads the JWT from the request header cookie. If it exists, it verifies it and then adds the payload to the logged-in session. - If the JWT doesn't exist, or if the system cannot verify it, it would be safe to ignore it and create the logged-in session anyway. - We assume that the you have saved the JWT in the cookies in with the key of `jwt`. But if not, you can remove the JWT from the request based on how you have saved it. -You can even read the headers from the request. +You can even read the headers from the request. diff --git a/docs/post-authentication/session-management/advanced-workflows/customize-error-handling.mdx b/docs/post-authentication/session-management/advanced-workflows/customize-error-handling.mdx index 8fe51954df..703ffee5b0 100644 --- a/docs/post-authentication/session-management/advanced-workflows/customize-error-handling.mdx +++ b/docs/post-authentication/session-management/advanced-workflows/customize-error-handling.mdx @@ -1,16 +1,10 @@ --- title: Customize error handling -hide_title: true -sidebar_position: 3 description: Customize errors thrown by the Session recipe in your SuperTokens integration. -page_type: guide -recipe: session -category: session-management +sidebar: + order: 3 --- - -# Customize error handling - ## Overview The following page shows the errors that the SuperTokens Session recipe throws and how you can customize them. @@ -22,10 +16,10 @@ The following page shows the errors that the SuperTokens Session recipe throws a The system generates the error when someone accesses a protected backend API without a session. The default behavior is to clear session tokens (if any) and send a 401 to the frontend. - - + + -```tsx +```tsx {15,16,17,18,19} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -40,21 +34,19 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - //highlight-start errorHandlers: { onUnauthorised: async (message, request, response, userContext) => { // TODO: Write your own logic and then send a 401 response to the frontend }, } - //highlight-end }) ] }); ``` - - + + -```go +```go {13,14,15,16,17,18} import ( "net/http" @@ -67,23 +59,21 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - //highlight-start ErrorHandlers: &sessmodels.ErrorHandlers{ OnUnauthorised: func(message string, req *http.Request, res http.ResponseWriter) error { // TODO: Write your own logic and then send a 401 response to the frontend return nil }, }, - //highlight-end }), }, }) } ``` - - + + -```python +```python {14,15,16} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session from supertokens_python.framework import BaseRequest, BaseResponse @@ -94,21 +84,19 @@ async def unauthorised_callback(req: BaseRequest, err: str, response: BaseRespon init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start error_handlers=session.InputErrorHandlers( on_unauthorised=unauthorised_callback ) - # highlight-end ) ] ) ``` - - + + --- @@ -117,10 +105,10 @@ init( The system generates the error when someone accesses a protected backend API with a session that doesn't pass the claim validators. The default behavior is to send a 403 to the frontend with the errors included in the body. - - + + -```tsx +```tsx {15,16,17,18,19} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -135,21 +123,19 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - //highlight-start errorHandlers: { onInvalidClaim: async (validatorErrors, request, response, userContext) => { // TODO: Write your own logic and then send a 403 response to the frontend }, } - //highlight-end }) ] }); ``` - - + + -```go +```go {14,15,16,17,18,19} import ( "net/http" @@ -163,23 +149,21 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - //highlight-start ErrorHandlers: &sessmodels.ErrorHandlers{ OnInvalidClaim: func(validationErrors []claims.ClaimValidationError, req *http.Request, res http.ResponseWriter) error { // TODO: Write your own logic and then send a 403 response to the frontend return nil }, }, - //highlight-end }), }, }) } ``` - - + + -```python +```python {17,18,19} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session from supertokens_python.recipe.session.exceptions import ClaimValidationError @@ -193,21 +177,19 @@ async def invalid_claim_callback(req: BaseRequest, invalid_claims: List[ClaimVal init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start error_handlers=session.InputErrorHandlers( on_invalid_claim=invalid_claim_callback ) - # highlight-end ) ] ) ``` - - + + --- @@ -217,10 +199,10 @@ The system generates the error when the system detects a [session hijacking](htt This happens through the use of [rotating refresh tokens](https://supertokens.com/blog/the-best-way-to-securely-manage-user-sessions). The default behavior is to revoke the session and send a `401` to the frontend. - - + + -```tsx +```tsx {15,16,17,18,19} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -235,21 +217,19 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - //highlight-start errorHandlers: { onTokenTheftDetected: async (sessionHandle, userId, req, res, userContext) => { // TODO: Write your own logic and then send a 401 response to the frontend }, } - //highlight-end }) ] }); ``` - - + + -```go +```go {13,14,15,16,17,18,19} import ( "net/http" @@ -262,7 +242,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - //highlight-start ErrorHandlers: &sessmodels.ErrorHandlers{ OnTokenTheftDetected: func(sessionHandle, userID string, req *http.Request, res http.ResponseWriter) error { @@ -270,16 +249,15 @@ func main() { return nil }, }, - //highlight-end }), }, }) } ``` - - + + -```python +```python {16,17,18} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session from supertokens_python.framework import BaseRequest, BaseResponse @@ -292,21 +270,19 @@ async def token_theft_detected_callback(req: BaseRequest, session_handle: str, u init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start error_handlers=session.InputErrorHandlers( on_token_theft_detected=token_theft_detected_callback ) - # highlight-end ) ] ) ``` - - + + --- @@ -316,10 +292,10 @@ Thrown when the access token expires or is invalid. The session refresh endpoint can also throw this if multiple access tokens are present in the request cookies. The default behavior is to send a `401` to the frontend. - - + + -```tsx +```tsx {15,16,17,18,19} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -334,21 +310,19 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - //highlight-start errorHandlers: { onTryRefreshToken: async (message, request, response, userContext) => { // TODO: Write your own logic and then send a 401 response to the frontend }, } - //highlight-end }) ] }); ``` - - + + -```go +```go {13,14,15,16,17,18} import ( "net/http" @@ -361,23 +335,21 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - //highlight-start ErrorHandlers: &sessmodels.ErrorHandlers{ OnTryRefreshToken: func(message string, req *http.Request, res http.ResponseWriter) error { // TODO: Write your own logic and then send a 401 response to the frontend return nil }, }, - //highlight-end }), }, }) } ``` - - + + -```python +```python {14,15,16} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session from supertokens_python.framework import BaseRequest, BaseResponse @@ -388,21 +360,19 @@ async def try_refresh_callback(req: BaseRequest, err: str, response: BaseRespons init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start error_handlers=session.InputErrorHandlers( on_try_refresh_token=try_refresh_callback ) - # highlight-end ) ] ) ``` - - + + --- @@ -411,10 +381,10 @@ init( Thrown when the refresh session API clears session cookies from the `olderCookieDomain` because it found multiple access tokens in the request cookies. See [this issue](https://github.com/supertokens/supertokens-node/issues/826) for more information. The default behavior is to send a 200 to the frontend. - - + + -```tsx +```tsx {15,16,17,18,19} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -429,21 +399,19 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - //highlight-start errorHandlers: { onClearDuplicateSessionCookies: async (message, request, response, userContext) => { // TODO: Write your own logic and then send a 200 response to the frontend }, } - //highlight-end }) ] }); ``` - - + + -```go +```go {13,14,15,16,17,18} import ( "net/http" @@ -456,23 +424,21 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - //highlight-start ErrorHandlers: &sessmodels.ErrorHandlers{ OnClearDuplicateSessionCookies: func(message string, req *http.Request, res http.ResponseWriter) error { // TODO: Write your own logic and then send a 200 response to the frontend return nil }, }, - //highlight-end }), }, }) } ``` - - + + -```python +```python {14,15,16} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session from supertokens_python.framework import BaseRequest, BaseResponse @@ -483,18 +449,16 @@ async def on_clear_duplication_session_cookies_callback(req: BaseRequest, err: s init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start error_handlers=session.InputErrorHandlers( on_clear_duplicate_session_cookies=on_clear_duplication_session_cookies_callback ) - # highlight-end ) ] ) ``` - - + + diff --git a/docs/post-authentication/session-management/advanced-workflows/disable-frontend-interceptors.mdx b/docs/post-authentication/session-management/advanced-workflows/disable-frontend-interceptors.mdx index d555d92d54..29b544707e 100644 --- a/docs/post-authentication/session-management/advanced-workflows/disable-frontend-interceptors.mdx +++ b/docs/post-authentication/session-management/advanced-workflows/disable-frontend-interceptors.mdx @@ -1,18 +1,10 @@ --- title: Disable frontend network interceptors -hide_title: true -sidebar_position: 6 -description: >- - Disable frontend network interceptors to manage session tokens and request - headers manually in projects. -page_type: guide -recipe: session -category: session-management +description: Disable frontend network interceptors to manage session tokens and request headers manually in projects. +sidebar: + order: 6 --- - -# Disable frontend network interceptors - ## Overview SuperTokens frontend SDKs add interceptors to networking libraries to: @@ -26,13 +18,13 @@ Whilst this helps for greenfield projects, for existing projects, you may want t ### 1. Update the frontend configuration - + - + - + - + ```tsx import Session from "supertokens-auth-react/recipe/session"; @@ -57,9 +49,9 @@ Session.init({ }) ``` - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: @@ -67,7 +59,6 @@ This change is in your auth route configuration. ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUISession.init({ override: { @@ -114,18 +105,18 @@ Session.init({ }) ``` - + - + - - + + - - + + - - + + ```tsx import Session from "supertokens-web-js/recipe/session"; @@ -150,11 +141,10 @@ Session.init({ }) ``` - - + + ```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; supertokensSession.init({ override: { functions: (oI) => { @@ -175,16 +165,16 @@ supertokensSession.init({ }) ``` - - + + - + - + - + - + You can use the `doesSessionExist` function to check if a session exists. @@ -212,40 +202,37 @@ SuperTokens.init({ }) ``` - + - + -:::note -At the moment this feature is not supported through the Android SDK. +:::note[At the moment this feature is not supported through the Android SDK.] ::: - + - + -:::note -At the moment this feature is not supported through the iOS SDK. +:::note[At the moment this feature is not supported through the iOS SDK.] ::: - + - + -:::note -At the moment this feature is not supported through the Flutter SDK. +:::note[At the moment this feature is not supported through the Flutter SDK.] ::: - + - + - + - + - + In the code above, the `shouldDoInterceptionBasedOnUrl` function is overridden to only allow interception for all API calls that start with `/auth` in their path. This ensures that API calls made from frontend SDKs (like sign out) continue to use the session tokens as expected by backend APIs. It also allows you to take control of how you want to attach session tokens to your own API calls (ones that have a path that don't start with `/auth`). -If you want to also change how session tokens attach to API calls (like sign out), you can return `false` from the function override. Then, attach custom session headers using the [pre-API hook function](/docs/references/frontend-sdks/hooks#pre-api-hook) on the frontend. +If you want to also change how session tokens attach to API calls (like sign out), you can return `false` from the function override. Then, attach custom session headers using the [pre-API hook function](/references/frontend-sdks/hooks#pre-api-hook) on the frontend. diff --git a/docs/post-authentication/session-management/advanced-workflows/in-iframe.mdx b/docs/post-authentication/session-management/advanced-workflows/in-iframe.mdx index 67f4381149..c74fdad4cc 100644 --- a/docs/post-authentication/session-management/advanced-workflows/in-iframe.mdx +++ b/docs/post-authentication/session-management/advanced-workflows/in-iframe.mdx @@ -1,18 +1,10 @@ --- title: Usage inside an iframe -hide_title: true -sidebar_position: 6 -description: >- - Embed your website in an iframe with secure session management and custom - storage handlers. -page_type: guide -recipe: session -category: session-management +description: Embed your website in an iframe with secure session management and custom storage handlers. +sidebar: + order: 6 --- - -# Usage inside an iframe - ## Overview If your website can embed in an iframe that other websites consume, update your configuration based on this guide. @@ -32,19 +24,17 @@ If the sites where your iframe can embed share the same top-level domain as the - Switch to using header based auth - Provide a custom `windowHandler` and a custom `cookieHandler` to ensure that the app works on safari and chrome incognito. These handlers switch from using `document.cookies` to `localstorage` to store tokens on the frontend (since safari doesn't allow access to `document.cookies` in iframes), and use in-memory storage for chrome incognito (since chrome incognito doesn't even allow access to `localstorage`). You can find implementations of these handlers [here (`windowHandler`)](https://github.com/SuperTokens/supertokens-auth-react/blob/master/examples/with-next-iframe/config/windowHandler.js) and [here (`cookieHandler`)](https://github.com/SuperTokens/supertokens-auth-react/blob/master/examples/with-next-iframe/config/cookieHandler.js). - + - + - + - + -```tsx +```tsx {14,15} import SuperTokens from "supertokens-auth-react"; import Session from "supertokens-auth-react/recipe/session"; -declare let cookieHandler: any // REMOVE_FROM_OUTPUT -declare let windowHandler: any // REMOVE_FROM_OUTPUT SuperTokens.init({ cookieHandler, @@ -56,28 +46,22 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-start tokenTransferMethod: "header", isInIframe: true - // highlight-end }) ] }); ``` - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: This change is in your auth route configuration. -```tsx -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; -declare let cookieHandler: any // REMOVE_FROM_OUTPUT -declare let windowHandler: any // REMOVE_FROM_OUTPUT +```tsx {12,13} supertokensUIInit({ cookieHandler, @@ -89,10 +73,8 @@ supertokensUIInit({ }, recipeList: [ supertokensUISession.init({ - // highlight-start tokenTransferMethod: "header", isInIframe: true - // highlight-end }) ] }); @@ -100,11 +82,9 @@ supertokensUIInit({ This change goes in the `supertokens-web-js` SDK configuration at the root of your application: -```tsx +```tsx {13,14} import SuperTokens from "supertokens-web-js"; import Session from "supertokens-web-js/recipe/session"; -declare let cookieHandler: any // REMOVE_FROM_OUTPUT -declare let windowHandler: any // REMOVE_FROM_OUTPUT SuperTokens.init({ cookieHandler, @@ -115,34 +95,30 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-start tokenTransferMethod: "header", isInIframe: true - // highlight-end }) ], }) ``` - + - + - + - + - - + + - - + + -```tsx +```tsx {13,14} import SuperTokens from "supertokens-web-js"; import Session from "supertokens-web-js/recipe/session"; -declare let cookieHandler: any // REMOVE_FROM_OUTPUT -declare let windowHandler: any // REMOVE_FROM_OUTPUT SuperTokens.init({ cookieHandler, @@ -153,23 +129,17 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-start tokenTransferMethod: "header", isInIframe: true - // highlight-end }) ], }) ``` - - + + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; -declare let cookieHandler: any // REMOVE_FROM_OUTPUT -declare let windowHandler: any // REMOVE_FROM_OUTPUT +```tsx {10,11} supertokens.init({ cookieHandler, windowHandler, @@ -179,32 +149,28 @@ supertokens.init({ }, recipeList: [ supertokensSession.init({ - // highlight-start tokenTransferMethod: "header", isInIframe: true - // highlight-end }) ], }) ``` - - + + - + - + -:::caution -Not applicable to mobile apps +:::warning[Not applicable to mobile apps] ::: - + - + - + -:::caution -Because of the restrictions on access to storage on Chrome incognito, you must use in-memory storage to store the tokens on the frontend. This in turn implies that if the user refreshes the page, or if your app does a full page navigation, the user logs out. +:::warning[Because of the restrictions on access to storage on Chrome incognito, you must use in-memory storage to store the tokens on the frontend. This in turn implies that if the user refreshes the page, or if your app does a full page navigation, the user logs out.] ::: diff --git a/docs/post-authentication/session-management/advanced-workflows/meta.ts b/docs/post-authentication/session-management/advanced-workflows/meta.ts new file mode 100644 index 0000000000..6e78698c78 --- /dev/null +++ b/docs/post-authentication/session-management/advanced-workflows/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Advanced Workflows", + "icon": "workflow", + "order": 5 +}); diff --git a/docs/post-authentication/session-management/advanced-workflows/multiple-api-endpoints.mdx b/docs/post-authentication/session-management/advanced-workflows/multiple-api-endpoints.mdx index 2f8381a683..4c27856c92 100644 --- a/docs/post-authentication/session-management/advanced-workflows/multiple-api-endpoints.mdx +++ b/docs/post-authentication/session-management/advanced-workflows/multiple-api-endpoints.mdx @@ -1,19 +1,10 @@ --- title: Work with multiple API endpoints -hide_title: true -sidebar_position: 5 -description: >- - Configure sessions for multiple API endpoints using cookie and header-based - authentication. -page_type: guide -recipe: session -category: session-management +description: Configure sessions for multiple API endpoints using cookie and header-based authentication. +sidebar: + order: 5 --- - -# Work with multiple API endpoints - - ## Overview To enable use of sessions for multiple API endpoints, you need to update the configuration on both the frontend and backend. @@ -29,17 +20,17 @@ If using header based auth, please skip to step 3. ### 1. Set the cookie domain in the backend configuration -:::caution no-title +:::warning This step is only applicable for cookie based authentication. ::: Set the `cookieDomain` value to be the common top level domain. For example, if your API endpoints are `{"api.example.com", "api2.example.com", "api3.example.com"}`, the common portion of these endpoints is `".example.com"` (The dot is important). You would need to set the following: - - + + -```tsx +```tsx {15} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -54,16 +45,15 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-next-line cookieDomain: ".example.com", }) ] }); ``` - - + + -```go +```go {8,13} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -71,64 +61,59 @@ import ( ) func main() { - // highlight-next-line cookieDomain := ".example.com" supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - // highlight-next-line CookieDomain: &cookieDomain, }), }, }) } ``` - - + + -```python +```python {10} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start cookie_domain='.example.com' - # highlight-end ) ] ) ``` - - + + The above sets the session cookies' domain to `example.com`, allowing them to send to `*.example.com`. -:::note -Whilst the `cookieDomain` can start with a leading `.`, the value of the `apiDomain` in `appInfo` must point to an exact API domain only. This should be the API in which you want to expose all the auth related endpoints (for example `/auth/signin`). +:::note[Whilst the `cookieDomain` can start with a leading `.`, the value of the `apiDomain` in `appInfo` must point to an exact API domain only. This should be the API in which you want to expose all the auth related endpoints (for example `/auth/signin`).] For local development, you should not set the `cookieDomain` to an IP address-based domain, or `.localhost` - browsers reject these cookies. Instead, you should [alias `localhost` to a named domain and use that](https://superuser.com/questions/152146/how-to-alias-a-hostname-on-mac-osx). ::: ### 2. Set the older cookie domain in the backend configuration -:::caution no-title +:::warning This step is only applicable for cookie based authentication. ::: To avoid locking out users with existing sessions (they get a 500 error when trying to refresh their session), set `olderCookieDomain` to match your previous `cookieDomain`. If your `cookieDomain` was not set, you can use an empty string. However, if you don't have any existing sessions, you can skip this step entirely. - - + + -```tsx +```tsx {15,16} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -143,18 +128,16 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-next-line cookieDomain: ".example.com", - // highlight-next-line olderCookieDomain: "" // Set to an empty string if your previous cookieDomain was unset. Otherwise, use your old cookieDomain value. }) ] }); ``` - - + + -```go +```go {8,14,15} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -162,49 +145,43 @@ import ( ) func main() { - // highlight-next-line cookieDomain := ".example.com" olderCookieDomain := "" // Set to an empty string if your previous cookieDomain was unset. Otherwise, use your old cookieDomain value. supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - // highlight-next-line CookieDomain: &cookieDomain, - // highlight-next-line OlderCookieDomain: &olderCookieDomain, }), }, }) } ``` - - + + -```python +```python {10,11} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start cookie_domain='.example.com', older_cookie_domain='' # Set to an empty string if your previous cookie_domain was unset. Otherwise, use your old cookie_domain value. - # highlight-end ) ] ) ``` - - + + -:::caution -- If `olderCookieDomain` isn't set, users with older sessions get a 500 error from the session refresh endpoint, locking them out. This continues until you set `olderCookieDomain` correctly or they clear their cookies. +:::warning[- If `olderCookieDomain` isn't set, users with older sessions get a 500 error from the session refresh endpoint, locking them out. This continues until you set `olderCookieDomain` correctly or they clear their cookies.] - Keep the value set for `olderCookieDomain` for 1 year because the cookie lifetime of the access token on the frontend is 1 year (even though the JWT expiry is a few hours). @@ -213,8 +190,7 @@ init( - Changing the `cookieDomain` can cause a temporary spike in requests, even if you set the `olderCookieDomain` correctly. This happens because older sessions, with older cookie domain, require additional refresh calls to clear their old cookies and set new ones. This spike is a one-time event and should not recur after the update. ::: -:::info -Set the `olderCookieDomain` value to prevent clients from having multiple session cookies from different domains. This can happen when cookies from a previous domain are still valid and sent with requests. For instance, if your previous `cookieDomain` was `api.example.com` and the new one is `.example.com`, both sets of cookies would send to the `apiDomain` `api.example.com`, leading to an inconsistent state. This can cause issues until you clear the older cookies. Setting `olderCookieDomain` in the configuration ensures that the SuperTokens SDK can automatically remove these older cookies. +:::info[Set the `olderCookieDomain` value to prevent clients from having multiple session cookies from different domains. This can happen when cookies from a previous domain are still valid and sent with requests. For instance, if your previous `cookieDomain` was `api.example.com` and the new one is `.example.com`, both sets of cookies would send to the `apiDomain` `api.example.com`, leading to an inconsistent state. This can cause issues until you clear the older cookies. Setting `olderCookieDomain` in the configuration ensures that the SuperTokens SDK can automatically remove these older cookies.] ::: ### 3. Update the frontend configuration @@ -222,15 +198,15 @@ Set the `olderCookieDomain` value to prevent clients from having multiple sessio Set the same value for `sessionTokenBackendDomain` on the frontend. This allows the frontend SDK to apply interception and automatic refreshing across all your API calls: - + - + - + - + -```tsx +```tsx {12} import SuperTokens from "supertokens-auth-react"; import Session from "supertokens-auth-react/recipe/session"; @@ -242,23 +218,20 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-next-line sessionTokenBackendDomain: ".example.com" }) ] }); ``` - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: This change is in your auth route configuration. -```tsx -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; +```tsx {10} supertokensUIInit({ appInfo: { @@ -268,7 +241,6 @@ supertokensUIInit({ }, recipeList: [ supertokensUISession.init({ - // highlight-next-line sessionTokenBackendDomain: ".example.com" }) ] @@ -294,19 +266,19 @@ SuperTokens.init({ }); ``` - + - + - + - + - - + + - - + + ```tsx import SuperTokens from 'supertokens-web-js'; @@ -325,12 +297,10 @@ SuperTokens.init({ }); ``` - - + + ```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; supertokens.init({ appInfo: { apiDomain: "...", @@ -344,16 +314,16 @@ supertokens.init({ }); ``` - - + + - + - + - + - + ```tsx import SuperTokens from 'supertokens-react-native'; @@ -364,11 +334,11 @@ SuperTokens.init({ }); ``` - + - + -```kotlin +```kotlin {9} import android.app.Application import com.supertokens.session.SuperTokens @@ -377,18 +347,17 @@ class MainApplication: Application() { super.onCreate() SuperTokens.Builder(this, "...") - // highlight-next-line .sessionTokenBackendDomain(".example.com") .build() } } ``` - + - + -```swift +```swift {10} import UIKit import SuperTokensIOS @@ -398,7 +367,6 @@ fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { do { try SuperTokens.initialize( apiDomain: "...", - // highlight-next-line sessionTokenBackendDomain: ".example.com" ) } catch SuperTokensError.initError(let message) { @@ -413,9 +381,9 @@ fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -428,12 +396,12 @@ void initialiseSuperTokens() { } ``` - + - + - + - + - + diff --git a/docs/post-authentication/session-management/advanced-workflows/user-impersonation.mdx b/docs/post-authentication/session-management/advanced-workflows/user-impersonation.mdx index e2510465c6..2ac3ba80db 100644 --- a/docs/post-authentication/session-management/advanced-workflows/user-impersonation.mdx +++ b/docs/post-authentication/session-management/advanced-workflows/user-impersonation.mdx @@ -1,19 +1,10 @@ --- title: Implement user impersonation -hide_title: true -sidebar_position: 2 -description: >- - Enable user impersonation for testing and support by creating an - admin-protected API endpoint. -page_type: guide -recipe: session -category: session-management +description: Enable user impersonation for testing and support by creating an admin-protected API endpoint. +sidebar: + order: 2 --- - - -# Implement user impersonation - ## Overview Impersonating a user allows you to login as them without using their credentials. @@ -23,8 +14,7 @@ This guide shows you how to achieve this by only allowing a certain type of user ## Before you start -:::caution -Since this feature allows you to login as any user in your application, only admins or custom support staff should use it. +:::warning[Since this feature allows you to login as any user in your application, only admins or custom support staff should use it.] You can use any method to protect this API. (API Key, specific user roles, IP address validation, etc.) ::: @@ -35,12 +25,12 @@ You can use any method to protect this API. (API Key, specific user roles, IP ad Create a new API endpoint that accepts some form of identifier (email, phone number, user ID, etc.) and creates a new impersonation session for that user. -In order for this to work, admins need to first log in to the application as themselves. Once they create their session (like any regular user's session), they can call the API via a frontend UI that's only shown to them. You can detect the admin role on the frontend by seeing [this guide](/docs/additional-verification/user-roles/protecting-routes#protecting-frontend-routes). +In order for this to work, admins need to first log in to the application as themselves. Once they create their session (like any regular user's session), they can call the API via a frontend UI that's only shown to them. You can detect the admin role on the frontend by seeing [this guide](/additional-verification/user-roles/protecting-routes#protecting-frontend-routes). - - - - + + + + ```tsx import express from "express"; @@ -79,8 +69,8 @@ app.post( }) ``` - - + + ```tsx import Hapi from "@hapi/hapi"; @@ -126,8 +116,8 @@ server.route({ }, }); ``` - - + + ```tsx import Fastify from "fastify"; @@ -168,8 +158,8 @@ fastify.post( }) ``` - - + + ```tsx import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; @@ -208,8 +198,8 @@ exports.handler = verifySession(impersonate, { }); ``` - - + + ```tsx import KoaRouter from "koa-router"; @@ -247,8 +237,8 @@ router.post( }) ``` - - + + ```tsx import { inject, intercept } from "@loopback/core"; @@ -287,12 +277,12 @@ class Login { } ``` - - + + + - - + @@ -352,7 +342,6 @@ import SuperTokens from "supertokens-node"; import { withPreParsedRequestResponse } from "supertokens-node/nextjs"; import { CollectingResponse, PreParsedRequest } from "supertokens-node/framework/custom"; import { createNewSession } from "supertokens-node/recipe/session"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -380,13 +369,12 @@ export function POST(req: NextRequest) { - - + + ```ts import { Controller, Post, Res, Req, UseGuards } from "@nestjs/common"; import type { Response, Request } from "express"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; import { createNewSession, SessionContainer, SessionClaimValidator } from "supertokens-node/recipe/session"; import supertokens from "supertokens-node"; @@ -422,10 +410,10 @@ export class ExampleController { } ``` - - - - + + + + ```go import ( @@ -481,11 +469,11 @@ func impersonate(w http.ResponseWriter, r *http.Request) { } ``` - - + + - - + + ```python from fastapi import Depends, Request @@ -499,7 +487,7 @@ from supertokens_python.recipe.userroles import UserRoleClaim from supertokens_python.types.base import AccountInfoInput -@app.post("/impersonate") # type: ignore +@app.post("/impersonate") async def impersonate( request: Request, session: SessionContainer = Depends( @@ -532,8 +520,8 @@ async def impersonate( ``` - - + + ```python from flask import jsonify @@ -546,7 +534,7 @@ from supertokens_python.syncio import list_users_by_account_info from supertokens_python.types.base import AccountInfoInput -@app.route("/impersonate", methods=["POST"]) # type: ignore +@app.route("/impersonate", methods=["POST"]) @verify_session( # We add the UserRoleClaim's includes validator override_global_claim_validators=lambda global_validators, @@ -574,8 +562,8 @@ def login(request: Request): ``` - - + + ```python from django.http import HttpRequest, JsonResponse @@ -614,12 +602,12 @@ async def impersonate(request: HttpRequest): ``` - - - - + + + + -:::info Multi Tenancy +:::info[Multi Tenancy] Notice that the `"public"` `tenantId` goes to the function call above. This is the default `tenantId` in SuperTokens. If you are using the multi-tenancy feature and want to login into a different tenant, you can replace `"public"` with the `tenantId` you want to login into. You can fetch this `tenantId` based on the admin user's tenant (from their session), or you can pass it in the request body. diff --git a/docs/post-authentication/session-management/introduction.mdx b/docs/post-authentication/session-management/introduction.mdx index 7280af3613..00c98fda42 100644 --- a/docs/post-authentication/session-management/introduction.mdx +++ b/docs/post-authentication/session-management/introduction.mdx @@ -1,26 +1,17 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -skip_llms_txt: true -description: >- - Learn about SuperTokens' session management and how to handle session security - and flow. -page_type: overview -recipe: session -category: session-management +description: Learn about SuperTokens' session management and how to handle session security and flow. +sidebar: + order: 1 --- - -# Session management - ## Overview SuperTokens provides session management out of the box. Sessions get created when a user signs in and maintained throughout the authentication lifecycle. In the next graphic you can see a high level overview of how the session flow works. -Flowcharts showing an overview of session flow +Flowcharts showing an overview of session flow - After sign in, the system creates a new session by issuing a refresh and access token to the frontend. - The frontend sends the access token for each API call that requires session authentication. @@ -44,88 +35,42 @@ In the next graphic you can see a high level overview of how the session flow wo ## Getting started Including the `Session` recipe in the initial configuration enables sessions. -This step is outlined in all the guides that show you how to integrate different authentication methods: [Email Password](/docs/authentication/email-password/introduction), [Passwordless](/docs/authentication/passwordless/introduction) or [Social Login](/docs/authentication/social/introduction). +This step is outlined in all the guides that show you how to integrate different authentication methods: [Email Password](/authentication/email-password/introduction), [Passwordless](/authentication/passwordless/introduction) or [Social Login](/authentication/social/introduction). Additionally, this section includes information on how to work with sessions after a user has signed in. - - - - Access Session Data - - - See how you can read the properties of an active session. - - - - - Invalidate Sessions - - - Learn how to revoke a session either through a user action or programmatically. - - - + + +See how you can read the properties of an active session. + + +Learn how to revoke a session either through a user action or programmatically. + + ## Customization - - - - - Share sessions across subdomains - - - Update the configuration to share sessions across different subdomains. - - - - - Switch between cookie and header based authentication - - - Choose how tokens are sent and stored during the authentication lifecycle. - - - - - Implement anonymous sessions - - - Learn how to track session data event if a user has not logged in. - - - - - Implement user impersonation - - - See how to act as a different user during the authentication flow. - - - - - Customize error handling - - - Change the default error handling behaviour. - - - - - Work with multiple API endpoints - - - Use the same session management logic for multiple API endpoints. - - - - - Blacklist Access Tokens - - - Block access tokens from being used. - - - + + +Update the configuration to share sessions across different subdomains. + + +Choose how tokens are sent and stored during the authentication lifecycle. + + +Learn how to track session data event if a user has not logged in. + + +See how to act as a different user during the authentication flow. + + +Change the default error handling behaviour. + + +Use the same session management logic for multiple API endpoints. + + +Block access tokens from being used. + + diff --git a/docs/post-authentication/session-management/meta.ts b/docs/post-authentication/session-management/meta.ts new file mode 100644 index 0000000000..4ab828bc53 --- /dev/null +++ b/docs/post-authentication/session-management/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Session Management", + "icon": "id-card", + "order": 1.1 +}); diff --git a/docs/post-authentication/session-management/security.mdx b/docs/post-authentication/session-management/security.mdx index 292615bea1..554cdc1b43 100644 --- a/docs/post-authentication/session-management/security.mdx +++ b/docs/post-authentication/session-management/security.mdx @@ -1,19 +1,10 @@ --- title: Security -hide_title: true -sidebar_position: 5 -description: >- - Learn how to protect your website from CSRF attacks using the `sameSite` - cookie attribute. -page_type: guide -recipe: session -category: session-management +description: Learn how to protect your website from CSRF attacks using the `sameSite` cookie attribute. +sidebar: + order: 5 --- - - -# Session security - ## Overview The following page takes you through some common security considerations that the **SuperTokens** `Session` recipe handles. @@ -32,8 +23,7 @@ If a user visits a malicious site, requests from those sites do not have the ses ### Configure anti-csrf -:::caution -- SuperTokens automatically defends against CSRF attacks. +:::warning[- SuperTokens automatically defends against CSRF attacks.] - Please only change this setting if you know what you are doing. If you are unsure, please feel free to [ask questions](https://supertokens.com/discord). - This setting does not apply while using header-based authentication, since they get the same protection as `antiCsrf` set to `VIA_CUSTOM_HEADER`. ::: @@ -49,10 +39,10 @@ This sets automatically if `sameSite` is `none` or if your `apiDomain` and `webs Use this method if you want to allow any origin to query your APIs. This method may cause issues in browsers like Safari, especially if your site embeds as an `iframe`. - - + + -```tsx +```tsx {15} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -67,16 +57,15 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-next-line antiCsrf: "VIA_CUSTOM_HEADER", // Should be one of "NONE" or "VIA_CUSTOM_HEADER" or "VIA_TOKEN" }) ] }); ``` - - + + -```go +```go {8,9,14} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -84,44 +73,39 @@ import ( ) func main() { - // highlight-start // Should be one of "NONE" or "VIA_CUSTOM_HEADER" or "VIA_TOKEN" antiCsrf := "VIA_CUSTOM_HEADER" - // highlight-end supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - // highlight-next-line AntiCsrf: &antiCsrf, }), }, }) } ``` - - + + -```python +```python {9,10} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start # Should be one of "NONE" or "VIA_CUSTOM_HEADER" or "VIA_TOKEN" anti_csrf='VIA_CUSTOM_HEADER' - # highlight-end ) ] ) ``` - - + + --- @@ -129,7 +113,7 @@ init( [Per GDPR](https://gdpr.eu/cookies/), users do not need to give consent for your application to use session cookies. This is because they fall under essential cookies and not tracking cookies: -:::info Important +:::info[Important] "While it is not required to obtain consent for these cookies, explain to the user what they do and why they are necessary." ::: @@ -142,7 +126,7 @@ The ``sameSite`` cookie attribute declares if your cookies should restrict to a The ``sameSite`` attribute can have three possible values: - ``none`` - Cookies attach in all contexts, that is, cookies attach to both first-party and cross-origin requests. - - On Safari however, if third-party cookies do not work (which is the default behavior), and the website and `API` domains do not share the same top-level domain, then cookies do not go. Please check [the session management page](/docs/post-authentication/session-management/switch-between-cookies-and-header-authentication) to see how you can switch to using headers. + - On Safari however, if third-party cookies do not work (which is the default behavior), and the website and `API` domains do not share the same top-level domain, then cookies do not go. Please check [the session management page](/post-authentication/session-management/switch-between-cookies-and-header-authentication) to see how you can switch to using headers. - ``lax`` - Cookies are only sent in a first-party context and along with `GET` requests initiated by third party websites (that result in browser navigation - user clicking on a link). - ``strict`` @@ -150,15 +134,14 @@ The ``sameSite`` attribute can have three possible values: ### Configuration -:::caution -- SuperTokens automatically sets the value of the ``sameSite`` cookie attribute based on your website and `API` domain configuration. +:::warning[- SuperTokens automatically sets the value of the ``sameSite`` cookie attribute based on your website and `API` domain configuration.] - Please only change this setting if you are a web security expert. If you are unsure, please feel free to [ask questions](https://supertokens.com/discord). ::: - - + + -```tsx +```tsx {15} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -173,17 +156,16 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-next-line cookieSameSite: "strict", // Should be one of "strict" or "lax" or "none" }), ], }); ``` - - + + -```go +```go {8,9,14} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -191,15 +173,12 @@ import ( ) func main() { - // highlight-start // Should be one of "strict" or "lax" or "none" cookieSameSite := "lax" - // highlight-end supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - // highlight-next-line CookieSameSite: &cookieSameSite, }), }, @@ -207,29 +186,27 @@ func main() { } ``` - - + + -```python +```python {10} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start cookie_same_site='lax' # Should be one of 'strict' or 'lax' or 'none' - # highlight-end ) ] ) ``` - - + + --- @@ -242,14 +219,13 @@ This, in turn, prevents cookie theft via man in the middle attacks. You can explicitly set the security level of cookies using the next snippet: -:::important -If not explicitly set, SuperTokens automatically determines the value for the `secure` attribute based on your API domain having `http` or `https`. +:::note[If not explicitly set, SuperTokens automatically determines the value for the `secure` attribute based on your API domain having `http` or `https`.] ::: - - + + -```tsx +```tsx {15} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -264,16 +240,15 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - //highlight-next-line cookieSecure: true, }) ] }); ``` - - + + -```go +```go {8,13} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -281,41 +256,37 @@ import ( ) func main() { - // highlight-next-line cookieSecure := true supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - // highlight-next-line CookieSecure: &cookieSecure, }), }, }) } ``` - - + + -```python +```python {9} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start cookie_secure=True - # highlight-end ) ] ) ``` - - + + --- @@ -324,29 +295,26 @@ init( Access Token signing key rotation implies that the secret key for signing the access tokens changes at a fixed time interval. This reduces the risk of key theft. -:::info -- Existing logged in users are not logged out on key change. +:::info[- Existing logged in users are not logged out on key change.] - This feature enables by default. ::: ### Change the key rotation interval - - + + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-start -e ACCESS_TOKEN_DYNAMIC_SIGNING_KEY_UPDATE_INTERVAL=168 \ - // highlight-end -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -355,25 +323,24 @@ docker run \ access_token_dynamic_signing_key_update_interval: 168 ``` - - + + - ``access_token_dynamic_signing_key_update_interval`` - Time in hours for how frequently the signing key changes. - It must have a ``number`` value with, the default value set to ``168`` -:::info -For managed service, update this value in the **Session Management** configuration card in the relevant deployment's **Configuration** page. +:::info[For managed service, update this value in the **Session Management** configuration card in the relevant deployment's **Configuration** page.] ::: ### Use static keys -If you do not want to use dynamic keys for session creation, then you can tell SuperTokens to use the static key instead. This is useful in cases where you want to [hard-code the public key for JWT verification in some process](/docs/additional-verification/session-verification/protect-api-routes#with-the-public-key-string). +If you do not want to use dynamic keys for session creation, then you can tell SuperTokens to use the static key instead. This is useful in cases where you want to [hard-code the public key for JWT verification in some process](/additional-verification/session-verification/protect-api-routes#with-the-public-key-string). - - + + -```tsx +```tsx {15} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -388,21 +355,19 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - //highlight-next-line useDynamicAccessTokenSigningKey: false, }) ] }); ``` -:::caution -Updating this value causes a spike in the session refresh API, as and when users visit your application. +:::warning[Updating this value causes a spike in the session refresh API, as and when users visit your application.] ::: - - + + -```go +```go {8,13} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -410,13 +375,11 @@ import ( ) func main() { - // highlight-next-line useDynamicAccessTokenSigningKey := false supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - // highlight-next-line UseDynamicAccessTokenSigningKey: &useDynamicAccessTokenSigningKey, }), }, @@ -424,45 +387,41 @@ func main() { } ``` -:::caution -Updating this value causes a spike in the session refresh API, as and when users visit your application. +:::warning[Updating this value causes a spike in the session refresh API, as and when users visit your application.] ::: - - + + -```python +```python {9} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start use_dynamic_access_token_signing_key=False - # highlight-end ) ] ) ``` -:::caution -Updating this value causes a spike in the session refresh API, as and when users visit your application. +:::warning[Updating this value causes a spike in the session refresh API, as and when users visit your application.] ::: - - + + --- ## See also - - - - - - - + + + + + + + diff --git a/docs/post-authentication/session-management/session-invalidation.mdx b/docs/post-authentication/session-management/session-invalidation.mdx index f82d4cad61..c4c389477f 100644 --- a/docs/post-authentication/session-management/session-invalidation.mdx +++ b/docs/post-authentication/session-management/session-invalidation.mdx @@ -1,20 +1,12 @@ --- title: Session Invalidation -hide_title: true -sidebar_position: 3 -toc_max_heading_level: 4 description: >- - Learn how to handle session expiry, implement sign out, and revoke sessions - across different programming languages and frameworks. -page_type: guide -recipe: session -category: session-management + Learn how to handle session expiry, implement sign out, and revoke sessions across different programming languages and + frameworks. +sidebar: + order: 3 --- - - -# Session invalidation - ## Overview You can invalidate a session in **SuperTokens** in different ways. @@ -24,7 +16,7 @@ This guide shows you how to implement each of these. ## Before you start - +:::info[Access token guidance] --- @@ -35,134 +27,123 @@ You need to add your own UI element for this since the library does not expose a The `signOut` function calls the sign out API exposed by the session recipe on the backend and, in turn, revokes all the user active sessions. If you call the `signOut` function whilst the access token has expired, but the refresh token still exists, the SDKs automatically perform a session refresh before revoking the session. -:::important -You have to add your own redirection logic after the sign out call completes. +:::note[You have to add your own redirection logic after the sign out call completes.] ::: - + - + - - + + -```tsx +```tsx {2,6,12} import React from "react"; -// highlight-next-line import { signOut } from "supertokens-auth-react/recipe/session"; function NavBar() { async function onLogout() { - // highlight-next-line await signOut(); window.location.href = "/auth"; // or redirect to wherever the login page is } return (
  • Home
  • - // highlight-next-line
  • Logout
) } ``` -
+ - + -```tsx -// highlight-next-line +```tsx {1,4} import Session from "supertokens-web-js/recipe/session"; async function logout () { - // highlight-next-line await Session.signOut(); window.location.href = "/auth"; // or redirect to wherever the login page is } ``` - + -
+ -
+ - + - - + + - - + + -```tsx +```tsx {4} import Session from "supertokens-web-js/recipe/session"; async function logout () { - // highlight-next-line await Session.signOut(); window.location.href = "/auth"; // or redirect to wherever the login page is } ``` - - + + -```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; +```tsx {2} async function logout () { - // highlight-next-line await supertokensSession.signOut(); window.location.href = "/auth"; // or redirect to wherever the login page is } ``` - - + + - + - + - + - + -```tsx +```tsx {4} import SuperTokens from "supertokens-react-native"; async function logout () { - // highlight-next-line await SuperTokens.signOut(); // navigate to the login screen.. } ``` - + - + -```kotlin +```kotlin {6} import android.app.Application import com.supertokens.session.SuperTokens class MainApplication: Application() { fun logout() { - // highlight-next-line SuperTokens.signOut(this); // navigate to the login screen.. } } ``` - + - + ```swift import UIKit @@ -183,9 +164,9 @@ fileprivate class ViewController: UIViewController { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -199,47 +180,45 @@ Future signOut() async { } ``` - + - + - + - + - + ### Expose a backend sign out method If you do not want to use the frontend function you can expose a backend sign out method. - - + + - - + + -```tsx +```tsx {7,8,9,10} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; let app = express(); -// highlight-start app.post("/someapi", verifySession(), async (req: SessionRequest, res) => { // This will delete the session from the db and from the frontend (cookies) await req.session!.revokeSession(); - // highlight-end res.send("Success! User session revoked"); }); ``` - - + + -```tsx +```tsx {10,11,12,13,14,15,16,17,18,19} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import { SessionRequest } from "supertokens-node/framework/hapi"; @@ -249,7 +228,6 @@ let server = Hapi.server({ port: 8000 }); server.route({ path: "/someapi", method: "post", - //highlight-start options: { pre: [ { @@ -260,45 +238,40 @@ server.route({ handler: async (req: SessionRequest, res) => { // This will delete the session from the db and from the frontend (cookies) await req.session!.revokeSession(); - // highlight-end return res.response("Success! User session revoked").code(200); } }) ``` - - + + -```tsx +```tsx {7,8,9,10,11} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import { SessionRequest } from "supertokens-node/framework/fastify"; let fastify = Fastify(); -//highlight-start fastify.post("/someapi", { preHandler: verifySession(), }, async (req: SessionRequest, res) => { // This will delete the session from the db and from the frontend (cookies) await req.session!.revokeSession(); - // highlight-end res.send("Success! User session revoked"); }); ``` - - + + -```tsx +```tsx {4,5,6} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; -// highlight-start async function someapi(awsEvent: SessionEvent) { // This will delete the session from the db and from the frontend (cookies) await awsEvent.session!.revokeSession(); - // highlight-end return { body: JSON.stringify({ message: "Success! User session revoked" }), @@ -309,37 +282,34 @@ async function someapi(awsEvent: SessionEvent) { exports.handler = verifySession(someapi); ``` - - + + -```tsx +```tsx {7,8,9} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from 'supertokens-node/framework/koa'; let router = new KoaRouter(); -//highlight-start router.post("/someapi", verifySession(), async (ctx: SessionContext, next) => { // This will delete the session from the db and from the frontend (cookies) await ctx.session!.revokeSession(); - // highlight-end ctx.body = "Success! User session revoked"; }); ``` - - + + -```tsx +```tsx {7,8,9,10,11,12,13} import { inject, intercept } from "@loopback/core"; import { RestBindings, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; import { SessionContext } from "supertokens-node/framework/loopback"; class Logout { - //highlight-start constructor(@inject(RestBindings.Http.CONTEXT) private ctx: SessionContext) { } @post("/someapi") @intercept(verifySession()) @@ -347,33 +317,30 @@ class Logout { async handler() { // This will delete the session from the db and from the frontend (cookies) await this.ctx.session!.revokeSession(); - // highlight-end return "Success! User session revoked"; } } ``` - - + + + - - + -```tsx +```tsx {5,6,7,8,9,10,11,12,13,14} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; -// highlight-start export default async function someapi(req: SessionRequest, res: any) { await superTokensNextWrapper( async (next) => { - // highlight-next-line await verifySession()(req, res, next); }, req, @@ -381,7 +348,6 @@ export default async function someapi(req: SessionRequest, res: any) { ) // This will delete the session from the db and from the frontend (cookies) await req.session!.revokeSession(); - // highlight-end res.send("Success! User session revoked"); } ``` @@ -394,7 +360,6 @@ export default async function someapi(req: SessionRequest, res: any) { import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -413,14 +378,13 @@ export function POST(request: NextRequest) { - + - + ```ts import { Controller, Post, UseGuards, Request, Response, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; @Controller() @@ -435,10 +399,10 @@ export class ExampleController { } } ``` - - - - + + + + ```go import ( @@ -466,48 +430,44 @@ func someAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + - - + + -```python +```python {6,7} from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.session import SessionContainer from fastapi import Depends from fastapi.responses import PlainTextResponse -# highlight-start async def some_api(session: SessionContainer = Depends(verify_session())): await session.revoke_session() # This will delete the session from the db and from the frontend (cookies) - # highlight-end return PlainTextResponse(content='success') ``` - - + + -```python +```python {5,6,7,8,9,10} from supertokens_python.recipe.session.framework.flask import verify_session from supertokens_python.recipe.session import SessionContainer from flask import g -# highlight-start -@app.route('/some_api', methods=['POST']) # type: ignore +@app.route('/some_api', methods=['POST']) @verify_session() def some_api(): - session: SessionContainer = g.supertokens # type: ignore + session: SessionContainer = g.supertokens session.sync_revoke_session() # This will delete the session from the db and from the frontend (cookies) - # highlight-end return 'success' ``` - - + + -```python +```python {9,10,11} from typing import cast from django.http import HttpRequest @@ -516,21 +476,19 @@ from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.django.asyncio import verify_session -# highlight-start @verify_session() async def some_api(request: HttpRequest): - session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore This will delete the session from the db and from the frontend (cookies) - # highlight-end + session: SessionContainer = cast(SessionContainer, request.supertokens) This will delete the session from the db and from the frontend (cookies) await session.revoke_session() ``` - - + + - - + + -:::info Tip +:::info[Tip] If you are using the pre-built UI, and the `` component set custom post log out logic with the `onSessionExpired` prop. The handler gets called if: @@ -540,7 +498,6 @@ The handler gets called if: ```tsx import React from "react"; import { SessionAuth } from "supertokens-auth-react/recipe/session"; -// @ts-ignore import MyComponent from "./myComponent"; const App = () => { @@ -560,16 +517,15 @@ const App = () => { To invalidate a session without relying on the intervention of a user you can create your own custom methods using the backend SDKs. -:::caution -This method of revoking a session only deletes the session from the database and not from the frontend. +:::warning[This method of revoking a session only deletes the session from the database and not from the frontend.] This implies that the user can still access protected endpoints while their access token is alive. -If you want to instantly logout the user in this mode, you should [enable access token blacklisting](/docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting). +If you want to instantly logout the user in this mode, you should [enable access token blacklisting](/post-authentication/session-management/advanced-workflows/access-token-blacklisting). ::: ### Revoke a specific session - - + + ```tsx import Session from "supertokens-node/recipe/session"; @@ -578,15 +534,14 @@ async function revokeSession(sessionHandle: string) { let revoked = await Session.revokeSession(sessionHandle); }; ``` - - + + -```go +```go {5} import "github.com/supertokens/supertokens-golang/recipe/session" func main() { sessionHandle := "someSessionHandle" - // highlight-next-line revoked, err := session.RevokeSession(sessionHandle) if err != nil { // TODO: Handle error @@ -601,45 +556,43 @@ func main() { } ``` - - - + + + - + -```python +```python {5} from supertokens_python.recipe.session.asyncio import revoke_session async def some_func(): session_handle = "someSessionHandle" - # highlight-next-line _ = await revoke_session(session_handle) ``` - - + + -```python +```python {4} from supertokens_python.recipe.session.syncio import revoke_session session_handle = "someSessionHandle" -# highlight-next-line revoked = revoke_session(session_handle) ``` - - - - + + + + -You can fetch all the `sessionHandle`s for a user using the [`getAllSessionHandlesForUser` function](/docs/post-authentication/session-management/access-session-data#fetch-all-user-sessions) +You can fetch all the `sessionHandle`s for a user using the [`getAllSessionHandlesForUser` function](/post-authentication/session-management/access-session-data#fetch-all-user-sessions) ### Revoke all sessions for a user - - + + -```tsx +```tsx {9} import express from "express"; import Session from "supertokens-node/recipe/session"; @@ -648,16 +601,15 @@ let app = express(); app.use("/revoke-all-user-sessions", async (req, res) => { let userId = req.body.userId - // highlight-next-line await Session.revokeAllSessionsForUser(userId); res.send("Success! All user sessions have been revoked"); }); ``` - - + + -```go +```go {8} import ( "fmt" @@ -665,7 +617,6 @@ import ( ) func main() { - // highlight-next-line tenantId := "public" revokedSessionHandles, err := session.RevokeAllSessionsForUser("userId", &tenantId) if err != nil { @@ -678,44 +629,42 @@ func main() { } ``` - - + + - + - + -```python +```python {5} from supertokens_python.recipe.session.asyncio import revoke_all_sessions_for_user async def some_func(): user_id = "someUserId" - # highlight-next-line revoked_session_handles = await revoke_all_sessions_for_user(user_id) print(revoked_session_handles) # revoked_session_handles is an array of revoked session handles. ``` - - + + -```python +```python {4} from supertokens_python.recipe.session.syncio import revoke_all_sessions_for_user user_id = "someUserId" -# highlight-next-line revoked_session_handles = revoke_all_sessions_for_user(user_id) # revoked_session_handles is an array of revoked session handles. ``` - - + + - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] By default, revokeAllSessionsForUser deletes all the sessions for the user across all the tenants. If you want to delete the sessions for a user in a specific tenant, you can pass the tenant ID as a parameter to the function call. ::: @@ -723,11 +672,10 @@ By default, revokeAllSessionsForUser deletes all the sessions for the user acros ## See also - - - - - - - - + + + + + + + diff --git a/docs/post-authentication/session-management/share-session-across-sub-domains.mdx b/docs/post-authentication/session-management/share-session-across-sub-domains.mdx index b2dfc39020..e37211c552 100644 --- a/docs/post-authentication/session-management/share-session-across-sub-domains.mdx +++ b/docs/post-authentication/session-management/share-session-across-sub-domains.mdx @@ -1,22 +1,15 @@ --- title: Share sessions across sub domains -hide_title: true -sidebar_position: 3 description: Configure SuperTokens to share sessions across multiple subdomains. -page_type: guide -recipe: session -category: session-management +sidebar: + order: 3 --- - -# Share sessions across subdomains - - ## Overview Configure sharing sessions across multiple subdomains in SuperTokens by setting the `sessionTokenFrontendDomain` attribute of the Session recipe in your frontend code. -:::info Example +:::info[Example] - Your app has two subdomains `abc.example.com` and `xyz.example.com`. Assume that the user logs in via `example.com` - To enable sharing sessions across `example.com`, `abc.example.com` and `xyz.example.com`, set the `sessionTokenFrontendDomain` attribute to `.example.com`. ::: @@ -27,15 +20,15 @@ Configure sharing sessions across multiple subdomains in SuperTokens by setting ### 1. Update the frontend configuration - + - + - + - + -```tsx +```tsx {14} import SuperTokens from "supertokens-auth-react"; import Session from "supertokens-auth-react/recipe/session"; @@ -49,24 +42,21 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-next-line sessionTokenFrontendDomain: ".example.com" }) ] }); ``` - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: This change is in your auth route configuration. -```tsx -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; +```tsx {12} supertokensUIInit({ appInfo: { @@ -78,7 +68,6 @@ supertokensUIInit({ }, recipeList: [ supertokensUISession.init({ - // highlight-next-line sessionTokenFrontendDomain: ".example.com" }) ] @@ -87,7 +76,7 @@ supertokensUIInit({ This change goes in the `supertokens-web-js` SDK configuration at the root of your application: -```tsx +```tsx {11} import SuperTokens from "supertokens-web-js"; import Session from "supertokens-web-js/recipe/session"; @@ -98,24 +87,22 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-start sessionTokenFrontendDomain: ".example.com" - // highlight-end }), ], }) ``` - + - + -:::caution +:::warning - Do not set `sessionTokenFrontendDomain` to a value that's in the [public suffix list](https://publicsuffix.org/list/public_suffix_list.dat) (Search for your value without the leading dot). Otherwise, session management does not work. - Do not set `sessionTokenFrontendDomain` to `.localhost` or an IP address based domain with a leading `.` since browsers reject these cookies. For local development, you should configure [your machine to use alias for `localhost`](https://superuser.com/questions/152146/how-to-alias-a-hostname-on-mac-osx). ::: -:::info Multi Tenancy +:::info[Multi Tenancy] If each tenant belongs to one subdomain, and a user has access to more than one tenant, the tenant ID in the session is always the one from which they logged in. @@ -125,17 +112,17 @@ To solve this, add extra information about access token payload containing a lis ::: - + - + - - + + - - + + -```tsx +```tsx {11} import SuperTokens from "supertokens-web-js"; import Session from "supertokens-web-js/recipe/session"; @@ -146,20 +133,16 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-start sessionTokenFrontendDomain: ".example.com" - // highlight-end }), ], }) ``` - - + + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; +```tsx {9} supertokens.init({ appInfo: { apiDomain: "...", @@ -168,23 +151,21 @@ supertokens.init({ recipeList: [ supertokensSession.init({ // ... - // highlight-start sessionTokenFrontendDomain: ".example.com" - // highlight-end }) ], }) ``` - - + + -:::caution +:::warning - Do not set `sessionTokenFrontendDomain` to a value that's in the [public suffix list](https://publicsuffix.org/list/public_suffix_list.dat) (Search for your value without the leading dot). Otherwise, session management does not work. - Do not set `sessionTokenFrontendDomain` to `.localhost` or an IP address based domain with a leading `.` since browsers reject these cookies. For local development, you should configure [your machine to use alias for `localhost`](https://superuser.com/questions/152146/how-to-alias-a-hostname-on-mac-osx). ::: -:::info Multi Tenancy +:::info[Multi Tenancy] If each tenant belongs to one subdomain, and a user has access to more than one tenant, the tenant ID in the session is always the one from which they logged in. @@ -194,30 +175,29 @@ To solve this, add extra information about access token payload containing a lis ::: - + - + -:::caution -Not applicable +:::warning[Not applicable] ::: - + - + - + --- ## See also - - - - - - - - + + + + + + + + diff --git a/docs/post-authentication/session-management/switch-between-cookies-and-header-authentication.mdx b/docs/post-authentication/session-management/switch-between-cookies-and-header-authentication.mdx index 638ae94310..fe131cf847 100644 --- a/docs/post-authentication/session-management/switch-between-cookies-and-header-authentication.mdx +++ b/docs/post-authentication/session-management/switch-between-cookies-and-header-authentication.mdx @@ -1,19 +1,10 @@ --- title: Switch between cookie and header-based sessions -hide_title: true -sidebar_position: 4 -description: >- - Switch between cookie and header-based sessions for secure token management in - SuperTokens. -page_type: guide -recipe: session -category: session-management +description: Switch between cookie and header-based sessions for secure token management in SuperTokens. +sidebar: + order: 4 --- - -# Switch between cookie and header-based sessions - - ## Overview SuperTokens supports 2 methods of authorizing requests. @@ -35,8 +26,7 @@ The backend controls this choice, but it follows a preference set in the fronten ## Before you start -:::caution -We recommend cookie-based sessions in browsers because header-based sessions require saving the access and refresh tokens in storage vulnerable to XSS attacks. +:::warning[We recommend cookie-based sessions in browsers because header-based sessions require saving the access and refresh tokens in storage vulnerable to XSS attacks.] ::: ## Steps @@ -46,15 +36,15 @@ We recommend cookie-based sessions in browsers because header-based sessions req You can provide a `tokenTransferMethod` property in the configuration of the Session recipe to set the preferred token transfer method. The backend receives this method with every request in the `st-auth-mode` header. By default, the backend follows this preference. - + - + - + - + -```tsx +```tsx {12} import SuperTokens from "supertokens-auth-react"; import Session from "supertokens-auth-react/recipe/session"; @@ -66,25 +56,22 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-next-line tokenTransferMethod: "header" // or "cookie" }) ] }); ``` - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: This change is in your auth route configuration. -```tsx +```tsx {11} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -94,7 +81,6 @@ supertokensUIInit({ }, recipeList: [ supertokensUISession.init({ - // highlight-next-line tokenTransferMethod: "header" // or "cookie" }) ] @@ -103,7 +89,7 @@ supertokensUIInit({ This change goes in the `supertokens-web-js` SDK configuration at the root of your application: -```tsx +```tsx {11} import SuperTokens from "supertokens-web-js"; import Session from "supertokens-web-js/recipe/session"; @@ -114,28 +100,27 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-next-line tokenTransferMethod: "header" // or "cookie" }) ], }) ``` - + - + - + - + - - + + - - + + -```tsx +```tsx {11} import SuperTokens from "supertokens-web-js"; import Session from "supertokens-web-js/recipe/session"; @@ -146,19 +131,16 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-next-line tokenTransferMethod: "header" // or "cookie" }) ], }) ``` - - + + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; +```tsx {8} supertokens.init({ appInfo: { apiDomain: "...", @@ -166,23 +148,22 @@ supertokens.init({ }, recipeList: [ supertokensSession.init({ - // highlight-next-line tokenTransferMethod: "header" // or "cookie", }) ], }) ``` - - + + - + - + - + - + ```tsx import SuperTokens from 'supertokens-react-native'; @@ -193,9 +174,9 @@ SuperTokens.init({ }); ``` - + - + You can use the `tokenTransferMethod` builder method to set what mode the SDK should use for sessions. @@ -274,9 +255,9 @@ class NetworkManager { In the above example, `PersistentCookieJar` from `'com.github.franmontiel:PersistentCookieJar:v1.0.1'` enables persistently storing cookies using SharedPreferences to maintain sessions across app launches. - + - + ```swift import UIKit @@ -302,9 +283,9 @@ fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -317,30 +298,29 @@ void main() { } ``` - + - + - + - + - + -### 2. Update the backend configuration {{optional}} +### 2. Update the backend configuration (optional) This step is optional. You can force the backend to use a specific token transfer method regardless of the frontend configuration. -:::caution -**You should not set this on the backend if you have more than one client using different modes** (for example if you have a website that uses cookie based, and a mobile app that uses header based sessions). +:::warning[**You should not set this on the backend if you have more than one client using different modes** (for example if you have a website that uses cookie based, and a mobile app that uses header based sessions).] ::: - - + + -```tsx +```tsx {12} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -352,17 +332,15 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-start getTokenTransferMethod: () => "header", - // highlight-end }) ] }); ``` - - + + -```go +```go {12,13,14} import ( "net/http" "github.com/supertokens/supertokens-golang/recipe/session" @@ -374,20 +352,18 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - // highlight-start GetTokenTransferMethod: func(req *http.Request, forCreateNewSession bool, userContext supertokens.UserContext) sessmodels.TokenTransferMethod { return sessmodels.HeaderTransferMethod }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {16} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session from supertokens_python.framework import BaseRequest @@ -400,20 +376,17 @@ def get_token_transfer_method(req: BaseRequest, for_create_new_session: bool, us init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-start get_token_transfer_method=get_token_transfer_method - # highlight-end ) ] ) ``` - - + + -:::note -By default, session verification allows both cookie and authorization bearer tokens. When creating a new session, it follows the preference of the frontend indicated by the `st-auth-mode` request header (set by the frontend SDK). +:::note[By default, session verification allows both cookie and authorization bearer tokens. When creating a new session, it follows the preference of the frontend indicated by the `st-auth-mode` request header (set by the frontend SDK).] ::: diff --git a/docs/post-authentication/user-management/_category_.json b/docs/post-authentication/user-management/_category_.json deleted file mode 100644 index a9432697ca..0000000000 --- a/docs/post-authentication/user-management/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "User Management", - "position": 2 -} diff --git a/docs/post-authentication/user-management/account-deduplication.mdx b/docs/post-authentication/user-management/account-deduplication.mdx index c07c2ad2b5..14b2cd3512 100644 --- a/docs/post-authentication/user-management/account-deduplication.mdx +++ b/docs/post-authentication/user-management/account-deduplication.mdx @@ -1,18 +1,10 @@ --- title: Account deduplication -hide_title: true -sidebar_position: 5 -description: >- - Learn how to prevent duplicate user accounts through account deduplication - techniques. -page_type: guide -recipe: emailpassword -category: authentication +description: Learn how to prevent duplicate user accounts through account deduplication techniques. +sidebar: + order: 5 --- - -# Account deduplication - ## Overview Users may forget the initial method they used to sign up and may create multiple accounts with the same email ID - leading to a poor user experience. @@ -35,8 +27,8 @@ The difference is that whilst deduplication prevents duplicate sign ups, account The approach to implementing account deduplication is to override the backend functions / APIs. This way, you can check if a user already exists and return an error to the frontend if the condition is true. - - + + ```tsx import ThirdParty from "supertokens-node/recipe/thirdparty" @@ -45,8 +37,6 @@ import supertokens from "supertokens-node"; let recipeList = [ Passwordless.init({ - contactMethod: "EMAIL", // REMOVE_FROM_OUTPUT - flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // REMOVE_FROM_OUTPUT override: { apis: (originalImplementation) => { return { @@ -128,8 +118,8 @@ let recipeList = [ ] ``` - - + + ```go import ( @@ -244,8 +234,8 @@ func main() { } ``` - - + + ```python from typing import Any, Dict, Optional, Union @@ -447,11 +437,11 @@ def override_passwordless_apis(original_implementation: PasswordlessAPIInterface init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ passwordless.init( - contact_config=..., # type: ignore - flow_type="...", # type: ignore + contact_config=..., + flow_type="...", override=passwordless.InputOverrideConfig( apis=override_passwordless_apis, ), @@ -465,8 +455,8 @@ init( ) ``` - - + + In the above code snippet, override the `signInUpPOST` (third party recipe) and the `createCodePOST` (passwordless recipe) API as well as the `signInUp` recipe function. @@ -480,7 +470,7 @@ The `signInUp` recipe function is overridden to: - If instead, a user exists, but has the same `thirdPartyId` and `thirdPartyUserId`, implying that this is a sign in (for example a user who had signed up with Google is signing in with Google), the operation proceeds by calling the `originalImplementation` function. - If neither of the conditions above match, it means that the user is trying to sign up with a third party provider whilst they already have an account with another provider or via passwordless login. Here, the system throws an error with some custom message. -Finally, the `signInUpPOST` API is overridden to catch that custom error and return a [general error status](/docs/references/backend-sdks/api-overrides#error-management) to the frontend with a message displayed to the user in the sign in form. +Finally, the `signInUpPOST` API is overridden to catch that custom error and return a [general error status](/references/backend-sdks/api-overrides#error-management) to the frontend with a message displayed to the user in the sign in form. The `createCodePOST` API is also overridden to perform similar checks: - If the input is phone number based, then the system calls the `originalImplementation` function allowing sign up or sign in. This is OK since social login is always email based, there is no scope of duplication. @@ -489,7 +479,7 @@ The `createCodePOST` API is also overridden to perform similar checks: - Else, check if the existing user is not a Third Party login user, implying that it's a Passwordless login user. Here, the `originalImplementation` function is also called to allow the user to sign in. - If neither of the conditions above match, it means that the user is trying to sign up with passwordless login whilst they already have an account with a third party provider. Here, the system returns an appropriate message to display on the frontend. -:::info Multi Tenancy +:::info[Multi Tenancy] For a multi tenant setup, the customisations above ensure that multiple accounts with the same email don't exist within a single tenant. To ensure no duplication across all tenants, when fetching the list of existing users, loop through all tenants in the app. You can fetch them by using the `listAllTenants` function of the multi tenancy recipe. diff --git a/docs/post-authentication/user-management/allow-users-to-update-their-data.mdx b/docs/post-authentication/user-management/allow-users-to-update-their-data.mdx index 3a4c098f24..38427ee989 100644 --- a/docs/post-authentication/user-management/allow-users-to-update-their-data.mdx +++ b/docs/post-authentication/user-management/allow-users-to-update-their-data.mdx @@ -1,27 +1,17 @@ --- title: Allow users to update their data -hide_title: true -sidebar_position: 3 -toc_max_heading_level: 4 description: Enable users to change their email or password. -page_type: guide -recipe: emailpassword -category: authentication +sidebar: + order: 3 --- - - -# Allow users to change their data - - ## Overview This guide shows you how to implement a feature that allows users to update their email or password. ## Before you start -:::caution -SuperTokens does not provide the UI for this type of use case. +:::warning[SuperTokens does not provide the UI for this type of use case.] You need to create the UI and set up a route on your backend to have this functionality. ::: @@ -40,38 +30,35 @@ In this flow, a user can update their account's email without verifying the new #### 1. Create the email update endpoint - You need to create a route on the backend protected by the session verification middleware, ensuring that only an authenticated user can access the protected route. -- To learn more about how to use the session verification middleware for other frameworks, click [this link](/docs/additional-verification/session-verification/protect-api-routes) +- To learn more about how to use the session verification middleware for other frameworks, click [this link](/additional-verification/session-verification/protect-api-routes) - + - + -```tsx +```tsx {7,8,9,10} import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express" import express from "express"; let app = express(); -// highlight-start app.post("/change-email", verifySession(), async (req: SessionRequest, res: express.Response) => { // TODO: see next steps }) -// highlight-end ``` - + - + -```go +```go {7,8,9,10,11,12,13,14,15,16,17,18} import ( "net/http" "github.com/supertokens/supertokens-golang/recipe/session" ) -// highlight-start // the following example uses net/http func main() { _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { @@ -84,15 +71,14 @@ func changeEmailAPI(w http.ResponseWriter, r *http.Request) { // TODO: see next steps } -// highlight-end ``` - + - + -```python +```python {8,9,10,11} # the following example uses flask from flask import Flask @@ -100,27 +86,25 @@ from supertokens_python.recipe.session.framework.flask import verify_session app = Flask(__name__) -# highlight-start -@app.route('/change-email', methods=['POST']) # type: ignore +@app.route('/change-email', methods=['POST']) @verify_session() def change_email(): pass # TODO: see next steps -# highlight-end ``` - + - + #### 2. Update the account - Validate the input email. - Update the account with the input email. - - + + -```tsx +```tsx {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39} // the following example uses express import Passwordless from "supertokens-node/recipe/passwordless"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; @@ -131,7 +115,6 @@ let app = express(); app.post("/change-email", verifySession(), async (req: SessionRequest, res: express.Response) => { - // highlight-start let session = req.session!; let email = req.body.email; @@ -161,7 +144,6 @@ app.post("/change-email", verifySession(), async (req: SessionRequest, res: expr // TODO: tell the user to contact support. } throw new Error("Should never come here"); - // highlight-end }) @@ -174,11 +156,11 @@ function isValidEmail(email: string) { ``` - + - + -```go +```go {24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56} import ( "encoding/json" "log" @@ -202,7 +184,6 @@ func main() { } func changeEmailAPI(w http.ResponseWriter, r *http.Request) { - // highlight-start sessionContainer := session.GetSessionFromRequestContext(r.Context()) var requestBody RequestBody @@ -236,7 +217,6 @@ func changeEmailAPI(w http.ResponseWriter, r *http.Request) { } log.Fatal("should not reach here") - // highlight-end } @@ -249,11 +229,11 @@ func isValidEmail(email string) bool { } ``` - + - + -```python +```python {20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52} from re import fullmatch from flask import Flask, g, request @@ -270,15 +250,14 @@ from supertokens_python.recipe.session.framework.flask import verify_session app = Flask(__name__) -@app.route("/change-email", methods=["POST"]) # type: ignore +@app.route("/change-email", methods=["POST"]) @verify_session() def change_email(): - # highlight-start session: SessionContainer = g.supertokens request_body = request.get_json() - email = str(request_body["email"]) # type: ignore + email = str(request_body["email"]) if request_body is None: # TODO: handle invalid body error return @@ -307,8 +286,6 @@ def change_email(): raise Exception("Should never reach here") - # highlight-end - def is_valid_email(value: str) -> bool: return ( @@ -320,8 +297,8 @@ def is_valid_email(value: str) -> bool: ) ``` - - + + ### With email verification @@ -330,38 +307,35 @@ In this flow, the user's account updates once they have verified the new email. #### 1. Create the email update endpoint - You need to create a route on the backend protected by the session verification middleware, ensuring that only an authenticated user can access the protected route. -- To learn more about how to use the session verification middleware for other frameworks, click [this link](/docs/additional-verification/session-verification/protect-api-routes) +- To learn more about how to use the session verification middleware for other frameworks, click [this link](/additional-verification/session-verification/protect-api-routes) - + - + -```tsx +```tsx {7,8,9,10} import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express" import express from "express"; let app = express(); -// highlight-start app.post("/change-email", verifySession(), async (req: SessionRequest, res: express.Response) => { // TODO: see next steps }) -// highlight-end ``` - + - + -```go +```go {7,8,9,10,11,12,13,14,15,16,17,18} import ( "net/http" "github.com/supertokens/supertokens-golang/recipe/session" ) -// highlight-start // the following example uses net/http func main() { _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { @@ -374,15 +348,14 @@ func changeEmailAPI(w http.ResponseWriter, r *http.Request) { // TODO: see next steps } -// highlight-end ``` - + - + -```python +```python {8,9,10,11} # the following example uses flask from flask import Flask @@ -390,17 +363,15 @@ from supertokens_python.recipe.session.framework.flask import verify_session app = Flask(__name__) -# highlight-start -@app.route('/change-email', methods=['POST']) # type: ignore +@app.route('/change-email', methods=['POST']) @verify_session() def change_password(): pass # TODO: see next steps -# highlight-end ``` - + - + #### 2. Initiate the email verification flow @@ -410,11 +381,11 @@ def change_password(): - If the email is **NOT** verified, create and send the verification email. - If the email has been verified, update the account with the new email. - - - -```tsx + + + +```tsx {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71} import Passwordless from "supertokens-node/recipe/passwordless"; import EmailVerification from "supertokens-node/recipe/emailverification"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; @@ -427,7 +398,6 @@ let app = express(); app.post("/change-email", verifySession(), async (req: SessionRequest, res: express.Response) => { - // highlight-start let session = req.session!; let email = req.body.email; @@ -487,7 +457,6 @@ app.post("/change-email", verifySession(), async (req: SessionRequest, res: expr } throw new Error("Should never come here"); - // highlight-end }) @@ -500,11 +469,11 @@ function isValidEmail(email: string) { ``` - + - + -```go +```go {26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82} import ( "encoding/json" @@ -530,7 +499,6 @@ func main() { } func changeEmailAPI(w http.ResponseWriter, r *http.Request) { - // highlight-start sessionContainer := session.GetSessionFromRequestContext(r.Context()) var requestBody RequestBody @@ -588,7 +556,6 @@ func changeEmailAPI(w http.ResponseWriter, r *http.Request) { } log.Fatal("should not reach here") - // highlight-end } @@ -602,11 +569,11 @@ func isValidEmail(email string) bool { ``` - + - + -```python +```python {26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91} from re import fullmatch from flask import Flask, g, request @@ -629,11 +596,10 @@ from supertokens_python.types.base import AccountInfoInput app = Flask(__name__) -@app.route("/change-email", methods=["POST"]) # type: ignore +@app.route("/change-email", methods=["POST"]) @verify_session() def change_email(): - # highlight-start - session: SessionContainer = g.supertokens # type: ignore + session: SessionContainer = g.supertokens request_body = request.get_json() @@ -699,7 +665,6 @@ def change_email(): # TODO handle error, email already exists return - # highlight-end raise Exception("Should never reach here") @@ -714,10 +679,10 @@ def is_valid_email(value: str) -> bool: ) ``` - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] - Notice that the process loops through all the tenants that this user belongs to check that for each of the tenants, there is no other user with the new email. If this step is not done, then calling `updateEmailOrPassword` would fail because the email is already used by another user in one of the tenants that this user belongs to. In that case, the verification process should not proceed either. - The `tenantId` of the current session is also passed when calling the `sendEmailVerificationEmail` function, ensuring that the link generated opens the tenant's UI that the user interacts with. @@ -729,10 +694,10 @@ def is_valid_email(value: str) -> bool: - Update the accounts email on successful email verification. - - + + -```tsx +```tsx {24,25,26,27,28,29,30,31,32,33} import SuperTokens from "supertokens-node"; import Passwordless from "supertokens-node/recipe/passwordless"; import EmailVerification from "supertokens-node/recipe/emailverification"; @@ -756,7 +721,6 @@ SuperTokens.init({ return { ...oI, verifyEmailPOST: async function (input) { - // highlight-start let response = await oI.verifyEmailPOST!(input); if (response.status === "OK") { // This will update the email of the user to the one @@ -767,7 +731,6 @@ SuperTokens.init({ }); } return response; - // highlight-end }, }; }, @@ -779,11 +742,11 @@ SuperTokens.init({ ``` - + - + -```go +```go {33,34,35,36,37,38,39,40,41} import ( "github.com/supertokens/supertokens-golang/recipe/emailverification" "github.com/supertokens/supertokens-golang/recipe/emailverification/evmodels" @@ -816,7 +779,6 @@ func main() { originalVerifyEmailPOST := *originalImplementation.VerifyEmailPOST (*originalImplementation.VerifyEmailPOST) = func(token string, sessionContainer sessmodels.SessionContainer, tenantId string, options evmodels.APIOptions, userContext supertokens.UserContext) (evmodels.VerifyEmailPOSTResponse, error) { - // highlight-start response, err := originalVerifyEmailPOST(token, sessionContainer, tenantId, options, userContext) if response.OK != nil { // This will update the email of the user to the one @@ -826,7 +788,6 @@ func main() { // TODO: Handle error } } - // highlight-end return response, err } @@ -846,11 +807,11 @@ func main() { ``` - + - + -```python +```python {31,32,33,34,35,36,37,38,39,40,41,59} from typing import Any, Dict, Optional from supertokens_python import ( @@ -881,7 +842,6 @@ def override_email_verification_apis(original_implementation: APIInterface): api_options: APIOptions, user_context: Dict[str, Any], ): - # highlight-start verification_response = await original_email_verification_verify_email_post( token, session, tenant_id, api_options, user_context ) @@ -893,7 +853,6 @@ def override_email_verification_apis(original_implementation: APIInterface): ) return verification_response - # highlight-end original_implementation.email_verify_post = email_verify_post return original_implementation @@ -911,17 +870,15 @@ init( emailverification.init( "REQUIRED", override=emailverification.InputOverrideConfig( - # highlight-start apis=override_email_verification_apis - # highlight-end ), ), ], ) ``` - - + + --- @@ -933,38 +890,35 @@ Calling this route checks if the old password is valid and updates the user's pr ### 1. Create the password update endpoint - You need to create a route on the backend protected by the session verification middleware, ensuring that only an authenticated user can access the protected route. -- To learn more about how to use the session verification middleware for other frameworks, click [this link](/docs/additional-verification/session-verification/protect-api-routes#using-verify-session) +- To learn more about how to use the session verification middleware for other frameworks, click [this link](/additional-verification/session-verification/protect-api-routes#using-verify-session) - + - + -```tsx +```tsx {7,8,9,10} import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express" import express from "express"; let app = express(); -// highlight-start app.post("/change-password", verifySession(), async (req: SessionRequest, res: express.Response) => { // TODO: see next steps }) -// highlight-end ``` - + - + -```go +```go {7,8,9,10,11,12,13,14,15,16,17,18} import ( "net/http" "github.com/supertokens/supertokens-golang/recipe/session" ) -// highlight-start // the following example uses net/http func main() { _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { @@ -977,14 +931,13 @@ func changePasswordAPI(w http.ResponseWriter, r *http.Request) { // TODO: see next steps } -// highlight-end ``` - + - + -```python +```python {8,9,10,11} # the following example uses flask from flask import Flask @@ -992,17 +945,15 @@ from supertokens_python.recipe.session.framework.flask import verify_session app = Flask(__name__) -# highlight-start -@app.route('/change-password', methods=['POST']) # type: ignore +@app.route('/change-password', methods=['POST']) @verify_session() def change_password(): pass # TODO: see next steps -# highlight-end ``` - + - + ### 2. Update the user password @@ -1010,10 +961,10 @@ def change_password(): - Use the recipe's sign in function and check if the old password is valid - Update the user's password. - - + + -```tsx +```tsx {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54} // the following example uses express import EmailPassword from "supertokens-node/recipe/emailpassword"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; @@ -1024,7 +975,6 @@ import supertokens from "supertokens-node"; let app = express(); app.post("/change-password", verifySession(), async (req: SessionRequest, res: express.Response) => { -// highlight-start // get the supertokens session object from the req let session = req.session @@ -1069,17 +1019,16 @@ app.post("/change-password", verifySession(), async (req: SessionRequest, res: e } // TODO: send successful password update response - // highlight-end }) ``` - + - + -```go +```go {51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68} import ( "encoding/json" "net/http" @@ -1130,7 +1079,6 @@ func changePasswordAPI(w http.ResponseWriter, r *http.Request) { return } - // highlight-start if isPasswordValid.WrongCredentialsError != nil { // TODO: Handle error return @@ -1149,16 +1097,15 @@ func changePasswordAPI(w http.ResponseWriter, r *http.Request) { return } // TODO: send successful password update response - // highlight-end } ``` - + - + -```python +```python {20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74} from flask import g, request from supertokens_python.recipe.emailpassword.interfaces import ( @@ -1174,12 +1121,11 @@ from supertokens_python.recipe.session.framework.flask import verify_session from supertokens_python.syncio import get_user -@app.route("/change-password", methods=["POST"]) # type: ignore +@app.route("/change-password", methods=["POST"]) @verify_session() def change_password(): - # highlight-start - session: SessionContainer = g.supertokens # type: ignore + session: SessionContainer = g.supertokens # get the signed in user's email from the getUserById function @@ -1234,26 +1180,25 @@ def change_password(): return # TODO: send successful password update response - # highlight-end ``` - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] Notice that the `tenantId` passes as an argument to the `signIn` and the `updateEmailOrPassword` functions. This ensures that the current tenant has email password enabled, and ensures that the user's new password matches the password policy defined for their tenant (if different password policies exist for different tenants). If this user shares access across multiple tenants, their password changes for all tenants. ::: -### 3. Revoke all sessions associated with the user {{optional}} +### 3. Revoke all sessions associated with the user (optional) - Revoking all sessions associated with the user forces them to re-authenticate with their new password. - - + + -```tsx +```tsx {21,22,23,24,25} // the following example uses express import Session from "supertokens-node/recipe/session"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; @@ -1274,24 +1219,22 @@ app.post("/change-password", verifySession(), async (req: SessionRequest, res: e * * */ - // highlight-start // revoke all sessions for the user await Session.revokeAllSessionsForUser(userId) // revoke the current user's session, this removes the auth cookies, logging out the user on the frontend. await req.session!.revokeSession() - //highlight-end // TODO: send successful password update response }) ``` - + - + -```go +```go {33,34,35,36,37,38,39,40,41,42,43,44,45} import ( "net/http" @@ -1324,7 +1267,6 @@ func changePasswordAPI(w http.ResponseWriter, r *http.Request) { * * */ - // highlight-start // revoke all sessions for the user _, err := session.RevokeAllSessionsForUser(userID, nil) @@ -1338,16 +1280,15 @@ func changePasswordAPI(w http.ResponseWriter, r *http.Request) { // TODO: Handle error } - // highlight-end // TODO: send successful password update response } ``` - + - + -```python +```python {21,22,23,24} from typing import cast from flask import Flask @@ -1357,26 +1298,24 @@ from supertokens_python.recipe.session.framework.flask import verify_session from supertokens_python.recipe.session.syncio import revoke_all_sessions_for_user app = Flask(__name__) -@app.route('/change-password', methods=['POST']) # type: ignore +@app.route('/change-password', methods=['POST']) @verify_session() def change_password(): - session: SessionContainer = cast(SessionContainer, g.supertokens) # type: ignore + session: SessionContainer = cast(SessionContainer, g.supertokens) # get the userId from the session object user_id = session.get_user_id() # TODO: see previous step... - # highlight-start # revoke all sessions for the user revoke_all_sessions_for_user(user_id) # revoke the user's current session, this removes the auth cookies, logging out the user on the frontend session.sync_revoke_session() - # highlight-end # TODO: send successful password update response ``` - + - + diff --git a/docs/post-authentication/user-management/common-actions.mdx b/docs/post-authentication/user-management/common-actions.mdx index 7270b1cae5..fb456c42b6 100644 --- a/docs/post-authentication/user-management/common-actions.mdx +++ b/docs/post-authentication/user-management/common-actions.mdx @@ -1,17 +1,10 @@ --- title: Common actions -hide_title: true -toc_max_heading_level: 4 -sidebar_position: 2 description: Discover how to manage users using SuperTokens. -page_type: guide -recipe: emailpassword -category: authentication +sidebar: + order: 2 --- - -# User management actions - ## Overview **SuperTokens** exposes a set of functions and APIs that you can use to have manual control over your users. @@ -23,8 +16,8 @@ Actions like fetching users or deleting them are available through different SDK ### By email - - + + ```tsx @@ -51,9 +44,9 @@ async function getUserInfo() { } ``` - + - + ```go @@ -76,12 +69,12 @@ func main() { } ``` - - + + - + - + ```python @@ -107,8 +100,8 @@ async def some_func(): # ``` - - + + ```python @@ -134,13 +127,13 @@ def some_func(): # ``` - - + + - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] Notice that the first argument of the above function is `"public"`. This is the default `tenantId`, which means that SuperTokens returns information about the user whose email is `"test@example.com"` in the `"public"` tenant. If you are using the multi-tenancy feature, you can pass in a different `tenantId` to get information about a user in a different tenant. @@ -148,8 +141,8 @@ If you are using the multi-tenancy feature, you can pass in a different `tenantI ### By phone number - - + + ```tsx import supertokens from "supertokens-node"; @@ -175,9 +168,9 @@ async function handler() { } ``` - + - + ```go import ( @@ -199,12 +192,12 @@ func main() { } ``` - - + + - + - + ```python from supertokens_python.asyncio import list_users_by_account_info @@ -217,8 +210,8 @@ async def some_func(): ) ``` - - + + ```python from supertokens_python.syncio import list_users_by_account_info @@ -231,24 +224,24 @@ def some_func(): ) ``` - - + + - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] Notice that the `"public"` `tenantId` appears in the function call above. This is the default `tenantId` and returns the user with the given phone number that belongs to the `public` tenant. You can provide a different `tenantId` if required. ::: ### By User ID - - - - + + + + -```tsx +```tsx {10} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from 'supertokens-node/framework/express'; @@ -258,7 +251,6 @@ let app = express(); app.get("/get-user-info", verifySession(), async (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - // highlight-next-line let userInfo = await supertokens.getUser(userId) /** @@ -276,11 +268,11 @@ app.get("/get-user-info", verifySession(), async (req: SessionRequest, res) => { */ }) ``` - + - + -```tsx +```tsx {21} import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import Hapi from "@hapi/hapi"; import { SessionRequest } from "supertokens-node/framework/hapi"; @@ -298,11 +290,9 @@ server.route({ }, ], }, - // @ts-ignore handler: async (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - // highlight-next-line let userInfo = await supertokens.getUser(userId) /** @@ -322,11 +312,11 @@ server.route({ }) ``` - + - + -```tsx +```tsx {13} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import { SessionRequest } from 'supertokens-node/framework/fastify'; @@ -339,7 +329,6 @@ fastify.post("/like-comment", { }, async (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - // highlight-next-line let userInfo = await supertokens.getUser(userId) /** @@ -358,11 +347,11 @@ fastify.post("/like-comment", { }); ``` - + - + -```tsx +```tsx {8} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; import supertokens from "supertokens-node"; @@ -370,7 +359,6 @@ import supertokens from "supertokens-node"; async function getUserInfo(awsEvent: SessionEvent) { let userId = awsEvent.session!.getUserId(); - // highlight-next-line let userInfo = await supertokens.getUser(userId) /** @@ -391,11 +379,11 @@ async function getUserInfo(awsEvent: SessionEvent) { exports.handler = verifySession(getUserInfo); ``` - + - + -```tsx +```tsx {11} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from "supertokens-node/framework/koa"; @@ -406,7 +394,6 @@ let router = new KoaRouter(); router.get("/get-user-info", verifySession(), async (ctx: SessionContext, next) => { let userId = ctx.session!.getUserId(); - // highlight-next-line let userInfo = await supertokens.getUser(userId) /** @@ -425,11 +412,11 @@ router.get("/get-user-info", verifySession(), async (ctx: SessionContext, next) }); ``` - + - + -```tsx +```tsx {16} import { inject, intercept } from "@loopback/core"; import { RestBindings, MiddlewareContext, get, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; @@ -445,7 +432,6 @@ class GetUserInfo { async handler() { let userId = ((this.ctx as any).session as Session.SessionContainer).getUserId(); - // highlight-next-line let userInfo = await supertokens.getUser(userId) /** @@ -465,17 +451,17 @@ class GetUserInfo { } ``` - + + + - - - + -```tsx +```tsx {17} import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; @@ -492,7 +478,6 @@ export default async function likeComment(req: SessionRequest, res: any) { let userId = req.session!.getUserId(); - // highlight-next-line let userInfo = await supertokens.getUser(userId) /** @@ -514,11 +499,10 @@ export default async function likeComment(req: SessionRequest, res: any) { -```tsx +```tsx {15} import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -530,7 +514,6 @@ export function POST(request: NextRequest) { } const userId = session!.getUserId(); - // highlight-next-line let userInfo = await SuperTokens.getUser(userId) /** @@ -552,16 +535,14 @@ export function POST(request: NextRequest) { ``` - + - + -```tsx +```tsx {14} import { Controller, Post, UseGuards, Request, Response } from "@nestjs/common"; -// @ts-ignore import { AuthGuard } from './auth/auth.guard'; -// @ts-ignore import { Session } from './auth/session.decorator'; import { SessionRequest } from "supertokens-node/framework/express"; import supertokens from "supertokens-node"; @@ -573,7 +554,6 @@ export class ExampleController { async postExample(@Request() req: SessionRequest, @Session() session: Session, @Response({passthrough: true}) res: Response): Promise { let userId = session.getUserId(); - // highlight-next-line let userInfo = await supertokens.getUser(userId) /** @@ -593,17 +573,17 @@ export class ExampleController { } } ``` - + - + - - + + - - + + -```go +```go {20} import ( "fmt" "net/http" @@ -623,7 +603,6 @@ func getUserInfoAPI(w http.ResponseWriter, r *http.Request) { userID := sessionContainer.GetUserID() // You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki - // highlight-next-line userInfo, err := emailpassword.GetUserByID(userID) if err != nil { // TODO: Handle error @@ -633,11 +612,11 @@ func getUserInfoAPI(w http.ResponseWriter, r *http.Request) { } ``` - + - + -```go +```go {33} import ( "fmt" "net/http" @@ -670,7 +649,6 @@ func getUserInfoAPI(c *gin.Context) { userID := sessionContainer.GetUserID() // You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki - // highlight-next-line userInfo, err := emailpassword.GetUserByID(userID) if err != nil { // TODO: Handle error @@ -681,11 +659,11 @@ func getUserInfoAPI(c *gin.Context) { } ``` - + - + -```go +```go {20} import ( "fmt" "net/http" @@ -705,7 +683,6 @@ func getUserInfoAPI(w http.ResponseWriter, r *http.Request) { userID := sessionContainer.GetUserID() // You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki - // highlight-next-line userInfo, err := emailpassword.GetUserByID(userID) if err != nil { // TODO: Handle error @@ -715,11 +692,11 @@ func getUserInfoAPI(w http.ResponseWriter, r *http.Request) { } ``` - + - + -```go +```go {20} import ( "fmt" "net/http" @@ -739,7 +716,6 @@ func getUserInfoAPI(w http.ResponseWriter, r *http.Request) { userID := sessionContainer.GetUserID() // You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki - // highlight-next-line userInfo, err := emailpassword.GetUserByID(userID) if err != nil { // TODO: Handle error @@ -749,17 +725,17 @@ func getUserInfoAPI(w http.ResponseWriter, r *http.Request) { } ``` - + - + - - + + - - + + -```python +```python {14} from fastapi import Depends, FastAPI from supertokens_python.asyncio import get_user @@ -768,19 +744,18 @@ from supertokens_python.recipe.session.framework.fastapi import verify_session app = FastAPI() -@app.post('/get_user_info_api') # type: ignore +@app.post('/get_user_info_api') async def get_user_info_api(session: SessionContainer = Depends(verify_session())): user_id = session.get_user_id() # You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki - # highlight-next-line _ = await get_user(user_id) ``` - - + + -```python +```python {17} from flask import Flask, g from supertokens_python.recipe.session import SessionContainer @@ -789,22 +764,21 @@ from supertokens_python.syncio import get_user app = Flask(__name__) -@app.route('/get_user_info', methods=['GET']) # type: ignore +@app.route('/get_user_info', methods=['GET']) @verify_session() def get_user_info_api(): - session: SessionContainer = g.supertokens # type: ignore + session: SessionContainer = g.supertokens user_id = session.get_user_id() # You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki - # highlight-next-line _ = get_user(user_id) ``` - - + + -```python +```python {17} from typing import cast from django.http import HttpRequest @@ -816,29 +790,28 @@ from supertokens_python.recipe.session.framework.django.asyncio import verify_se @verify_session() async def get_user_info_api(request: HttpRequest): - session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore + session: SessionContainer = cast(SessionContainer, request.supertokens) user_id = session.get_user_id() # You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki - # highlight-next-line _ = await get_user(user_id) ``` - - - - + + + + -:::info Tip +:::info[Tip] The authentication session also contains the user ID and the session payload. -You can access it on [both the backend and the frontend](/docs/additional-verification/session-verification/claim-validation#using-the-access-token-payload). +You can access it on [both the backend and the frontend](/additional-verification/session-verification/claim-validation#using-the-access-token-payload). ::: #### Using the user metadata recipe -Checkout the [user metadata recipe docs](/docs/post-authentication/user-management/user-metadata) which shows you how to save and fetch any JSON object against the user's ID. You can use this to save information like the user's name (`first_name` and `last_name`) or any other field associated with the user. +Checkout the [user metadata recipe docs](/post-authentication/user-management/user-metadata) which shows you how to save and fetch any JSON object against the user's ID. You can use this to save information like the user's name (`first_name` and `last_name`) or any other field associated with the user. --- @@ -846,8 +819,8 @@ Checkout the [user metadata recipe docs](/docs/post-authentication/user-manageme ## Delete user - - + + ```tsx import {deleteUser} from "supertokens-node"; @@ -858,8 +831,8 @@ async function deleteUserForId() { } ``` - - + + ```go import "github.com/supertokens/supertokens-golang/supertokens" @@ -870,11 +843,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.asyncio import delete_user @@ -885,8 +858,8 @@ async def do_delete(): await delete_user(user_id) # this will succeed even if the userId didn't exist. ``` - - + + ```python from supertokens_python.syncio import delete_user @@ -896,14 +869,13 @@ user_id = "..." # get the user ID somehow... delete_user(user_id) # this will succeed even if the userId didn't exist. ``` - - + + - - + + -:::caution -- Calling this function permanently removes all information associated with this user, including their sessions. +:::warning[- Calling this function permanently removes all information associated with this user, including their sessions.] - If this user has an active access token, and you have not enabled access token blacklisting, session verification still succeeds until their access token expires. After that, the system logs them out since session refresh fails. ::: @@ -914,8 +886,8 @@ delete_user(user_id) # this will succeed even if the userId didn't exist. ### Newest first - - + + ```tsx import { getUsersNewestFirst } from "supertokens-node"; @@ -944,8 +916,8 @@ async function getUsers() { tenantId: "public", limit: 200, paginationToken: nextPaginationToken, - // only get for those users who signed up with ^{recipeNameCapitalLetters} - includeRecipeIds: ["^{rid}"], + // only get for those users who signed up with + includeRecipeIds: [""], }) users = usersResponse.users; @@ -953,8 +925,8 @@ async function getUsers() { } ``` - - + + ```go import "github.com/supertokens/supertokens-golang/supertokens" @@ -976,7 +948,7 @@ func main() { } // get for specific recipes - includeRecipeIds := []string{"^{rid}"} + includeRecipeIds := []string{""} result, err = supertokens.GetUsersNewestFirst("", result.NextPaginationToken, &limit, &includeRecipeIds, nil) if err != nil { // TODO: Handle error @@ -985,11 +957,11 @@ func main() { } ``` - - + + - - + + ```python from supertokens_python.asyncio import get_users_newest_first @@ -1007,13 +979,13 @@ async def some_func(): "public", 200, users_response.next_pagination_token, - # only get for those users who signed up with ^{recipeNameCapitalLetters} - ["^{rid}"] + # only get for those users who signed up with + [""] ) ``` - - + + ```python from supertokens_python.syncio import get_users_newest_first @@ -1030,22 +1002,22 @@ users_response = get_users_newest_first( "public", 200, users_response.next_pagination_token, - # only get for those users who signed up with ^{recipeNameCapitalLetters} - ["^{rid}"] + # only get for those users who signed up with + [""] ) ``` - - + + - - + + ### Oldest first - - + + ```ts import { getUsersOldestFirst } from "supertokens-node"; @@ -1073,8 +1045,8 @@ async function getUsers() { tenantId: "public", limit: 200, paginationToken: nextPaginationToken, - // only get for those users who signed up with ^{recipeNameCapitalLetters} - includeRecipeIds: ["^{rid}"] + // only get for those users who signed up with + includeRecipeIds: [""] }); users = usersResponse.users; @@ -1087,8 +1059,8 @@ async function getUsers() { - Each element in the `users` array is according to the output of the core API as shown in the [API documentation](https://app.swaggerhub.com/apis/supertokens/CDI/2.8.0#/Core/getUsers). - - + + ```go import "github.com/supertokens/supertokens-golang/supertokens" @@ -1110,7 +1082,7 @@ func main() { } // get for specific recipes - includeRecipeIds := []string{"^{rid}"} + includeRecipeIds := []string{""} result, err = supertokens.GetUsersOldestFirst("", result.NextPaginationToken, &limit, &includeRecipeIds, nil) if err != nil { // TODO: Handle error @@ -1124,11 +1096,11 @@ func main() { - Each element in the `result.Users` array is according to the output of the core API as shown in the [API documentation](https://app.swaggerhub.com/apis/supertokens/CDI/2.8.0#/Core/getUsers). - - + + - - + + ```python from supertokens_python.asyncio import get_users_oldest_first @@ -1146,13 +1118,13 @@ async def some_func(): "public", 200, users_response.next_pagination_token, - # only get for those users who signed up with ^{recipeNameCapitalLetters} - ["^{rid}"] + # only get for those users who signed up with + [""] ) ``` - - + + ```python from supertokens_python.syncio import get_users_oldest_first @@ -1169,19 +1141,19 @@ users_response = get_users_oldest_first( "public", 200, users_response.next_pagination_token, - # only get for those users who signed up with ^{recipeNameCapitalLetters} - ["^{rid}"] + # only get for those users who signed up with + [""] ) ``` - - + + - - + + -:::info Multi Tenancy +:::info[Multi Tenancy] Notice that the `tenantId` appears as `"public"`. This means that the functions above loop through the users of the `public` `tenantId`. If you want to loop through other tenant IDs, you can pass in the tenant ID string to the function call. This also implies that there is no way to loop through all users across all tenants in one go. If you want to do this, you must loop through each tenant one by one. @@ -1191,8 +1163,8 @@ This also implies that there is no way to loop through all users across all tena ## Count users - - + + ```ts import {getUserCount} from "supertokens-node"; @@ -1202,8 +1174,8 @@ async function getCount() { } ``` - - + + ```go import ( @@ -1224,10 +1196,10 @@ func main() { } ``` - - - - + + + + ```python from supertokens_python.asyncio import get_user_count @@ -1239,8 +1211,8 @@ async def some_func(): print(user_count) # TODO.. ``` - - + + ```python from supertokens_python.syncio import get_user_count @@ -1250,11 +1222,11 @@ user_count = get_user_count() ``` - - - - + + + + -:::info Multi Tenancy +:::info[Multi Tenancy] By default, the getUserCount function returns the number of users across all tenants. If you want to get the number of users for a specific tenant, you can pass in the tenant ID string to the function call. ::: diff --git a/docs/post-authentication/user-management/introduction.mdx b/docs/post-authentication/user-management/introduction.mdx index 78ee36ee9b..7a20cf2f44 100644 --- a/docs/post-authentication/user-management/introduction.mdx +++ b/docs/post-authentication/user-management/introduction.mdx @@ -1,17 +1,10 @@ --- title: Introduction -hide_title: true -sidebar_position: 1 -skip_llms_txt: true description: 'Learn how to manage users in SuperTokens ' -page_type: overview -recipe: emailpassword -category: authentication +sidebar: + order: 1 --- - -# User management - ## Overview Users are at the core of every authentication flow. @@ -21,44 +14,24 @@ They get created either from the recipe sign up flow, through the migration API ## Prerequisites This section assumes that you are familiar with basic **SuperTokens** concepts like **recipes**, **sessions** and authentication methods. -If not, please refer to the [quickstart guide](/docs/quickstart/introduction) first. +If not, please refer to the [quickstart guide](/quickstart/introduction) first. ## Customization Besides the common actions which you can use to manage users, you can also integrate different features which allow you extend the user functionality. - - - - Common actions - - - See how to create, update and delete users. - - - - - User Metadata - - - Learn how to include additional data to each user. - - - - - Allow users to update their data - - - Implement a series of steps that enable users to change their credentials. - - - - - Account deduplication - - - Prevent the creation of multiple accounts with the same email ID. - - - + + +See how to create, update and delete users. + + +Learn how to include additional data to each user. + + +Implement a series of steps that enable users to change their credentials. + + +Prevent the creation of multiple accounts with the same email ID. + + diff --git a/docs/post-authentication/user-management/meta.ts b/docs/post-authentication/user-management/meta.ts new file mode 100644 index 0000000000..7fe32fb283 --- /dev/null +++ b/docs/post-authentication/user-management/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "User Management", + "icon": "user-search", + "order": 2 +}); diff --git a/docs/post-authentication/user-management/progressive-profiling.mdx b/docs/post-authentication/user-management/progressive-profiling.mdx index d1c0f25fb0..4901e8fc7e 100644 --- a/docs/post-authentication/user-management/progressive-profiling.mdx +++ b/docs/post-authentication/user-management/progressive-profiling.mdx @@ -1,13 +1,11 @@ --- title: Progressive profiling -hide_title: true -sidebar_position: 6 description: Gradually collect user information through customizable multi-step forms using the progressive profiling plugin -page_type: tutorial +sidebar: + order: 6 + badge: New --- -# Progressive profiling - ## Overview This tutorial shows you how to add progressive profiling functionality to your **SuperTokens** authentication flows. @@ -26,10 +24,10 @@ The progressive profiling plugin supports only the `React` and `NodeJS` SDKs. Support for other platforms is under active development. The implementation is in early stages and APIs might change. -For more information on how plugins work refer to the [references page](/docs/references/plugins/introduction). +For more information on how plugins work refer to the [references page](/references/plugins/introduction). You need to start from a working **SuperTokens** setup. -If you haven't done that already, please refer to the [Quickstart Guides](/docs/quickstart/introduction). +If you haven't done that already, please refer to the [Quickstart Guides](/quickstart/introduction). ## Steps @@ -139,7 +137,7 @@ The plugin supports the following field types: | `url` | URL input with validation | Website, social profiles | | `image-url` | Image URL input with preview | Profile picture, logo | -:::info no-title +:::info The plugin provides built-in validation for form fields: - **Required Fields**: Automatically validates that required fields are not empty - **Field Type Validation**: Ensures values match the expected field type @@ -191,7 +189,7 @@ Try to authenticate and check if you get sent to the new form. Progressive profiling setup interface @@ -325,7 +323,7 @@ function CustomProfileComponent() { } ``` -:::info pre-built UI +:::info[pre-built UI] You can integrate the pre-built UI into other pages/components by importing the `ProgressiveProfilingWrapper` component: ```typescript @@ -341,7 +339,6 @@ function MyApp() { ::: - ### Form fields validation To change the default validation behavior you can override the `validateField` function: @@ -416,31 +413,16 @@ SuperTokens.init({ Besides progressive profiling, you can also explore other user management features: - - - - User Banning - - - Implement user banning functionality to restrict access. - - - - - - User Roles - - - Implement role-based access control for your users. - - - - - - Plugins Reference - - - General information on how plugins work. - - - + + +Implement user banning functionality to restrict access. + + + +Implement role-based access control for your users. + + + +General information on how plugins work. + + diff --git a/docs/post-authentication/user-management/user-banning.mdx b/docs/post-authentication/user-management/user-banning.mdx index 75938a0f20..bcf35111b3 100644 --- a/docs/post-authentication/user-management/user-banning.mdx +++ b/docs/post-authentication/user-management/user-banning.mdx @@ -1,13 +1,11 @@ --- title: User banning -hide_title: true -sidebar_position: 5 description: Implement a user banning feature using plugins -page_type: tutorial +sidebar: + order: 5 + badge: New --- -# User banning - ## Overview This tutorial shows you how to add a user banning feature to your SuperTokens authentication flows. @@ -69,7 +67,7 @@ SuperTokens.init({ ``` -:::warning no-title +:::warning Make sure to also initialize the `UserRoles` recipe if you haven't already. ::: @@ -112,13 +110,13 @@ SuperTokens.init({ The plugin provides a complete administrative interface accessible at `/admin/ban-user`. Before you access the interface, make sure that your user has the required permission, `ban-user` by default. -Read the [role management actions page](/docs/additional-verification/user-roles/role-management-actions#add-permissions) for instructions on how to add permissions to your users. +Read the [role management actions page](/additional-verification/user-roles/role-management-actions#add-permissions) for instructions on how to add permissions to your users. User banning UI @@ -189,7 +187,6 @@ if (status.status === "OK") { ``` - ## Customization ### Implement a custom user interface @@ -247,31 +244,16 @@ function MyCustomAdminComponent() { Besides user banning you can also look into other user management features and security measures: - - - - Attack Protection Suite - - - Prevent suspicious authentication attempts. - - - - - - User Roles - - - Implement role-based access control for your users. - - - - - - Plugins Reference - - - General information on how plugins work. - - - + + +Prevent suspicious authentication attempts. + + + +Implement role-based access control for your users. + + + +General information on how plugins work. + + diff --git a/docs/post-authentication/user-management/user-metadata.mdx b/docs/post-authentication/user-management/user-metadata.mdx index 77d2366362..12d398d3f6 100644 --- a/docs/post-authentication/user-management/user-metadata.mdx +++ b/docs/post-authentication/user-management/user-metadata.mdx @@ -1,16 +1,10 @@ --- title: User metadata -hide_title: true -sidebar_position: 4 description: Store and manage user metadata using the backend SDK's UserMetadata recipe. -page_type: guide -recipe: emailpassword -category: authentication +sidebar: + order: 4 --- - -# User metadata - ## Overview You can use the `UserMetadata` recipe to store your custom data about each user. @@ -21,10 +15,10 @@ The following page shows you how to enable and use the feature. ## Enable the `UserMetadata` recipe - - + + -```tsx +```tsx {15} import SuperTokens from "supertokens-node"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -39,16 +33,15 @@ SuperTokens.init({ }, recipeList: [ // Initialize other recipes as seen in the quick setup guide - // highlight-next-line UserMetadata.init(), ] }); ``` - - + + -```go +```go {10} import ( "github.com/supertokens/supertokens-golang/recipe/usermetadata" "github.com/supertokens/supertokens-golang/supertokens" @@ -58,17 +51,16 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ // Initialize other recipes as seen in the quick setup guide - // highlight-next-line usermetadata.Init(nil), }, }) } ``` - - + + -```python +```python {11} from supertokens_python import InputAppInfo, init from supertokens_python.recipe import usermetadata @@ -76,32 +68,30 @@ init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..." ), - framework='...', # type: ignore + framework='...', recipe_list=[ # Initialize other recipes as seen in the quick setup guide - # highlight-next-line usermetadata.init() ] ) ``` - - + + --- ## Store data -:::important -Only root-level properties merge into the stored object. Nested objects and all lower-level properties replace the existing ones. +:::note[Only root-level properties merge into the stored object. Nested objects and all lower-level properties replace the existing ones.] ::: - - - - + + + + -```tsx +```tsx {11} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -112,18 +102,16 @@ app.post("/updateinfo", verifySession(), async (req, res) => { const session = req.session; const userId = session.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { newKey: "data" }); - // highlight-end res.json({ message: "successfully updated user metadata" }); }); ``` - - + + -```tsx +```tsx {22} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import { SessionRequest } from "supertokens-node/framework/hapi"; @@ -145,18 +133,16 @@ server.route({ const session = req.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { newKey: "data" }); - // highlight-end return res.response({ message: "successfully updated user metadata" }).code(200); }, }); ``` - - + + -```tsx +```tsx {16} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -172,18 +158,16 @@ fastify.post( const session = req.session; const userId = session.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { newKey: "data" }); - // highlight-end res.send({ message: "successfully updated user metadata" }); }, ); ``` - - + + -```tsx +```tsx {9} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -192,9 +176,7 @@ async function updateinfo(awsEvent: SessionEvent) { const session = awsEvent.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { newKey: "data" }); - // highlight-end return { body: JSON.stringify({ message: "successfully updated user metadata" }), @@ -205,10 +187,10 @@ async function updateinfo(awsEvent: SessionEvent) { exports.handler = verifySession(updateinfo); ``` - - + + -```tsx +```tsx {12} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from "supertokens-node/framework/koa"; @@ -220,17 +202,15 @@ router.post("/updateinfo", verifySession(), async (ctx: SessionContext, next) => const session = ctx.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { newKey: "data" }); - // highlight-end ctx.body = { message: "successfully updated user metadata" }; }); ``` - - + + -```tsx +```tsx {16} import { inject, intercept } from "@loopback/core"; import { RestBindings, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; @@ -246,24 +226,22 @@ class UpdateInfo { const session = this.ctx.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { newKey: "data" }); - // highlight-end return { message: "successfully updated user metadata" }; } } ``` - - + + + - - + -```tsx +```tsx {17} import { superTokensNextWrapper } from "supertokens-node/nextjs"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; @@ -280,9 +258,7 @@ export default async function updateInfo(req: any, res: any) { const session = (req as SessionRequest).session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { newKey: "data" }); - // highlight-end res.json({ message: "successfully updated user metadata" }); } ``` @@ -290,12 +266,11 @@ export default async function updateInfo(req: any, res: any) { -```tsx +```tsx {16} import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import UserMetadata from "supertokens-node/recipe/usermetadata"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -307,9 +282,7 @@ export function POST(request: NextRequest) { } const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { newKey: "data" }); - // highlight-end return NextResponse.json({ success: "successfully updated user metadata" }); }); } @@ -317,14 +290,13 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {14} import { Controller, Post, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; import UserMetadata from "supertokens-node/recipe/usermetadata"; -// @ts-ignore import { AuthGuard } from "./auth/auth.guard"; @Controller() @@ -335,75 +307,67 @@ export class ExampleController { async postExample(@Session() session: SessionContainer): Promise<{ message: string }> { const userId = session.getUserId(); - //highlight-start await UserMetadata.updateUserMetadata(userId, { newKey: "data" }); - //highlight-end return { message: "successfully updated user metadata" }; } } ``` - - - - + + + + -```go +```go {6,7,8} import "github.com/supertokens/supertokens-golang/recipe/usermetadata" func main() { userId := "..." - // highlight-start usermetadata.UpdateUserMetadata(userId, map[string]interface{}{ "newKey": "data", }) - // highlight-end } ``` - - - + + + - + -```python +```python {7,8,9} from supertokens_python.recipe.usermetadata.asyncio import update_user_metadata async def some_func(): user_id = "..." - # highlight-start await update_user_metadata(user_id, { "newKey": "data" }) - # highlight-end ``` - - + + -```python +```python {5,6,7} from supertokens_python.recipe.usermetadata.syncio import update_user_metadata user_id = "..." -# highlight-start update_user_metadata(user_id, { "newKey": "data" }) -# highlight-end ``` - - - - + + + + -:::info Multi Tenancy +:::info[Multi Tenancy] User metadata that associates with a user shares across all tenants that that user is a part of. If instead, you want to store user metadata on a tenant level, you can add a custom key in the JSON like: ```json @@ -425,12 +389,12 @@ and then read the appropriate key based on the `tenantId`. ## Access data - - - - + + + + -```tsx +```tsx {11} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -441,18 +405,16 @@ app.post("/updateinfo", verifySession(), async (req, res) => { const session = req.session; const userId = session.getUserId(); - // highlight-start const { metadata } = await UserMetadata.getUserMetadata(userId); - // highlight-end res.json({ preferences: metadata.preferences }); }); ``` - - + + -```tsx +```tsx {22} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -474,18 +436,16 @@ server.route({ const session = req.session; const userId = session!.getUserId(); - // highlight-start const { metadata } = await UserMetadata.getUserMetadata(userId); - // highlight-end return res.response({ preferences: metadata.preferences }).code(200); }, }); ``` - - + + -```tsx +```tsx {16} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -501,18 +461,16 @@ fastify.post( const session = req.session; const userId = session.getUserId(); - // highlight-start const { metadata } = await UserMetadata.getUserMetadata(userId); - // highlight-end res.send({ preferences: metadata.preferences }); }, ); ``` - - + + -```tsx +```tsx {9} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import UserMetadata from "supertokens-node/recipe/usermetadata"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; @@ -521,9 +479,7 @@ async function updateinfo(awsEvent: SessionEvent) { const session = awsEvent.session; const userId = session!.getUserId(); - // highlight-start const { metadata } = await UserMetadata.getUserMetadata(userId); - // highlight-end return { body: JSON.stringify({ preferences: metadata.preferences }), @@ -534,10 +490,10 @@ async function updateinfo(awsEvent: SessionEvent) { exports.handler = verifySession(updateinfo); ``` - - + + -```tsx +```tsx {12} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -549,17 +505,15 @@ router.post("/updateinfo", verifySession(), async (ctx: SessionContext, next) => const session = ctx.session; const userId = session!.getUserId(); - // highlight-start const { metadata } = await UserMetadata.getUserMetadata(userId); - // highlight-end ctx.body = { preferences: metadata.preferences }; }); ``` - - + + -```tsx +```tsx {16} import { inject, intercept } from "@loopback/core"; import { RestBindings, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; @@ -575,24 +529,22 @@ class UpdateInfo { const session = this.ctx.session; const userId = session!.getUserId(); - // highlight-start const { metadata } = await UserMetadata.getUserMetadata(userId); - // highlight-end return { preferences: metadata.preferences }; } } ``` - - + + + - - + -```tsx +```tsx {17} import { superTokensNextWrapper } from "supertokens-node/nextjs"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -609,9 +561,7 @@ export default async function updateInfo(req: any, res: any) { const session = (req as SessionRequest).session; const userId = session!.getUserId(); - // highlight-start const { metadata } = await UserMetadata.getUserMetadata(userId); - // highlight-end res.json({ preferences: metadata.preferences }); } ``` @@ -619,12 +569,11 @@ export default async function updateInfo(req: any, res: any) { -```tsx +```tsx {16} import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import UserMetadata from "supertokens-node/recipe/usermetadata"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -636,9 +585,7 @@ export function POST(request: NextRequest) { } const userId = session!.getUserId(); - // highlight-start const { metadata } = await UserMetadata.getUserMetadata(userId); - // highlight-end return NextResponse.json({ preferences: metadata.preferences }); }); } @@ -646,14 +593,13 @@ export function POST(request: NextRequest) { - - + + -```tsx +```tsx {14} import { Controller, Post, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; import UserMetadata from "supertokens-node/recipe/usermetadata"; -// @ts-ignore import { AuthGuard } from "./auth/auth.guard"; @Controller() @@ -664,20 +610,18 @@ export class ExampleController { async postExample(@Session() session: SessionContainer): Promise<{ preferences: any }> { const userId = session.getUserId(); - //highlight-start const { metadata } = await UserMetadata.getUserMetadata(userId); - //highlight-end return { preferences: metadata.preferences }; } } ``` - - - - + + + + -```go +```go {10} import ( "fmt" @@ -687,7 +631,6 @@ import ( func main() { userId := "..." - // highlight-next-line metadata, err := usermetadata.GetUserMetadata(userId) if err != nil { // TODO: handle error... @@ -698,45 +641,43 @@ func main() { } ``` - - - + + + - + -```python +```python {7} from supertokens_python.recipe.usermetadata.asyncio import get_user_metadata async def some_func(): user_id = "..." - # highlight-next-line metadataResult = await get_user_metadata(user_id) exampleValue = metadataResult.metadata["exampleKey"] print(exampleValue) ``` - - + + -```python +```python {5} from supertokens_python.recipe.usermetadata.syncio import get_user_metadata user_id = "..." -# highlight-next-line metadataResult = get_user_metadata(user_id) exampleValue = metadataResult.metadata["exampleKey"] print(exampleValue) ``` - - - - + + + + -:::info Important +:::info[Important] By default, all users have an empty metadata object. ::: @@ -771,18 +712,18 @@ This would result in the final metadata object: } ``` -:::info Important +:::info[Important] You can only remove the root level fields in the metadata object in this way. From the above example, if you set `preferences.theme: null`, then it does not remove the `"theme"` field, but instead sets it to a JSON null value. ::: In code, it would look like: - - - - + + + + -```tsx +```tsx {11} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -793,18 +734,16 @@ app.post("/updateinfo", verifySession(), async (req, res) => { const session = req.session; const userId = session.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { notifications: null }); - // highlight-end res.json({ message: "successfully updated user metadata" }); }); ``` - - + + -```tsx +```tsx {22} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import { SessionRequest } from "supertokens-node/framework/hapi"; @@ -826,18 +765,16 @@ server.route({ const session = req.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { notifications: null }); - // highlight-end return res.response({ message: "successfully updated user metadata" }).code(200); }, }); ``` - - + + -```tsx +```tsx {16} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -853,18 +790,16 @@ fastify.post( const session = req.session; const userId = session.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { notifications: null }); - // highlight-end res.send({ message: "successfully updated user metadata" }); }, ); ``` - - + + -```tsx +```tsx {9} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -873,9 +808,7 @@ async function updateinfo(awsEvent: SessionEvent) { const session = awsEvent.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { notifications: null }); - // highlight-end return { body: JSON.stringify({ message: "successfully updated user metadata" }), @@ -886,10 +819,10 @@ async function updateinfo(awsEvent: SessionEvent) { exports.handler = verifySession(updateinfo); ``` - - + + -```tsx +```tsx {12} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from "supertokens-node/framework/koa"; @@ -901,17 +834,15 @@ router.post("/updateinfo", verifySession(), async (ctx: SessionContext, next) => const session = ctx.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { notifications: null }); - // highlight-end ctx.body = { message: "successfully updated user metadata" }; }); ``` - - + + -```tsx +```tsx {16} import { inject, intercept } from "@loopback/core"; import { RestBindings, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; @@ -927,24 +858,22 @@ class UpdateInfo { const session = this.ctx.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { notifications: null }); - // highlight-end return { message: "successfully updated user metadata" }; } } ``` - - + + + - - + -```tsx +```tsx {17} import { superTokensNextWrapper } from "supertokens-node/nextjs"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; @@ -961,9 +890,7 @@ export default async function updateInfo(req: any, res: any) { const session = (req as SessionRequest).session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { notifications: null }); - // highlight-end res.json({ message: "successfully updated user metadata" }); } ``` @@ -971,12 +898,11 @@ export default async function updateInfo(req: any, res: any) { -```tsx +```tsx {16} import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import UserMetadata from "supertokens-node/recipe/usermetadata"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -988,23 +914,20 @@ export function POST(request: NextRequest) { } const userId = session!.getUserId(); - // highlight-start await UserMetadata.updateUserMetadata(userId, { notifications: null }); - // highlight-end return NextResponse.json({ message: "successfully updated user metadata" }); }); } ``` - - + + -```tsx +```tsx {14} import { Controller, Post, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; import UserMetadata from "supertokens-node/recipe/usermetadata"; -// @ts-ignore import { AuthGuard } from "./auth/auth.guard"; @Controller() @@ -1015,83 +938,75 @@ export class ExampleController { async postExample(@Session() session: SessionContainer): Promise<{ message: string }> { const userId = session.getUserId(); - //highlight-start await UserMetadata.updateUserMetadata(userId, { notifications: null }); - //highlight-end return { message: "successfully updated user metadata" }; } } ``` - - - - + + + + -```go +```go {6,7,8} import "github.com/supertokens/supertokens-golang/recipe/usermetadata" func main() { userId := "..." - // highlight-start usermetadata.UpdateUserMetadata(userId, map[string]interface{}{ "notifications": nil, }) - // highlight-end } ``` - - - + + + - + -```python +```python {7,8,9} from supertokens_python.recipe.usermetadata.asyncio import update_user_metadata async def some_func(): user_id = "..." - # highlight-start await update_user_metadata(user_id, { "notifications": None }) - # highlight-end ``` - - + + -```python +```python {5,6,7} from supertokens_python.recipe.usermetadata.syncio import update_user_metadata user_id = "..." -# highlight-start update_user_metadata(user_id, { "notifications": None }) -# highlight-end ``` - - - - + + + + ### Delete the entire metadata object Using this function deletes all the fields in the user metadata object for that user. - - - - + + + + -```tsx +```tsx {11} import express from "express"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -1102,18 +1017,16 @@ app.post("/updateinfo", verifySession(), async (req, res) => { const session = req.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.clearUserMetadata(userId); - // highlight-end res.json({ success: true }); }); ``` - - + + -```tsx +```tsx {22} import Hapi from "@hapi/hapi"; import { verifySession } from "supertokens-node/recipe/session/framework/hapi"; import { SessionRequest } from "supertokens-node/framework/hapi"; @@ -1135,18 +1048,16 @@ server.route({ const session = req.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.clearUserMetadata(userId); - // highlight-end return res.response({ success: true }).code(200); }, }); ``` - - + + -```tsx +```tsx {16} import Fastify from "fastify"; import { verifySession } from "supertokens-node/recipe/session/framework/fastify"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -1162,18 +1073,16 @@ fastify.post( const session = req.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.clearUserMetadata(userId); - // highlight-end res.send({ success: true }); }, ); ``` - - + + -```tsx +```tsx {9} import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; import UserMetadata from "supertokens-node/recipe/usermetadata"; @@ -1182,9 +1091,7 @@ async function updateinfo(awsEvent: SessionEvent) { const session = awsEvent.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.clearUserMetadata(userId); - // highlight-end return { body: JSON.stringify({ success: true }), @@ -1195,10 +1102,10 @@ async function updateinfo(awsEvent: SessionEvent) { exports.handler = verifySession(updateinfo); ``` - - + + -```tsx +```tsx {12} import KoaRouter from "koa-router"; import { verifySession } from "supertokens-node/recipe/session/framework/koa"; import { SessionContext } from "supertokens-node/framework/koa"; @@ -1210,17 +1117,15 @@ router.post("/updateinfo", verifySession(), async (ctx: SessionContext, next) => const session = ctx.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.clearUserMetadata(userId); - // highlight-end ctx.body = { success: true }; }); ``` - - + + -```tsx +```tsx {16} import { inject, intercept } from "@loopback/core"; import { RestBindings, post, response } from "@loopback/rest"; import { verifySession } from "supertokens-node/recipe/session/framework/loopback"; @@ -1236,24 +1141,22 @@ class UpdateInfo { const session = this.ctx.session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.clearUserMetadata(userId); - // highlight-end return { success: true }; } } ``` - - + + + - - + -```tsx +```tsx {17} import { superTokensNextWrapper } from "supertokens-node/nextjs"; import { verifySession } from "supertokens-node/recipe/session/framework/express"; import { SessionRequest } from "supertokens-node/framework/express"; @@ -1270,9 +1173,7 @@ export default async function updateInfo(req: any, res: any) { const session = (req as SessionRequest).session; const userId = session!.getUserId(); - // highlight-start await UserMetadata.clearUserMetadata(userId); - // highlight-end res.json({ success: true }); } ``` @@ -1280,12 +1181,11 @@ export default async function updateInfo(req: any, res: any) { -```tsx +```tsx {16} import { NextResponse, NextRequest } from "next/server"; import SuperTokens from "supertokens-node"; import { withSession } from "supertokens-node/nextjs"; import UserMetadata from "supertokens-node/recipe/usermetadata"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -1297,23 +1197,20 @@ export function POST(request: NextRequest) { } const userId = session!.getUserId(); - // highlight-start await UserMetadata.clearUserMetadata(userId); - // highlight-end return NextResponse.json({ success: true }); }); } ``` - - + + -```tsx +```tsx {13,14} import { Controller, Post, UseGuards, Session } from "@nestjs/common"; import { SessionContainer } from "supertokens-node/recipe/session"; import UserMetadata from "supertokens-node/recipe/usermetadata"; -// @ts-ignore import { AuthGuard } from "./auth/auth.guard"; @Controller() @@ -1323,75 +1220,67 @@ export class ExampleController { async postExample(@Session() session: SessionContainer): Promise<{ success: boolean }> { const userId = session.getUserId(); - //highlight-start // For more information about "AuthGuard" and the "Session" decorator please read our NestJS guide. await UserMetadata.clearUserMetadata(userId); - //highlight-end return { success: true }; } } ``` - - - - + + + + -```go +```go {6} import "github.com/supertokens/supertokens-golang/recipe/usermetadata" func main() { userId := "..." - // highlight-start usermetadata.ClearUserMetadata(userId) - // highlight-end } ``` - - - + + + - + -```python +```python {7} from supertokens_python.recipe.usermetadata.asyncio import clear_user_metadata async def some_func(): user_id = "..." - # highlight-start await clear_user_metadata(user_id) - # highlight-end ``` - - + + -```python +```python {5} from supertokens_python.recipe.usermetadata.syncio import clear_user_metadata user_id = "..." -# highlight-start clear_user_metadata(user_id) -# highlight-end ``` - - - - + + + + --- ## See also - - - - - - + + + + + + diff --git a/docs/post-authentication/user-management/user-profile.mdx b/docs/post-authentication/user-management/user-profile.mdx index 79a5c863ec..9ed141cf43 100644 --- a/docs/post-authentication/user-management/user-profile.mdx +++ b/docs/post-authentication/user-management/user-profile.mdx @@ -1,19 +1,18 @@ --- title: Profile Management -hide_title: true -sidebar_position: 4 -description: Add comprehensive user profile management with customizable form fields and account information display using the profile details plugin -page_type: tutorial +description: >- + Add comprehensive user profile management with customizable form fields and account information display using the + profile details plugin +sidebar: + order: 4 --- -# User profile management - ## Overview This tutorial shows you how to add comprehensive user profile management to your **SuperTokens** authentication flows. The guide makes use of the `plugins` functionality which provides a complete profile management interface with customizable form fields, account information display, and automatic third-party data integration. -The functionality integrates with the [progressive profiling plugin](/docs/post-authentication/user-management/progressive-profiling) by default. +The functionality integrates with the [progressive profiling plugin](/post-authentication/user-management/progressive-profiling) by default. This allows you to: - Gradually collect user information through the progressive profiling flow - Display collected information in the profile details interface @@ -25,7 +24,7 @@ The profile details plugin supports only the `React` and `NodeJS` SDKs. Support for other platforms is under active development. You need to start from a working **SuperTokens** setup. -If you haven't done that already, please refer to the [Quickstart Guides](/docs/quickstart/introduction). +If you haven't done that already, please refer to the [Quickstart Guides](/quickstart/introduction). ## Steps @@ -146,7 +145,7 @@ When users sign in using external providers, the plugin maps provider data to pr - `lastName`: Maps from `family_name` or `last_name` - `avatar`: Maps from `picture` or `avatar_url` -:::info no-title +:::info You can customize how third-party data maps to your profile fields by overriding the function `getFieldValueFromThirdPartyUserInfo`. ```typescript @@ -202,8 +201,7 @@ SuperTokens.init({ }); ``` -:::info -The user profile page gets rendered by default on the `/user/profile` path. +:::info[The user profile page gets rendered by default on the `/user/profile` path.] If you want to change the path, you have to initialize the `profile-base-react` plugin with the `profilePagePath` option. ```typescript @@ -238,7 +236,7 @@ You should see the new interface that renders the profile data. Progressive profiling setup interface ## Customization @@ -313,40 +311,20 @@ function CustomProfileComponent() { Besides profile details management, you can also explore other user management features: - - - - Progressive Profiling - - - Gradually collect user information through customizable forms. - - - - - - User Banning - - - Implement user banning functionality to restrict access. - - - - - - User Roles - - - Implement role-based access control for your users. - - - - - - Plugins Reference - - - General information on how plugins work. - - - + + +Gradually collect user information through customizable forms. + + + +Implement user banning functionality to restrict access. + + + +Implement role-based access control for your users. + + + +General information on how plugins work. + + diff --git a/docs/quickstart/_blocks/angular-app-component.mdx b/docs/quickstart/_blocks/angular-app-component.mdx deleted file mode 100644 index ce6992ae3d..0000000000 --- a/docs/quickstart/_blocks/angular-app-component.mdx +++ /dev/null @@ -1,13 +0,0 @@ - ```tsx title="/app/app.component.ts" - import SuperTokens from "supertokens-web-js"; - import Session from "supertokens-web-js/recipe/session"; - - SuperTokens.init({ - appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - }, - recipeList: [Session.init()], - }); - ``` diff --git a/docs/quickstart/_blocks/angular-auth-component.mdx b/docs/quickstart/_blocks/angular-auth-component.mdx deleted file mode 100644 index 59140a8006..0000000000 --- a/docs/quickstart/_blocks/angular-auth-component.mdx +++ /dev/null @@ -1,59 +0,0 @@ - ```tsx title="/app/auth/auth.component.ts" - import { init as supertokensUIInit } from "supertokens-auth-react-script"; - import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; - import supertokensUISession from "supertokens-auth-react-script/recipe/session"; - import { - Component, - OnDestroy, - AfterViewInit, - Renderer2, - Inject, - } from "@angular/core"; - import { DOCUMENT } from "@angular/common"; - - @Component({ - selector: "app-auth", - template: '
', - }) - export class AuthComponent implements OnDestroy, AfterViewInit { - constructor( - private renderer: Renderer2, - @Inject(DOCUMENT) private document: Document, - ) {} - - ngAfterViewInit() { - this.loadScript("^{prebuiltUIVersion}"); - } - - ngOnDestroy() { - // Remove the script when the component is destroyed - const script = this.document.getElementById("supertokens-script"); - if (script) { - script.remove(); - } - } - - private loadScript(src: string) { - const script = this.renderer.createElement("script"); - script.type = "text/javascript"; - script.src = src; - script.id = "supertokens-script"; - script.onload = () => { - supertokensUIInit({ - appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", - }, - recipeList: [ - supertokensUIEmailPassword.init(), - supertokensUISession.init(), - ], - }); - }; - this.renderer.appendChild(this.document.body, script); - } - } - ``` diff --git a/docs/quickstart/_blocks/angular-routing.mdx b/docs/quickstart/_blocks/angular-routing.mdx deleted file mode 100644 index c93b225c02..0000000000 --- a/docs/quickstart/_blocks/angular-routing.mdx +++ /dev/null @@ -1,26 +0,0 @@ -```tsx title="/app/app-routing.module.ts" -import { NgModule } from "@angular/core"; -import { RouterModule, Routes } from "@angular/router"; - -const routes: Routes = [ - // highlight-start - { - path: "^{appInfo.websiteBasePath_withoutForwardSlash}", - // @ts-ignore - loadChildren: () => import("./auth/auth.module").then((m) => m.AuthModule), - }, - - { - path: "**", - // @ts-ignore - loadChildren: () => import("./home/home.module").then((m) => m.HomeModule), - }, - // highlight-end -]; - -@NgModule({ - imports: [RouterModule.forRoot(routes)], - exports: [RouterModule], -}) -export class AppRoutingModule {} -``` diff --git a/docs/quickstart/_blocks/curl-sign-in.mdx b/docs/quickstart/_blocks/curl-sign-in.mdx deleted file mode 100644 index 842e57b5ce..0000000000 --- a/docs/quickstart/_blocks/curl-sign-in.mdx +++ /dev/null @@ -1,14 +0,0 @@ - -```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signin' \ ---header 'Content-Type: application/json; charset=utf-8' \ ---data-raw '{ - "formFields": [{ - "id": "email", - "value": "john@example.com" - }, { - "id": "password", - "value": "somePassword123" - }] -}' -``` diff --git a/docs/quickstart/_blocks/flutter-custom-client-session.mdx b/docs/quickstart/_blocks/flutter-custom-client-session.mdx deleted file mode 100644 index 6856a9b4ad..0000000000 --- a/docs/quickstart/_blocks/flutter-custom-client-session.mdx +++ /dev/null @@ -1,17 +0,0 @@ - -```dart -// Import http from the SuperTokens package -import 'package:supertokens_flutter/http.dart' as http; - -Future makeRequest() async { - Uri uri = Uri.parse("http://localhost:3001/api"); - - // Initialise your custom client - var customClient = http.Client(); - // provide your custom client to SuperTokens - var httpClient = http.Client(client: customClient); - - var response = await httpClient.get(uri); - // handle response -} -``` diff --git a/docs/quickstart/_blocks/flutter-dio-request-example.mdx b/docs/quickstart/_blocks/flutter-dio-request-example.mdx deleted file mode 100644 index f026fc0781..0000000000 --- a/docs/quickstart/_blocks/flutter-dio-request-example.mdx +++ /dev/null @@ -1,15 +0,0 @@ - -```dart -import 'package:supertokens_flutter/dio.dart'; -import 'package:dio/dio.dart'; - -void setup() { - Dio dio = Dio( - // Provide your config here - ); - dio.addSupertokensInterceptor(); - - var response = dio.get("http://localhost:3001/api"); - // handle response -} -``` diff --git a/docs/quickstart/_blocks/flutter-dio-session.mdx b/docs/quickstart/_blocks/flutter-dio-session.mdx deleted file mode 100644 index f5ab2aefa4..0000000000 --- a/docs/quickstart/_blocks/flutter-dio-session.mdx +++ /dev/null @@ -1,10 +0,0 @@ - -```dart -import 'package:supertokens_flutter/dio.dart'; -import 'package:dio/dio.dart'; - -void setup() { - Dio dio = Dio(); // Create a Dio instance. - dio.addSupertokensInterceptor(); -} -``` diff --git a/docs/quickstart/_blocks/flutter-http-session.mdx b/docs/quickstart/_blocks/flutter-http-session.mdx deleted file mode 100644 index 56b8cbde21..0000000000 --- a/docs/quickstart/_blocks/flutter-http-session.mdx +++ /dev/null @@ -1,11 +0,0 @@ - -```dart -// Import http from the SuperTokens package -import 'package:supertokens_flutter/http.dart' as http; - -Future makeRequest() async { - Uri uri = Uri.parse("http://localhost:3001/api"); - var response = await http.get(uri); - // handle response -} -``` diff --git a/docs/quickstart/_blocks/go-sdk-init.mdx b/docs/quickstart/_blocks/go-sdk-init.mdx deleted file mode 100644 index 8ccd3a1814..0000000000 --- a/docs/quickstart/_blocks/go-sdk-init.mdx +++ /dev/null @@ -1,37 +0,0 @@ - - ```go - import ( - "github.com/supertokens/supertokens-golang/recipe/emailpassword" - "github.com/supertokens/supertokens-golang/recipe/session" - "github.com/supertokens/supertokens-golang/supertokens" - ) - - func main() { - apiBasePath := "^{appInfo.apiBasePath}" - websiteBasePath := "^{appInfo.websiteBasePath}" - err := supertokens.Init(supertokens.TypeInput{ - Supertokens: &supertokens.ConnectionInfo{ - // We use try.supertokens for demo purposes. - // At the end of the tutorial we will show you how to create - // your own SuperTokens core instance and then update your config. - ConnectionURI: "https://try.supertokens.io^{derived.appIdPathname}", - // APIKey: - }, - AppInfo: supertokens.AppInfo{ - AppName: "^{appInfo.appName}", - APIDomain: "^{appInfo.apiDomain}", - WebsiteDomain: "^{appInfo.websiteDomain}", - APIBasePath: &apiBasePath, - WebsiteBasePath: &websiteBasePath, - }, - RecipeList: []supertokens.Recipe{ - emailpassword.Init(nil), - session.Init(nil), - }, - }) - - if err != nil { - panic(err.Error()) - } - } - ``` diff --git a/docs/quickstart/_blocks/kotlin-http-urlconnection-session.mdx b/docs/quickstart/_blocks/kotlin-http-urlconnection-session.mdx deleted file mode 100644 index 8ab7cbbf46..0000000000 --- a/docs/quickstart/_blocks/kotlin-http-urlconnection-session.mdx +++ /dev/null @@ -1,30 +0,0 @@ - -```kotlin -import android.app.Application -import com.supertokens.session.SuperTokens -import com.supertokens.session.SuperTokensHttpURLConnection -import com.supertokens.session.SuperTokensPersistentCookieStore -import java.net.URL -import java.net.HttpURLConnection - -class MainApplication: Application() { - override fun onCreate() { - super.onCreate() - // TODO: Make sure to call SuperTokens.init - } - - fun makeRequest() { - val url = URL("") - val connection = SuperTokensHttpURLConnection.newRequest(url, object: SuperTokensHttpURLConnection.PreConnectCallback { - override fun doAction(con: HttpURLConnection?) { - // TODO: Use `con` to set request method, headers etc - } - }) - - // Handle response using connection object, for example: - if (connection.responseCode == 200) { - // TODO: implement - } - } -} -``` diff --git a/docs/quickstart/_blocks/kotlin-okhttp-session.mdx b/docs/quickstart/_blocks/kotlin-okhttp-session.mdx deleted file mode 100644 index 02315079da..0000000000 --- a/docs/quickstart/_blocks/kotlin-okhttp-session.mdx +++ /dev/null @@ -1,31 +0,0 @@ - -```kotlin -import android.content.Context -import com.supertokens.session.SuperTokens -import com.supertokens.session.SuperTokensInterceptor -import okhttp3.OkHttpClient -import retrofit2.Retrofit - -class NetworkManager { - fun getClient(context: Context): OkHttpClient { - val clientBuilder = OkHttpClient.Builder() - clientBuilder.addInterceptor(SuperTokensInterceptor()) - // TODO: Make sure to call SuperTokens.init - - val client = clientBuilder.build() - - // REQUIRED FOR RETROFIT ONLY - val instance = Retrofit.Builder() - .baseUrl("") - .client(client) - .build() - - return client - } - - fun makeRequest(context: Context) { - val client = getClient(context) - // Use client to make requests normally - } -} -``` diff --git a/docs/quickstart/_blocks/kotlin-sdk-init.mdx b/docs/quickstart/_blocks/kotlin-sdk-init.mdx deleted file mode 100644 index f8ee5ff79f..0000000000 --- a/docs/quickstart/_blocks/kotlin-sdk-init.mdx +++ /dev/null @@ -1,17 +0,0 @@ - - -```kotlin -import android.app.Application -import com.supertokens.session.SuperTokens - -class MainApplication: Application() { - override fun onCreate() { - super.onCreate() - - SuperTokens.Builder(this, "^{appInfo.apiDomain}") - .apiBasePath("^{appInfo.apiBasePath}") - .build() - } -} -``` - diff --git a/docs/quickstart/_blocks/node-express-sdk-init.mdx b/docs/quickstart/_blocks/node-express-sdk-init.mdx deleted file mode 100644 index 3c8525d21d..0000000000 --- a/docs/quickstart/_blocks/node-express-sdk-init.mdx +++ /dev/null @@ -1,30 +0,0 @@ - -```tsx -import supertokens from "supertokens-node"; -import Session from "supertokens-node/recipe/session"; -import EmailPassword from "supertokens-node/recipe/emailpassword"; - -supertokens.init({ - framework: "express", - supertokens: { - // We use try.supertokens for demo purposes. - // At the end of the tutorial we will show you how to create - // your own SuperTokens core instance and then update your config. - connectionURI: "https://try.supertokens.io^{derived.appIdPathname}", - // apiKey: - }, - appInfo: { - // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", - }, - recipeList: [ - EmailPassword.init(), // initializes signin / sign up features - Session.init() // initializes session features - ] -}); - -``` diff --git a/docs/quickstart/_blocks/node-fastify-sdk-init.mdx b/docs/quickstart/_blocks/node-fastify-sdk-init.mdx deleted file mode 100644 index d287da80c6..0000000000 --- a/docs/quickstart/_blocks/node-fastify-sdk-init.mdx +++ /dev/null @@ -1,30 +0,0 @@ - -```tsx -import supertokens from "supertokens-node"; -import Session from "supertokens-node/recipe/session"; -import EmailPassword from "supertokens-node/recipe/emailpassword"; - -supertokens.init({ - framework: "fastify", - supertokens: { - // We use try.supertokens for demo purposes. - // At the end of the tutorial we will show you how to create - // your own SuperTokens core instance and then update your config. - connectionURI: "https://try.supertokens.io^{derived.appIdPathname}", - // apiKey: - }, - appInfo: { - // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", - }, - recipeList: [ - EmailPassword.init(), // initializes signin / sign up features - Session.init() // initializes session features - ] -}); -``` - diff --git a/docs/quickstart/_blocks/node-hapi-sdk-init.mdx b/docs/quickstart/_blocks/node-hapi-sdk-init.mdx deleted file mode 100644 index a42b175c99..0000000000 --- a/docs/quickstart/_blocks/node-hapi-sdk-init.mdx +++ /dev/null @@ -1,30 +0,0 @@ - -```tsx -import supertokens from "supertokens-node"; -import Session from "supertokens-node/recipe/session"; -import EmailPassword from "supertokens-node/recipe/emailpassword"; - -supertokens.init({ - framework: "hapi", - supertokens: { - // We use try.supertokens for demo purposes. - // At the end of the tutorial we will show you how to create - // your own SuperTokens core instance and then update your config. - connectionURI: "https://try.supertokens.io^{derived.appIdPathname}", - // apiKey: - }, - appInfo: { - // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", - }, - recipeList: [ - EmailPassword.init(), // initializes signin / sign up features - Session.init() // initializes session features - ] -}); -``` - diff --git a/docs/quickstart/_blocks/node-koa-sdk-init.mdx b/docs/quickstart/_blocks/node-koa-sdk-init.mdx deleted file mode 100644 index 1fc76bec16..0000000000 --- a/docs/quickstart/_blocks/node-koa-sdk-init.mdx +++ /dev/null @@ -1,30 +0,0 @@ - -```tsx -import supertokens from "supertokens-node"; -import Session from "supertokens-node/recipe/session"; -import EmailPassword from "supertokens-node/recipe/emailpassword"; - -supertokens.init({ - framework: "koa", - supertokens: { - // We use try.supertokens for demo purposes. - // At the end of the tutorial we will show you how to create - // your own SuperTokens core instance and then update your config. - connectionURI: "https://try.supertokens.io^{derived.appIdPathname}", - // apiKey: - }, - appInfo: { - // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", - }, - recipeList: [ - EmailPassword.init(), // initializes signin / sign up features - Session.init() // initializes session features - ] -}); -``` - diff --git a/docs/quickstart/_blocks/node-loopback-sdk-init.mdx b/docs/quickstart/_blocks/node-loopback-sdk-init.mdx deleted file mode 100644 index feaac7b93d..0000000000 --- a/docs/quickstart/_blocks/node-loopback-sdk-init.mdx +++ /dev/null @@ -1,30 +0,0 @@ - -```tsx -import supertokens from "supertokens-node"; -import Session from "supertokens-node/recipe/session"; -import EmailPassword from "supertokens-node/recipe/emailpassword"; - -supertokens.init({ - framework: "loopback", - supertokens: { - // We use try.supertokens for demo purposes. - // At the end of the tutorial we will show you how to create - // your own SuperTokens core instance and then update your config. - connectionURI: "https://try.supertokens.io^{derived.appIdPathname}", - // apiKey: - }, - appInfo: { - // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", - }, - recipeList: [ - EmailPassword.init(), // initializes signin / sign up features - Session.init() // initializes session features - ] -}); -``` - diff --git a/docs/quickstart/_blocks/python-django-sdk-init.mdx b/docs/quickstart/_blocks/python-django-sdk-init.mdx deleted file mode 100644 index e369ad9c95..0000000000 --- a/docs/quickstart/_blocks/python-django-sdk-init.mdx +++ /dev/null @@ -1,28 +0,0 @@ - -```python -from supertokens_python import init, InputAppInfo, SupertokensConfig -from supertokens_python.recipe import emailpassword, session - -init( - app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" - ), - supertokens_config=SupertokensConfig( - # We use try.supertokens for demo purposes. - # At the end of the tutorial we will show you how to create - # your own SuperTokens core instance and then update your config. - connection_uri="https://try.supertokens.io^{derived.appIdPathname}", - # api_key: - ), - framework='django', - recipe_list=[ - session.init(), # initializes session features - emailpassword.init() - ], - mode='asgi' # use wsgi if you are running django server in sync mode -) -``` diff --git a/docs/quickstart/_blocks/python-fastapi-sdk-init.mdx b/docs/quickstart/_blocks/python-fastapi-sdk-init.mdx deleted file mode 100644 index 953ca6c4ff..0000000000 --- a/docs/quickstart/_blocks/python-fastapi-sdk-init.mdx +++ /dev/null @@ -1,28 +0,0 @@ - -```python -from supertokens_python import init, InputAppInfo, SupertokensConfig -from supertokens_python.recipe import emailpassword, session - -init( - app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" - ), - supertokens_config=SupertokensConfig( - # We use try.supertokens for demo purposes. - # At the end of the tutorial we will show you how to create - # your own SuperTokens core instance and then update your config. - connection_uri="https://try.supertokens.io^{derived.appIdPathname}", - # api_key: - ), - framework='fastapi', - recipe_list=[ - session.init(), # initializes session features - emailpassword.init() - ], - mode='asgi' # use wsgi if you are running using gunicorn -) -``` diff --git a/docs/quickstart/_blocks/python-flask-sdk-init.mdx b/docs/quickstart/_blocks/python-flask-sdk-init.mdx deleted file mode 100644 index b36c3f16a2..0000000000 --- a/docs/quickstart/_blocks/python-flask-sdk-init.mdx +++ /dev/null @@ -1,27 +0,0 @@ - -```python -from supertokens_python import init, InputAppInfo, SupertokensConfig -from supertokens_python.recipe import emailpassword, session - -init( - app_info=InputAppInfo( - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}" - ), - supertokens_config=SupertokensConfig( - # We use try.supertokens for demo purposes. - # At the end of the tutorial we will show you how to create - # your own SuperTokens core instance and then update your config. - connection_uri="https://try.supertokens.io^{derived.appIdPathname}", - # api_key: - ), - framework='flask', - recipe_list=[ - session.init(), # initializes session features - emailpassword.init() - ] -) -``` diff --git a/docs/quickstart/_blocks/react-no-router.mdx b/docs/quickstart/_blocks/react-no-router.mdx deleted file mode 100644 index 438a479fa4..0000000000 --- a/docs/quickstart/_blocks/react-no-router.mdx +++ /dev/null @@ -1,23 +0,0 @@ - -```tsx -import React from 'react'; -import { EmailPasswordPreBuiltUI } from 'supertokens-auth-react/recipe/emailpassword/prebuiltui'; -import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; -import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; - -class App extends React.Component { - render() { - // highlight-start - if (canHandleRoute([EmailPasswordPreBuiltUI])) { - // This renders the login UI on the ^{appInfo.websiteBasePath} route - return getRoutingComponent([EmailPasswordPreBuiltUI]) - } - // highlight-end - - return ( - {/*Your app*/} - ); - } - -} -``` diff --git a/docs/quickstart/_blocks/react-router-v5.mdx b/docs/quickstart/_blocks/react-router-v5.mdx deleted file mode 100644 index 31f0433b52..0000000000 --- a/docs/quickstart/_blocks/react-router-v5.mdx +++ /dev/null @@ -1,34 +0,0 @@ - -```tsx -import React from 'react'; -import { - BrowserRouter, - Switch, - Route, - Link -} from "react-router-dom5"; - -// highlight-next-line -import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; -import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; -import { EmailPasswordPreBuiltUI } from 'supertokens-auth-react/recipe/emailpassword/prebuiltui'; -import * as reactRouterDom from "react-router-dom"; - - -class App extends React.Component { - render() { - return ( - - - - {/*This renders the login UI on the ^{appInfo.websiteBasePath} route*/} - // highlight-next-line - {getSuperTokensRoutesForReactRouterDom(reactRouterDom, [EmailPasswordPreBuiltUI])} - {/*Your app routes*/} - - - - ); - } -} -``` diff --git a/docs/quickstart/_blocks/react-router-v6.mdx b/docs/quickstart/_blocks/react-router-v6.mdx deleted file mode 100644 index 8902af13af..0000000000 --- a/docs/quickstart/_blocks/react-router-v6.mdx +++ /dev/null @@ -1,33 +0,0 @@ - -```tsx -import React from 'react'; -import { - BrowserRouter, - Routes, - Route, - Link -} from "react-router-dom"; - -// highlight-next-line -import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; -import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; -import { EmailPasswordPreBuiltUI } from 'supertokens-auth-react/recipe/emailpassword/prebuiltui'; -import * as reactRouterDom from "react-router-dom"; - -class App extends React.Component { - render() { - return ( - - - - {/*This renders the login UI on the ^{appInfo.websiteBasePath} route*/} - // highlight-next-line - {getSuperTokensRoutesForReactRouterDom(reactRouterDom, [EmailPasswordPreBuiltUI])} - {/*Your app routes*/} - - - - ); - } -} -``` diff --git a/docs/quickstart/_blocks/react-sdk-init.mdx b/docs/quickstart/_blocks/react-sdk-init.mdx deleted file mode 100644 index 8676695ca0..0000000000 --- a/docs/quickstart/_blocks/react-sdk-init.mdx +++ /dev/null @@ -1,35 +0,0 @@ - -```tsx -import React from "react"; - -// highlight-start -import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; -import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; -import Session from "supertokens-auth-react/recipe/session"; - -SuperTokens.init({ - appInfo: { - // learn more about this on https://supertokens.com/docs/references/frontend-sdks/reference#sdk-configuration - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", - }, - recipeList: [EmailPassword.init(), Session.init()], -}); -// highlight-end - -/* Your App */ -class App extends React.Component { - render() { - return ( - // highlight-next-line - - {/*Your app components*/} - // highlight-next-line - - ); - } -} -``` diff --git a/docs/quickstart/_blocks/swift-almorife.mdx b/docs/quickstart/_blocks/swift-almorife.mdx deleted file mode 100644 index 8d045b3652..0000000000 --- a/docs/quickstart/_blocks/swift-almorife.mdx +++ /dev/null @@ -1,18 +0,0 @@ - - -```swift -import Foundation -import SuperTokensIOS -import Alamofire - -fileprivate class NetworkManager { - func setupSuperTokensInterceptor() { - let configuration = URLSessionConfiguration.af.default - configuration.protocolClasses = [SuperTokensURLProtocol.self] + (configuration.protocolClasses ?? []) - let session = Session(configuration: configuration) - - // Use session when making network requests - } -} -``` - diff --git a/docs/quickstart/_blocks/swift-sdk-init.mdx b/docs/quickstart/_blocks/swift-sdk-init.mdx deleted file mode 100644 index 791cb868ff..0000000000 --- a/docs/quickstart/_blocks/swift-sdk-init.mdx +++ /dev/null @@ -1,24 +0,0 @@ - -```swift -import UIKit -import SuperTokensIOS - -fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - do { - try SuperTokens.initialize( - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}" - ) - } catch SuperTokensError.initError(let message) { - // TODO: Handle initialization error - } catch { - // Some other error - } - - return true - } - -} -``` diff --git a/docs/quickstart/_blocks/swift-url-session-instance.mdx b/docs/quickstart/_blocks/swift-url-session-instance.mdx deleted file mode 100644 index bbadd409f5..0000000000 --- a/docs/quickstart/_blocks/swift-url-session-instance.mdx +++ /dev/null @@ -1,15 +0,0 @@ - -```swift -import Foundation -import SuperTokensIOS - -fileprivate class NetworkManager { - func setupSuperTokensInterceptor() { - let configuration = URLSessionConfiguration.default - configuration.protocolClasses = [SuperTokensURLProtocol.self] - let session = URLSession(configuration: configuration) - - // Use session when making network requests - } -} -``` diff --git a/docs/quickstart/_blocks/swift-urlsession-shared.mdx b/docs/quickstart/_blocks/swift-urlsession-shared.mdx deleted file mode 100644 index 9a770c1103..0000000000 --- a/docs/quickstart/_blocks/swift-urlsession-shared.mdx +++ /dev/null @@ -1,11 +0,0 @@ - -```swift -import Foundation -import SuperTokensIOS - -fileprivate class NetworkManager { - func setupSuperTokensInterceptor() { - URLProtocol.registerClass(SuperTokensURLProtocol.self) - } -} -``` diff --git a/docs/quickstart/_blocks/vanilla-js-npm-check-email.mdx b/docs/quickstart/_blocks/vanilla-js-npm-check-email.mdx deleted file mode 100644 index 34c0c73d05..0000000000 --- a/docs/quickstart/_blocks/vanilla-js-npm-check-email.mdx +++ /dev/null @@ -1,23 +0,0 @@ - -```tsx -import { doesEmailExist } from "supertokens-web-js/recipe/emailpassword"; - -async function checkEmail(email: string) { - try { - let response = await doesEmailExist({ - email - }); - - if (response.doesExist) { - window.alert("Email already exists. Please sign in instead") - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` diff --git a/docs/quickstart/_blocks/vanilla-js-npm-sdk-init.mdx b/docs/quickstart/_blocks/vanilla-js-npm-sdk-init.mdx deleted file mode 100644 index 2c8f6fc6ff..0000000000 --- a/docs/quickstart/_blocks/vanilla-js-npm-sdk-init.mdx +++ /dev/null @@ -1,18 +0,0 @@ - -```tsx -import SuperTokens from 'supertokens-web-js'; -import Session from 'supertokens-web-js/recipe/session'; -import EmailPassword from 'supertokens-web-js/recipe/emailpassword' - -SuperTokens.init({ - appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - appName: "...", - }, - recipeList: [ - Session.init(), - EmailPassword.init(), - ], -}); -``` diff --git a/docs/quickstart/_blocks/vanilla-js-npm-sign-in.mdx b/docs/quickstart/_blocks/vanilla-js-npm-sign-in.mdx deleted file mode 100644 index bf459d8a1d..0000000000 --- a/docs/quickstart/_blocks/vanilla-js-npm-sign-in.mdx +++ /dev/null @@ -1,45 +0,0 @@ - -```tsx -import { signIn } from "supertokens-web-js/recipe/emailpassword"; - -async function signInClicked(email: string, password: string) { - try { - let response = await signIn({ - formFields: [{ - id: "email", - value: email - }, { - id: "password", - value: password - }] - }) - - if (response.status === "FIELD_ERROR") { - response.formFields.forEach(formField => { - if (formField.id === "email") { - // Email validation failed (for example incorrect email syntax). - window.alert(formField.error) - } - }) - } else if (response.status === "WRONG_CREDENTIALS_ERROR") { - window.alert("Email password combination is incorrect.") - } else if (response.status === "SIGN_IN_NOT_ALLOWED") { - // the reason string is a user friendly message - // about what went wrong. It can also contain a support code which users - // can tell you so you know why their sign in was not allowed. - window.alert(response.reason) - } else { - // sign in successful. The session tokens are automatically handled by - // the frontend SDK. - window.location.href = "/homepage" - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` diff --git a/docs/quickstart/_blocks/vanilla-js-npm-sign-up.mdx b/docs/quickstart/_blocks/vanilla-js-npm-sign-up.mdx deleted file mode 100644 index 22f35d6514..0000000000 --- a/docs/quickstart/_blocks/vanilla-js-npm-sign-up.mdx +++ /dev/null @@ -1,49 +0,0 @@ - -```tsx -import { signUp } from "supertokens-web-js/recipe/emailpassword"; - -async function signUpClicked(email: string, password: string) { - try { - let response = await signUp({ - formFields: [{ - id: "email", - value: email - }, { - id: "password", - value: password - }] - }) - - if (response.status === "FIELD_ERROR") { - // one of the input formFields failed validation - response.formFields.forEach(formField => { - if (formField.id === "email") { - // Email validation failed (for example incorrect email syntax), - // or the email is not unique. - window.alert(formField.error) - } else if (formField.id === "password") { - // Password validation failed. - // Maybe it didn't match the password strength - window.alert(formField.error) - } - }) - } else if (response.status === "SIGN_UP_NOT_ALLOWED") { - // the reason string is a user friendly message - // about what went wrong. It can also contain a support code which users - // can tell you so you know why their sign up was not allowed. - window.alert(response.reason) - } else { - // sign up successful. The session tokens are automatically handled by - // the frontend SDK. - window.location.href = "/homepage" - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` diff --git a/docs/quickstart/_blocks/vanilla-js-script-check-email.mdx b/docs/quickstart/_blocks/vanilla-js-script-check-email.mdx deleted file mode 100644 index 892669e59a..0000000000 --- a/docs/quickstart/_blocks/vanilla-js-script-check-email.mdx +++ /dev/null @@ -1,22 +0,0 @@ - -```tsx -import supertokensEmailPassword from "supertokens-web-js-script/recipe/emailpassword"; -async function checkEmail(email: string) { - try { - let response = await supertokensEmailPassword.doesEmailExist({ - email - }); - - if (response.doesExist) { - window.alert("Email already exists. Please sign in instead") - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` diff --git a/docs/quickstart/_blocks/vanilla-js-script-sdk-init.mdx b/docs/quickstart/_blocks/vanilla-js-script-sdk-init.mdx deleted file mode 100644 index 01906e7391..0000000000 --- a/docs/quickstart/_blocks/vanilla-js-script-sdk-init.mdx +++ /dev/null @@ -1,17 +0,0 @@ - -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensEmailPassword from 'supertokens-web-js-script/recipe/emailpassword' -supertokens.init({ - appInfo: { - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - appName: "...", - }, - recipeList: [ - supertokensSession.init(), - supertokensEmailPassword.init(), - ], -}); -``` diff --git a/docs/quickstart/_blocks/vanilla-js-script-sign-in.mdx b/docs/quickstart/_blocks/vanilla-js-script-sign-in.mdx deleted file mode 100644 index a061d41f34..0000000000 --- a/docs/quickstart/_blocks/vanilla-js-script-sign-in.mdx +++ /dev/null @@ -1,45 +0,0 @@ - -```tsx -import supertokensEmailPassword from "supertokens-web-js-script/recipe/emailpassword"; -async function signInClicked(email: string, password: string) { - try { - let response = await supertokensEmailPassword.signIn({ - formFields: [{ - id: "email", - value: email - }, { - id: "password", - value: password - }] - }) - - if (response.status === "FIELD_ERROR") { - // one of the input formFields failed validation - response.formFields.forEach(formField => { - if (formField.id === "email") { - // Email validation failed (for example incorrect email syntax). - window.alert(formField.error) - } - }) - } else if (response.status === "WRONG_CREDENTIALS_ERROR") { - window.alert("Email password combination is incorrect.") - } else if (response.status === "SIGN_IN_NOT_ALLOWED") { - // the reason string is a user friendly message - // about what went wrong. It can also contain a support code which users - // can tell you so you know why their sign in was not allowed. - window.alert(response.reason) - } else { - // sign in successful. The session tokens are automatically handled by - // the frontend SDK. - window.location.href = "/homepage" - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` diff --git a/docs/quickstart/_blocks/vanilla-js-script-sign-up.mdx b/docs/quickstart/_blocks/vanilla-js-script-sign-up.mdx deleted file mode 100644 index ce7435d747..0000000000 --- a/docs/quickstart/_blocks/vanilla-js-script-sign-up.mdx +++ /dev/null @@ -1,48 +0,0 @@ - -```tsx -import supertokensEmailPassword from "supertokens-web-js-script/recipe/emailpassword"; -async function signUpClicked(email: string, password: string) { - try { - let response = await supertokensEmailPassword.signUp({ - formFields: [{ - id: "email", - value: email - }, { - id: "password", - value: password - }] - }) - - if (response.status === "FIELD_ERROR") { - // one of the input formFields failed validation - response.formFields.forEach(formField => { - if (formField.id === "email") { - // Email validation failed (for example incorrect email syntax), - // or the email is not unique. - window.alert(formField.error) - } else if (formField.id === "password") { - // Password validation failed. - // Maybe it didn't match the password strength - window.alert(formField.error) - } - }) - } else if (response.status === "SIGN_UP_NOT_ALLOWED") { - // the reason string is a user friendly message - // about what went wrong. It can also contain a support code which users - // can tell you so you know why their sign in was not allowed. - window.alert(response.reason) - } else { - // sign up successful. The session tokens are automatically handled by - // the frontend SDK. - window.location.href = "/homepage" - } - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - window.alert(err.message); - } else { - window.alert("Oops! Something went wrong."); - } - } -} -``` diff --git a/docs/quickstart/_blocks/vue-auth-view.mdx b/docs/quickstart/_blocks/vue-auth-view.mdx deleted file mode 100644 index d0031c55bd..0000000000 --- a/docs/quickstart/_blocks/vue-auth-view.mdx +++ /dev/null @@ -1,50 +0,0 @@ - - ```tsx - import {init as supertokensUIInit} from "supertokens-auth-react-script"; - import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; - import supertokensUISession from "supertokens-auth-react-script/recipe/session"; - - - - ``` diff --git a/docs/quickstart/_blocks/vue-main-file.mdx b/docs/quickstart/_blocks/vue-main-file.mdx deleted file mode 100644 index fcced61928..0000000000 --- a/docs/quickstart/_blocks/vue-main-file.mdx +++ /dev/null @@ -1,26 +0,0 @@ - - ```tsx title="/main.ts " - // @ts-ignore - import { createApp } from "vue"; - import SuperTokens from "supertokens-web-js"; - import Session from "supertokens-web-js/recipe/session"; - // @ts-ignore - import App from "./App.vue"; - // @ts-ignore - import router from "./router"; - - SuperTokens.init({ - appInfo: { - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - }, - recipeList: [Session.init()], - }); - - const app = createApp(App); - - app.use(router); - - app.mount("#app"); - ``` diff --git a/docs/quickstart/_blocks/vue-routing.mdx b/docs/quickstart/_blocks/vue-routing.mdx deleted file mode 100644 index 5b77a0892d..0000000000 --- a/docs/quickstart/_blocks/vue-routing.mdx +++ /dev/null @@ -1,29 +0,0 @@ - -```tsx title="/router/index.ts" -// @ts-ignore -import { createRouter, createWebHistory } from "vue-router"; -// @ts-ignore -import HomeView from "../views/HomeView.vue"; -// @ts-ignore -import AuthView from "../views/AuthView.vue"; - -const router = createRouter({ - // @ts-ignore - history: createWebHistory(import.meta.env.BASE_URL), - routes: [ - { - path: "/", - name: "home", - component: HomeView, - }, - { - path: "^{appInfo.websiteBasePath}/:pathMatch(.*)*", - name: "auth", - component: AuthView, - }, - ], -}); - -export default router; -``` - diff --git a/docs/quickstart/_category_.json b/docs/quickstart/_category_.json deleted file mode 100644 index 7590589946..0000000000 --- a/docs/quickstart/_category_.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "label": "Quickstart", - "collapsible": true, - "collapsed": false, - "customProps": { - "isMainCategory": true - }, - "position": 2 -} diff --git a/docs/quickstart/backend-setup.mdx b/docs/quickstart/backend-setup.mdx index 0845ed3296..bb6ade554b 100644 --- a/docs/quickstart/backend-setup.mdx +++ b/docs/quickstart/backend-setup.mdx @@ -1,124 +1,351 @@ --- -id: backend-setup title: Backend Setup -hide_title: true -sidebar_position: 3 -description: >- - Set up SuperTokens authentication for your backend using Node.js, Python, or - Go SDKs. -page_type: tutorial -category: quickstart +description: Set up SuperTokens authentication for your backend using Node.js, Python, or Go SDKs. +sidebar: + order: 3 --- - -import NodeExpressSDKInit from "./_blocks/node-express-sdk-init.mdx"; -import NodeHapiSDKInit from "./_blocks/node-hapi-sdk-init.mdx"; -import NodeFastifySDKInit from "./_blocks/node-fastify-sdk-init.mdx"; -import NodeKoaSDKInit from "./_blocks/node-koa-sdk-init.mdx"; -import NodeLoopbackSDKInit from "./_blocks/node-loopback-sdk-init.mdx"; -import GoSDKInit from "./_blocks/go-sdk-init.mdx"; -import PythonFlaskSDKInit from "./_blocks/python-flask-sdk-init.mdx"; -import PythonDjangoSDKInit from "./_blocks/python-django-sdk-init.mdx"; -import PythonFastAPISDKInit from "./_blocks/python-fastapi-sdk-init.mdx"; - -# Backend Setup - Let's go through the changes required so that your backend can expose the **SuperTokens** authentication features. ## 1. Install the SDK Run the following command in your terminal to install the package. - + - + ```bash npm i -s supertokens-node ``` - + - + ```bash go get github.com/supertokens/supertokens-golang ``` - - + + ```bash pip install supertokens-python ``` - - + + -:::info - -At the moment we only have SDKs for **Node.js**, **Python** and **Go**. +:::info[At the moment we only have SDKs for **Node.js**, **Python** and **Go**.] If you wish to use **SuperTokens** with other languages you will have to create a separate authentication service. -Please check [our guide](/docs/references/backend-sdks/other-frameworks) that shows you how to resolve this. +Please check [our guide](/references/backend-sdks/other-frameworks) that shows you how to resolve this. ::: ## 2. Initialize the SDK - You will have to initialize the **Backend SDK** alongside the code that starts your server. -The init call will include [configuration details](/docs/references/backend-sdks/reference#sdk-configuration) for your app, how the backend will connect to the **SuperTokens Core**, as well as the **Recipes** that will be used in your setup. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -:::info Multiple frontend domains +The init call will include [configuration details](/references/backend-sdks/reference#sdk-configuration) for your app, how the backend will connect to the **SuperTokens Core**, as well as the **Recipes** that will be used in your setup. + + + + + + ```tsx {325,326,327,332,354,355,356,357,358,363,391,392,393,394,395,398,399,427,428,429,433,456,457,458,463,496,497,512,550,555,556,557,558,559,560,561,562,595,600,633,634,635,636,637,638,639,667,678,700,710,715,716,717,718,751,761,796,797,830,896,897,915,916,917,918,919,920,921,922,923,939,940,941,942,943,944,945,961,962,982,983,984,985,986,987,988,989,1150,1151,1152,1167,1168,1169,1170,1171,1172,1189,1190,1191,1192,1193} +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import EmailPassword from "supertokens-node/recipe/emailpassword"; + +supertokens.init({ + framework: "express", + supertokens: { + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + connectionURI: "https://try.supertokens.io", + // apiKey: + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/session/appinfo + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [ + EmailPassword.init(), // initializes signin / sign up features + Session.init() // initializes session features + ] +}); + +``` + + + ```tsx +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import EmailPassword from "supertokens-node/recipe/emailpassword"; + +supertokens.init({ + framework: "hapi", + supertokens: { + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + connectionURI: "https://try.supertokens.io", + // apiKey: + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/session/appinfo + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [ + EmailPassword.init(), // initializes signin / sign up features + Session.init() // initializes session features + ] +}); +``` + + + ```tsx +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import EmailPassword from "supertokens-node/recipe/emailpassword"; + +supertokens.init({ + framework: "fastify", + supertokens: { + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + connectionURI: "https://try.supertokens.io", + // apiKey: + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/session/appinfo + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [ + EmailPassword.init(), // initializes signin / sign up features + Session.init() // initializes session features + ] +}); +``` + + + ```tsx +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import EmailPassword from "supertokens-node/recipe/emailpassword"; + +supertokens.init({ + framework: "koa", + supertokens: { + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + connectionURI: "https://try.supertokens.io", + // apiKey: + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/session/appinfo + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [ + EmailPassword.init(), // initializes signin / sign up features + Session.init() // initializes session features + ] +}); +``` + + + ```tsx +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import EmailPassword from "supertokens-node/recipe/emailpassword"; + +supertokens.init({ + framework: "loopback", + supertokens: { + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + connectionURI: "https://try.supertokens.io", + // apiKey: + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/session/appinfo + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [ + EmailPassword.init(), // initializes signin / sign up features + Session.init() // initializes session features + ] +}); +``` + + + + + + ```go + import ( + "github.com/supertokens/supertokens-golang/recipe/emailpassword" + "github.com/supertokens/supertokens-golang/recipe/session" + "github.com/supertokens/supertokens-golang/supertokens" + ) + + func main() { + apiBasePath := "/auth" + websiteBasePath := "/auth" + err := supertokens.Init(supertokens.TypeInput{ + Supertokens: &supertokens.ConnectionInfo{ + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + ConnectionURI: "https://try.supertokens.io", + // APIKey: + }, + AppInfo: supertokens.AppInfo{ + AppName: "", + APIDomain: "", + WebsiteDomain: "", + APIBasePath: &apiBasePath, + WebsiteBasePath: &websiteBasePath, + }, + RecipeList: []supertokens.Recipe{ + emailpassword.Init(nil), + session.Init(nil), + }, + }) + + if err != nil { + panic(err.Error()) + } + } + ``` + + + + + + ```python +from supertokens_python import init, InputAppInfo, SupertokensConfig +from supertokens_python.recipe import emailpassword, session + +init( + app_info=InputAppInfo( + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" + ), + supertokens_config=SupertokensConfig( + # We use try.supertokens for demo purposes. + # At the end of the tutorial we will show you how to create + # your own SuperTokens core instance and then update your config. + connection_uri="https://try.supertokens.io", + # api_key: + ), + framework='fastapi', + recipe_list=[ + session.init(), # initializes session features + emailpassword.init() + ], + mode='asgi' # use wsgi if you are running using gunicorn +) +``` + + + ```python +from supertokens_python import init, InputAppInfo, SupertokensConfig +from supertokens_python.recipe import emailpassword, session + +init( + app_info=InputAppInfo( + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" + ), + supertokens_config=SupertokensConfig( + # We use try.supertokens for demo purposes. + # At the end of the tutorial we will show you how to create + # your own SuperTokens core instance and then update your config. + connection_uri="https://try.supertokens.io", + # api_key: + ), + framework='flask', + recipe_list=[ + session.init(), # initializes session features + emailpassword.init() + ] +) +``` + + + ```python +from supertokens_python import init, InputAppInfo, SupertokensConfig +from supertokens_python.recipe import emailpassword, session + +init( + app_info=InputAppInfo( + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth" + ), + supertokens_config=SupertokensConfig( + # We use try.supertokens for demo purposes. + # At the end of the tutorial we will show you how to create + # your own SuperTokens core instance and then update your config. + connection_uri="https://try.supertokens.io", + # api_key: + ), + framework='django', + recipe_list=[ + session.init(), # initializes session features + emailpassword.init() + ], + mode='asgi' # use wsgi if you are running django server in sync mode +) +``` + + + + + + +:::info[Multiple frontend domains] To handle clients from different domains with the same SuperTokens instance, use the `origin` property in the `appInfo` object instead of `websiteDomain`. The property accepts a function that receives the original request as an input and should return a valid domain. Make sure to whitelist all the domains during CORS configuration. Keep in mind that with this setup, each frontend application will not share authentication sessions. Users will have to authenticate separately for each domain. -To configure a shared authentication experience between multiple services check the [Unified Login](/docs/authentication/unified-login/introduction) documentation. +To configure a shared authentication experience between multiple services check the [Unified Login](/authentication/unified-login/introduction) documentation. ::: @@ -127,21 +354,19 @@ To configure a shared authentication experience between multiple services check Now that the SDK is initialized you need to expose the endpoints that will be used by the frontend SDKs. Besides this, your server's CORS, Cross-Origin Resource Sharing, settings should be updated to allow the use of the authentication headers required by **SuperTokens**. - - - - + + + + - + -:::important - -- Add the `middleware` BEFORE all your routes. +:::note[- Add the `middleware` BEFORE all your routes.] - Add the `cors` middleware BEFORE the SuperTokens middleware as shown below. ::: - + ```tsx import express from "express"; @@ -153,29 +378,26 @@ let app = express(); app.use( cors({ - // highlight-start - origin: "^{appInfo.websiteDomain}", + origin: "", allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()], credentials: true, - // highlight-end }), ); // IMPORTANT: CORS should be before the below line. -// highlight-next-line app.use(middleware()); // ...your API routes ``` - - + + - + Register the `plugin`. - + ```tsx import Hapi from "@hapi/hapi"; @@ -185,18 +407,15 @@ import { plugin } from "supertokens-node/framework/hapi"; let server = Hapi.server({ port: 8000, routes: { - // highlight-start cors: { - origin: ["^{appInfo.websiteDomain}"], + origin: [""], additionalHeaders: [...supertokens.getAllCORSHeaders()], credentials: true, }, - // highlight-end }, }); (async () => { - // highlight-next-line await server.register(plugin); await server.start(); @@ -205,14 +424,14 @@ let server = Hapi.server({ // ...your API routes ``` - - + + - + Register the `plugin`. Also register [`@fastify/formbody`](https://github.com/fastify/fastify-formbody) plugin. - + ```tsx import cors from "@fastify/cors"; @@ -225,18 +444,14 @@ import fastifyImport from "fastify"; let fastify = fastifyImport(); // ...other middlewares -// highlight-start fastify.register(cors, { - origin: "^{appInfo.websiteDomain}", + origin: "", allowedHeaders: ["Content-Type", ...supertokens.getAllCORSHeaders()], credentials: true, }); -// highlight-end (async () => { - // highlight-next-line await fastify.register(formDataPlugin); - // highlight-next-line await fastify.register(plugin); await fastify.listen({ port: 8000 }); @@ -245,16 +460,15 @@ fastify.register(cors, { // ...your API routes ``` - - + + - + -:::important -Add the `middleware` BEFORE all your routes. +:::note[Add the `middleware` BEFORE all your routes.] ::: - + ```tsx import Koa from "koa"; @@ -266,30 +480,26 @@ let app = new Koa(); app.use( cors({ - // highlight-start - origin: "^{appInfo.websiteDomain}", + origin: "", allowHeaders: ["content-type", ...supertokens.getAllCORSHeaders()], credentials: true, - // highlight-end }), ); -// highlight-next-line app.use(middleware()); // ...your API routes ``` - - + + - + -:::important -Add the `middleware` BEFORE all your routes. +:::note[Add the `middleware` BEFORE all your routes.] ::: - + ```tsx import { RestApplication } from "@loopback/rest"; @@ -299,37 +509,34 @@ import { middleware } from "supertokens-node/framework/loopback"; let app = new RestApplication({ rest: { cors: { - // highlight-start - origin: "^{appInfo.websiteDomain}", + origin: "", allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()], credentials: true, - // highlight-end }, }, }); -// highlight-next-line app.middleware(middleware); // ...your API routes ``` - + - - + + - + - + - + - + Use the `supertokens.Middleware` and the `supertokens.GetAllCORSHeaders()` functions as shown below. - + ```go import ( @@ -342,10 +549,8 @@ import ( func main() { // SuperTokens init... - //highlight-start http.ListenAndServe("SERVER ADDRESS", corsMiddleware( supertokens.Middleware(http.HandlerFunc(func(rw http.ResponseWriter, - //highlight-end r *http.Request) { // TODO: Handle your APIs.. @@ -354,15 +559,13 @@ func main() { func corsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(response http.ResponseWriter, r *http.Request) { - response.Header().Set("Access-Control-Allow-Origin", "^{appInfo.websiteDomain}") + response.Header().Set("Access-Control-Allow-Origin", "") response.Header().Set("Access-Control-Allow-Credentials", "true") if r.Method == "OPTIONS" { // we add content-type + other headers used by SuperTokens response.Header().Set("Access-Control-Allow-Headers", strings.Join(append([]string{"Content-Type"}, - //highlight-start supertokens.GetAllCORSHeaders()...), ",")) - //highlight-end response.Header().Set("Access-Control-Allow-Methods", "*") response.Write([]byte("")) } else { @@ -372,15 +575,15 @@ func corsMiddleware(next http.Handler) http.Handler { } ``` - + - + - + Use the `supertokens.Middleware` and the `supertokens.GetAllCORSHeaders()` functions as shown below. - + ```go import ( "net/http" @@ -397,16 +600,14 @@ func main() { // CORS router.Use(cors.New(cors.Config{ - AllowOrigins: []string{"^{appInfo.websiteDomain}"}, + AllowOrigins: []string{""}, AllowMethods: []string{"GET", "POST", "DELETE", "PUT", "OPTIONS"}, AllowHeaders: append([]string{"content-type"}, - // highlight-next-line supertokens.GetAllCORSHeaders()...), AllowCredentials: true, })) // Adding the SuperTokens middleware - // highlight-start router.Use(func(c *gin.Context) { supertokens.Middleware(http.HandlerFunc( func(rw http.ResponseWriter, r *http.Request) { @@ -415,21 +616,20 @@ func main() { // we call Abort so that the next handler in the chain is not called, unless we call Next explicitly c.Abort() }) - // highlight-end // Add APIs and start server } ``` - + - + - + Use the `supertokens.Middleware` and the `supertokens.GetAllCORSHeaders()` functions as shown below. - + ```go import ( @@ -445,31 +645,29 @@ func main() { // CORS r.Use(cors.Handler(cors.Options{ - AllowedOrigins: []string{"^{appInfo.websiteDomain}"}, + AllowedOrigins: []string{""}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: append([]string{"Content-Type"}, - //highlight-next-line supertokens.GetAllCORSHeaders()...), AllowCredentials: true, })) // SuperTokens Middleware - //highlight-next-line r.Use(supertokens.Middleware) // Add APIs and start server } ``` - + - + - + Use the `supertokens.Middleware` and the `supertokens.GetAllCORSHeaders()` functions as shown below. - + ```go import ( @@ -488,33 +686,31 @@ func main() { router := mux.NewRouter() // Adding handlers.CORS(options)(supertokens.Middleware(router))) - //highlight-start http.ListenAndServe("SERVER ADDRESS", handlers.CORS( handlers.AllowedHeaders(append([]string{"Content-Type"}, supertokens.GetAllCORSHeaders()...)), handlers.AllowedMethods([]string{"GET", "POST", "PUT", "HEAD", "OPTIONS"}), - handlers.AllowedOrigins([]string{"^{appInfo.websiteDomain}"}), + handlers.AllowedOrigins([]string{""}), handlers.AllowCredentials(), )(supertokens.Middleware(router))) - //highlight-end } ``` - + - + - + - - - + + + - + Use the `Middleware` (**BEFORE all your routes**) and the `get_all_cors_headers()` functions as shown below. - + ```python from fastapi import FastAPI @@ -524,7 +720,6 @@ from supertokens_python import get_all_cors_headers from supertokens_python.framework.fastapi import get_middleware app = FastAPI() -# highlight-next-line app.add_middleware(get_middleware()) # TODO: Add APIs @@ -532,34 +727,32 @@ app.add_middleware(get_middleware()) app.add_middleware( CORSMiddleware, allow_origins=[ - "^{appInfo.websiteDomain}" + "" ], allow_credentials=True, allow_methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], - # highlight-next-line allow_headers=["Content-Type"] + get_all_cors_headers(), ) # TODO: start server ``` - - + + - + - Use the `Middleware` (**BEFORE all your routes and after calling init function**) and the `get_all_cors_headers()` functions as shown below. - Add a route to catch all paths and return a 404. This is needed because if we don't add this, then OPTIONS request for the APIs exposed by the `Middleware` will return a `404`. - + ```python from supertokens_python import get_all_cors_headers from flask import Flask, abort -from flask_cors import CORS # type: ignore +from flask_cors import CORS from supertokens_python.framework.flask import Middleware app = Flask(__name__) -# highlight-next-line Middleware(app) # TODO: Add APIs @@ -567,33 +760,30 @@ Middleware(app) CORS( app=app, origins=[ - "^{appInfo.websiteDomain}" + "" ], supports_credentials=True, - # highlight-next-line allow_headers=["Content-Type"] + get_all_cors_headers(), ) # This is required since if this is not there, then OPTIONS requests for # the APIs exposed by the supertokens' Middleware will return a 404 -# highlight-start -@app.route('/', defaults={'u_path': ''}) # type: ignore -@app.route('/') # type: ignore +@app.route('/', defaults={'u_path': ''}) +@app.route('/') def catch_all(u_path: str): abort(404) -# highlight-end # TODO: start server ``` - - + + - + Use the `Middleware` and the `get_all_cors_headers()` functions as shown below in your `settings.py`. - + ```python from typing import List @@ -603,18 +793,17 @@ from corsheaders.defaults import default_headers from supertokens_python import get_all_cors_headers CORS_ORIGIN_WHITELIST = [ - "^{appInfo.websiteDomain}" + "" ] CORS_ALLOW_CREDENTIALS = True CORS_ALLOWED_ORIGINS = [ - "^{appInfo.websiteDomain}" + "" ] CORS_ALLOW_HEADERS: List[str] = list(default_headers) + [ "Content-Type" - # highlight-next-line ] + get_all_cors_headers() INSTALLED_APPS = [ @@ -622,21 +811,20 @@ INSTALLED_APPS = [ 'supertokens_python' ] -MIDDLEWARE = [ # type: ignore +MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', ..., - # highlight-next-line 'supertokens_python.framework.django.django_middleware.middleware', ] # TODO: start server ``` - - + + - + - + You can review all the endpoints that are added through the use of **SuperTokens** by visiting the [API Specs](https://app.swaggerhub.com/apis/supertokens/FDI). @@ -645,13 +833,13 @@ You can review all the endpoints that are added through the use of **SuperTokens Depending on the language and framework that you are using, you might need to add a custom error handler to your server. The handler will catch all the authentication related errors and return proper HTTP responses that can be parsed by the frontend SDKs. - + - + - + - + ```tsx import express, { Request, Response, NextFunction } from "express"; @@ -661,10 +849,8 @@ let app = express(); // ...your API routes -// highlight-start // Add this AFTER all your routes app.use(errorHandler()); -// highlight-end // your own error handler app.use((err: unknown, req: Request, res: Response, next: NextFunction) => { @@ -672,24 +858,24 @@ app.use((err: unknown, req: Request, res: Response, next: NextFunction) => { }); ``` - - + + - + No additional `errorHandler` is required. - + - + - + - + Add the `errorHandler` **Before all your routes and plugin registration** - + ```tsx import Fastify from "fastify"; @@ -697,67 +883,64 @@ import { errorHandler } from "supertokens-node/framework/fastify"; let fastify = Fastify(); -// highlight-next-line fastify.setErrorHandler(errorHandler()); // ...your API routes ``` - + - + - + No additional `errorHandler` is required. - + - + - + - + No additional `errorHandler` is required. - + - + - + - + - + -:::info -You can skip this step +:::info[You can skip this step] ::: - - + + -:::info -You can skip this step +:::info[You can skip this step] ::: - - + + ## 5. Secure Application Routes Now that your server can authenticate users, the final step that you need to take care of is to prevent unauthorized access to certain parts of the application. - + - + For your APIs that require a user to be logged in, use the `verifySession` middleware. - + - + ```tsx import express from "express"; @@ -766,16 +949,14 @@ import { SessionRequest } from "supertokens-node/framework/express"; let app = express(); -// highlight-start app.post("/like-comment", verifySession(), (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - // highlight-end //.... }); ``` - - + + ```tsx import Hapi from "@hapi/hapi"; @@ -787,7 +968,6 @@ let server = Hapi.server({ port: 8000 }); server.route({ path: "/like-comment", method: "post", - //highlight-start options: { pre: [ { @@ -797,14 +977,13 @@ server.route({ }, handler: async (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - //highlight-end //... }, }); ``` - - + + ```tsx import Fastify from "fastify"; @@ -813,7 +992,6 @@ import { SessionRequest } from "supertokens-node/framework/fastify"; let fastify = Fastify(); -//highlight-start fastify.post( "/like-comment", { @@ -821,14 +999,13 @@ fastify.post( }, (req: SessionRequest, res) => { let userId = req.session!.getUserId(); - //highlight-end //.... }, ); ``` - - + + ```tsx import KoaRouter from "koa-router"; @@ -837,16 +1014,14 @@ import { SessionContext } from "supertokens-node/framework/koa"; let router = new KoaRouter(); -//highlight-start router.post("/like-comment", verifySession(), (ctx: SessionContext, next) => { let userId = ctx.session!.getUserId(); - //highlight-end //.... }); ``` - - + + ```tsx import { inject, intercept } from "@loopback/core"; @@ -860,7 +1035,6 @@ import { verifySession } from "supertokens-node/recipe/session/framework/loopbac import { SessionContext } from "supertokens-node/framework/loopback"; class LikeComment { - //highlight-start constructor( @inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext, ) {} @@ -869,22 +1043,21 @@ class LikeComment { @response(200) handler() { let userId = (this.ctx as SessionContext).session!.getUserId(); - //highlight-end //.... } } ``` - - + + - - + + For your APIs that require a user to be logged in, use the `VerifySession` middleware. - - + + ```go import ( @@ -911,8 +1084,8 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + ```go import ( @@ -954,8 +1127,8 @@ func likeCommentAPI(c *gin.Context) { } ``` - - + + ```go import ( @@ -983,8 +1156,8 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - - + + ```go import ( @@ -1012,16 +1185,16 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) { } ``` - + - - - + + + For your APIs that require a user to be logged in, use the `verify_session` middleware. - - + + ```python from fastapi import Depends @@ -1030,17 +1203,15 @@ from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.fastapi import verify_session -# highlight-start -@app.post('/like_comment') # type: ignore +@app.post('/like_comment') async def like_comment(session: SessionContainer = Depends(verify_session())): user_id = session.get_user_id() - # highlight-end print(user_id) ``` - - + + ```python from flask import g @@ -1049,20 +1220,18 @@ from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.flask import verify_session -# highlight-start -@app.route('/update-jwt', methods=['POST']) # type: ignore +@app.route('/update-jwt', methods=['POST']) @verify_session() def like_comment(): - session: SessionContainer = g.supertokens # type: ignore + session: SessionContainer = g.supertokens user_id = session.get_user_id() - # highlight-end print(user_id) ``` - - + + ```python from typing import cast @@ -1073,23 +1242,21 @@ from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.framework.django.asyncio import verify_session -# highlight-start @verify_session() async def like_comment(request: HttpRequest): - session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore + session: SessionContainer = cast(SessionContainer, request.supertokens) user_id = session.get_user_id() - # highlight-end print(user_id) ``` - + - + - - + + The middleware function returns a `401` to the frontend if a session doesn't exist, or if the access token has expired, in which case, our frontend SDK automatically refreshes the session. @@ -1104,7 +1271,7 @@ From here follow these steps to confirm that your setup is working properly. - After you have created the account go to **Login** page and fill in your credentials. - If you are greeted with the login screen you have completed the quickstart setup. -:::success 🎉 Congratulations 🎉 +:::success[🎉 Congratulations 🎉] You've successfully integrated **SuperTokens** with your existing application! @@ -1112,3 +1279,5 @@ Of course, there are additional things that you should add in order to provide a We will talk about those things in the [next section](./next-steps). ::: + + ``` diff --git a/docs/quickstart/build-with-ai-tools.mdx b/docs/quickstart/build-with-ai-tools.mdx index 9c6d0da188..b23f80209a 100644 --- a/docs/quickstart/build-with-ai-tools.mdx +++ b/docs/quickstart/build-with-ai-tools.mdx @@ -1,17 +1,11 @@ --- title: Build with AI Tools -hide_title: true -pagination_next: null -sidebar_position: 6 -description: >- - Learn how to leverage the plain text documentation format inside AI tools. -page_type: tutorial -category: quickstart -skip_llms: true +description: Learn how to leverage the plain text documentation format inside AI tools. +sidebar: + order: 6 + badge: New --- -# Build with AI Tools - ## Overview If you plan on using large language models (LLMs) to assist in the process of integrating SuperTokens, the documentation exposes a set of helpers that can aid you. @@ -19,7 +13,7 @@ If you plan on using large language models (LLMs) to assist in the process of in ## Text documentation You can access all the documentation as plain text markdown files by appending `.md` to the end of any URL or by using the `Copy Markdown` button, from the top right part of each page. -For example, you can find the plain text version of this page at [https://supertokens.com/docs/quickstart/build-with-ai-tools.md](https://supertokens.com/docs/quickstart/build-with-ai-tools.md). +For example, you can find the plain text version of this page at [https://supertokens.com/docs/quickstart/build-with-ai-tools.md](https://supertokens.com/docs/quickstart/build-with-ai-tools). This plain text format is ideal for AI tools and agents as it: - Contains fewer formatting tokens. @@ -53,31 +47,28 @@ You can use the MCP server in two ways: - -### Install the plugin - + - - ```bash + + ```bash npm i -s supertokens-mcp-plugin ``` - - ```bash + + ```bash yarn add supertokens-mcp-plugin ``` - + ```bash pnpm add supertokens-auth-react supertokens-web-js ``` - -### Update the SDK initialization code - + + Initialize and include the `SuperTokensAdminMcpServer` in your SDK configuration. -You have to specify how the client will be authorized through either [claim validators](/docs/additional-verification/session-verification/claim-validation) or through custom logic defined in the `validateTokenPayload` function. +You have to specify how the client will be authorized through either [claim validators](/additional-verification/session-verification/claim-validation) or through custom logic defined in the `validateTokenPayload` function. ```ts import UserRoles, { UserRoleClaim } from "supertokens-node/recipe/userroles"; @@ -123,11 +114,10 @@ export const SuperTokensConfig = { }, }; ``` - -### Add the MCP server in a client configuration - + + - + Add the following to your `~/.cursor/mcp.json` file. To learn more, see the [Cursor documentation](https://docs.cursor.com/context/model-context-protocol). @@ -142,7 +132,7 @@ To learn more, see the [Cursor documentation](https://docs.cursor.com/context/mo } ``` - + Add the following to your `.vscode/mcp.json` file. To learn more, see the [VS Code documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers). @@ -158,7 +148,7 @@ To learn more, see the [VS Code documentation](https://code.visualstudio.com/doc } ``` - + Add the following to your `~/.codeium/windsurf/mcp_config.json` file. To learn more, see the [Windsurf documentation](https://docs.windsurf.com/windsurf/cascade/mcp). @@ -173,7 +163,7 @@ To learn more, see the [Windsurf documentation](https://docs.windsurf.com/windsu } ``` - + Add the following to your `claude_desktop_config.json` file. To learn more, see the [Claude Desktop documentation](https://modelcontextprotocol.io/quickstart/user). @@ -189,7 +179,7 @@ To learn more, see the [Claude Desktop documentation](https://modelcontextprotoc ``` - + @@ -199,7 +189,7 @@ If you plan on using the server locally you can run it directly through `npx`. You have to provide a set of environment variables that match the SDK configuration values. - + Add the following to your `~/.cursor/mcp.json` file. To learn more, see the [Cursor documentation](https://docs.cursor.com/context/model-context-protocol). @@ -223,7 +213,7 @@ To learn more, see the [Cursor documentation](https://docs.cursor.com/context/mo } ``` - + Add the following to your `.vscode/mcp.json` file. To learn more, see the [VS Code documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers). @@ -248,7 +238,7 @@ To learn more, see the [VS Code documentation](https://code.visualstudio.com/doc } ``` - + Add the following to your `~/.codeium/windsurf/mcp_config.json` file. To learn more, see the [Windsurf documentation](https://docs.windsurf.com/windsurf/cascade/mcp). @@ -273,7 +263,7 @@ To learn more, see the [Windsurf documentation](https://docs.windsurf.com/windsu } ``` - + Add the following to your `claude_desktop_config.json` file. To learn more, see the [Claude Desktop documentation](https://modelcontextprotocol.io/quickstart/user). @@ -299,6 +289,3 @@ To learn more, see the [Claude Desktop documentation](https://modelcontextprotoc ``` - - - diff --git a/docs/quickstart/example-applications.mdx b/docs/quickstart/example-applications.mdx index 7b26c3102a..da48d553ac 100644 --- a/docs/quickstart/example-applications.mdx +++ b/docs/quickstart/example-applications.mdx @@ -1,15 +1,10 @@ --- title: Example Applications -sidebar_position: 5 description: Generate and run a demo app to explore SuperTokens authentication setup. -page_type: tutorial -category: quickstart +sidebar: + order: 5 --- - -# Example App - - ## Overview The fastest way to run a quick demo of **SuperTokens** is to use our cli to generate an example application. @@ -19,49 +14,38 @@ You will get a quick understanding of how the authentication experience works an - ## Project Structure The command will create a new folder based on the application name that you have specified. Inside it you will find a project configured to support an authentication flow based on the recipe that you have chosen. - ## Next Steps -If you want more explanations on how to integrate **SuperTokens** with your application, please check our [**Quickstart Guide**](/docs/quickstart/introduction). +If you want more explanations on how to integrate **SuperTokens** with your application, please check our [**Quickstart Guide**](/quickstart/introduction). Otherwise, you can explore the other sections of the documentation that expand on the features of **SuperTokens** and offer you in-depth instructions on how to use them. - - - - Self Host SuperTokens Core - - - Run the SuperTokens in your own infrastructure. - - - - - Migration Guide - Migrate your data from other authentication providers. - - - - Multi Factor Authentication - Set up additional authentication layers in your sign-in process. - - - - User Management Dashboard - Administrate your users from the SuperTokens Dashboard. - - - - User Roles and Permissions - Adjust the authorization settings in your application. - - - + + +Run the SuperTokens in your own infrastructure. + + + +Migrate your data from other authentication providers. + + + +Set up additional authentication layers in your sign-in process. + + + +Administrate your users from the SuperTokens Dashboard. + + + +Adjust the authorization settings in your application. + + + diff --git a/docs/quickstart/frontend-setup.mdx b/docs/quickstart/frontend-setup.mdx index 506b425dab..f407fa64e0 100644 --- a/docs/quickstart/frontend-setup.mdx +++ b/docs/quickstart/frontend-setup.mdx @@ -1,152 +1,148 @@ --- -id: frontend-setup title: Frontend Setup -hide_title: true -sidebar_position: 2 -description: >- - Configure your frontend application for SuperTokens authentication, including - SDK installation and session management. -page_type: tutorial -category: quickstart +description: Configure your frontend application for SuperTokens authentication, including SDK installation and session management. +sidebar: + order: 2 --- - -import ReactRouterCallout from "/docs/_blocks/react-router-callout.mdx"; - -import ReactSDKInit from "./_blocks/react-sdk-init.mdx"; -import ReactRouterV6 from "./_blocks/react-router-v6.mdx"; -import ReactNoRouter from "./_blocks/react-no-router.mdx"; -import AngularAuthComponent from "./_blocks/angular-auth-component.mdx"; -import AngularAppComponent from "./_blocks/angular-auth-component.mdx"; -import AngularRouting from "./_blocks/angular-routing.mdx"; -import VueAuthView from "./_blocks/vue-auth-view.mdx"; -import VueMainFile from "./_blocks/vue-main-file.mdx"; -import VueRouting from "./_blocks/vue-routing.mdx"; -import VanillaJSNpmSDKInit from "./_blocks/vanilla-js-npm-sdk-init.mdx"; -import VanillaJSScriptsSDKInit from "./_blocks/vanilla-js-script-sdk-init.mdx"; -import KotlinSDKInit from "./_blocks/kotlin-sdk-init.mdx"; -import SwiftSDKInit from "./_blocks/swift-sdk-init.mdx"; -import VanillaJSNpmSignUp from "./_blocks/vanilla-js-npm-sign-up.mdx"; -import VanillaJSScriptsSignUp from "./_blocks/vanilla-js-script-sign-up.mdx"; -import VanillaJSNpmCheckEmail from "./_blocks/vanilla-js-npm-check-email.mdx"; -import VanillaJSScriptsCheckEmail from "./_blocks/vanilla-js-script-check-email.mdx"; -import VanillaJSNpmSignIn from "./_blocks/vanilla-js-npm-sign-in.mdx"; -import VanillaJSScriptsSignIn from "./_blocks/vanilla-js-script-sign-in.mdx"; -import CurlSignIn from "./_blocks/curl-sign-in.mdx"; - - -# Frontend Setup - Start the setup by configuring your frontend application to use **SuperTokens** for authentication. This guide uses the **SuperTokens pre-built UI** components. If you want to create your own interface please check the **Custom UI** tutorial. - + - + ## 1. Install the SDK Run the following command in your terminal to install the package. - - - - - ```bash + + + + + ```bash npm i -s supertokens-auth-react ``` - - + + ```bash yarn add supertokens-auth-react supertokens-web-js ``` - - + + ```bash pnpm add supertokens-auth-react supertokens-web-js ``` - - + + ```bash bun add supertokens-auth-react supertokens-web-js ``` - - - - - - + + + + + + ```bash npm i -s supertokens-web-js ``` - - + + ```bash yarn add supertokens-web-js ``` - - + + ```bash pnpm add supertokens-web-js ``` - - + + ```bash bun add supertokens-web-js ``` - - - - - - + + + + + + ```bash npm i -s supertokens-web-js ``` - - + + ```bash yarn add supertokens-web-js ``` - - + + ```bash pnpm add supertokens-web-js ``` - - + + ```bash bun add supertokens-web-js ``` - - - - + + + + ## 2. Initialize the SDK - - - + + In your main application file call the `SuperTokens.init` function to initialize the SDK. - The `init` call includes the [main configuration details](/docs/references/frontend-sdks/reference#sdk-configuration), as well as the **recipes** that you use in your setup. + The `init` call includes the [main configuration details](/references/frontend-sdks/reference#sdk-configuration), as well as the **recipes** that you use in your setup. After that you have to wrap the application with the `SuperTokensWrapper` component. This provides authentication context for the rest of the UI tree. - - - + ```tsx {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,23,25} +import React from "react"; + +import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; +import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; +import Session from "supertokens-auth-react/recipe/session"; + +SuperTokens.init({ + appInfo: { + // learn more about this on https://supertokens.com/docs/references/frontend-sdks/reference#sdk-configuration + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [EmailPassword.init(), Session.init()], +}); + +/* Your App */ +class App extends React.Component { + render() { + return ( + + {/*Your app components*/} + + ); + } +} +``` + + Before we initialize the `supertokens-web-js` SDK let's see how we use it in our Angular app. **Architecture** - The `supertokens-web-js` SDK is responsible for session management and providing helper functions to check if a session exists, or validate the access token claims on the frontend (for example, to check for user roles before showing some UI). We initialise this SDK on the root of your Angular app, so that all pages in your app can use it. - - You have to create a `^{appInfo.websiteBasePath}*` route in the Angular app which renders our pre-built UI. which also needs to be initialised, but only on that route. + - You have to create a `/auth*` route in the Angular app which renders our pre-built UI. which also needs to be initialised, but only on that route. - **Creating the `^{appInfo.websiteBasePath}` route** + **Creating the `/auth` route** - Use the Angular CLI to generate a new route @@ -156,65 +152,366 @@ Run the following command in your terminal to install the package. - Add the following code to your `auth` angular component - + ```tsx title="/app/auth/auth.component.ts" + import { + Component, + OnDestroy, + AfterViewInit, + Renderer2, + Inject, + } from "@angular/core"; + import { DOCUMENT } from "@angular/common"; + + @Component({ + selector: "app-auth", + template: '
', + }) + export class AuthComponent implements OnDestroy, AfterViewInit { + constructor( + private renderer: Renderer2, + @Inject(DOCUMENT) private document: Document, + ) {} + + ngAfterViewInit() { + this.loadScript("https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js"); + } + + ngOnDestroy() { + // Remove the script when the component is destroyed + const script = this.document.getElementById("supertokens-script"); + if (script) { + script.remove(); + } + } + + private loadScript(src: string) { + const script = this.renderer.createElement("script"); + script.type = "text/javascript"; + script.src = src; + script.id = "supertokens-script"; + script.onload = () => { + supertokensUIInit({ + appInfo: { + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [ + supertokensUIEmailPassword.init(), + supertokensUISession.init(), + ], + }); + }; + this.renderer.appendChild(this.document.body, script); + } + } + ``` - In the `loadScript` function, we provide the SuperTokens config for the UI. We add the emailpassword and session recipe. - Initialize the `supertokens-web-js` SDK in your angular app's root component. This provides session management across your entire application. - -
- + ```tsx title="/app/auth/auth.component.ts" + import { + Component, + OnDestroy, + AfterViewInit, + Renderer2, + Inject, + } from "@angular/core"; + import { DOCUMENT } from "@angular/common"; + + @Component({ + selector: "app-auth", + template: '
', + }) + export class AuthComponent implements OnDestroy, AfterViewInit { + constructor( + private renderer: Renderer2, + @Inject(DOCUMENT) private document: Document, + ) {} + + ngAfterViewInit() { + this.loadScript("https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js"); + } + + ngOnDestroy() { + // Remove the script when the component is destroyed + const script = this.document.getElementById("supertokens-script"); + if (script) { + script.remove(); + } + } + + private loadScript(src: string) { + const script = this.renderer.createElement("script"); + script.type = "text/javascript"; + script.src = src; + script.id = "supertokens-script"; + script.onload = () => { + supertokensUIInit({ + appInfo: { + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [ + supertokensUIEmailPassword.init(), + supertokensUISession.init(), + ], + }); + }; + this.renderer.appendChild(this.document.body, script); + } + } + ``` + + Before we initialize the `supertokens-web-js` SDK let's see how we use it in our Vue app **Architecture** - The `supertokens-web-js` SDK is responsible for session management and providing helper functions to check if a session exists, or validate the access token claims on the frontend (for example, to check for user roles before showing some UI). We initialise this SDK on the root of your Vue app, so that all pages in your app can use it. - - We create a `^{appInfo.websiteBasePath}*` route in the Vue app which renders our pre-built UI which also needs to be initialised, but only on that route. + - We create a `/auth*` route in the Vue app which renders our pre-built UI which also needs to be initialised, but only on that route. - **Creating the `^{appInfo.websiteBasePath}` route** + **Creating the `/auth` route** - Create a new file `AuthView.vue`, this Vue component is used to render the auth component: - + ```tsx + + + + ``` - In the `loadScript` function, we provide the SuperTokens config for the UI. We add the emailpassword and session recipe. - Initialize the `supertokens-web-js` SDK in your Vue app's `main.ts` file. This provides session management across your entire application. - -
-
+ ```tsx title="/main.ts " + import { createApp } from "vue"; + import SuperTokens from "supertokens-web-js"; + import Session from "supertokens-web-js/recipe/session"; + import App from "./App.vue"; + import router from "./router"; + + SuperTokens.init({ + appInfo: { + appName: "", + apiDomain: "", + apiBasePath: "/auth", + }, + recipeList: [Session.init()], + }); + + const app = createApp(App); + + app.use(router); + + app.mount("#app"); + ``` + + ## 3. Configure Routing - - + + In order for the **pre-built UI** to be rendered inside your application, you have to specify which routes show the authentication components. The **React SDK** uses [**React Router**](https://reactrouter.com/en/main) under the hood to achieve this. Based on whether you already use this package or not in your project, there are two different ways of configuring the routes. - - + + Call the `getSuperTokensRoutesForReactRouterDom` method from within any `react-router-dom` `Routes` component. - - - - + ```tsx {9,21} +import React from 'react'; +import { + BrowserRouter, + Routes, + Route, + Link +} from "react-router-dom"; + +import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; +import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; +import { EmailPasswordPreBuiltUI } from 'supertokens-auth-react/recipe/emailpassword/prebuiltui'; +import * as reactRouterDom from "react-router-dom"; + +class App extends React.Component { + render() { + return ( + + + + {/*This renders the login UI on the /auth route*/} + {getSuperTokensRoutesForReactRouterDom(reactRouterDom, [EmailPasswordPreBuiltUI])} + {/*Your app routes*/} + + + + ); + } +} +``` + :::note[If you are using `useRoutes`, `createBrowserRouter` or have routes defined in a different file, you need to adjust the code sample.] +Please see [this issue](https://github.com/supertokens/supertokens-auth-react/issues/581#issuecomment-1246998493) for further details. +```tsx +import React from 'react'; + +import { BrowserRouter, useRoutes } from "react-router-dom"; +import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; +import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; +import * as reactRouterDom from "react-router-dom"; + +function AppRoutes() { + const authRoutes = getSuperTokensRoutesForReactRouterDom( + reactRouterDom, + [/* Add your UI recipes here e.g. EmailPasswordPrebuiltUI, PasswordlessPrebuiltUI, ThirdPartyPrebuiltUI */] + ); + + const routes = useRoutes([ + ...authRoutes.map(route => route.props), + // Include the rest of your app routes + ]); + + return routes; +} + +function App() { + return ( + + + + + + ); +} +``` +::: + + Add the highlighted code snippet to your root level `render` function. - - - - - + ```tsx {8,9,10,11} +import React from 'react'; +import { EmailPasswordPreBuiltUI } from 'supertokens-auth-react/recipe/emailpassword/prebuiltui'; +import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react"; +import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui"; + +class App extends React.Component { + render() { + if (canHandleRoute([EmailPasswordPreBuiltUI])) { + // This renders the login UI on the /auth route + return getRoutingComponent([EmailPasswordPreBuiltUI]) + } + + return ( + {/*Your app*/} + ); + } + +} +``` + + + + Update your angular router so that all auth related requests load the `auth` component - - - + ```tsx title="/app/app-routing.module.ts" {5,6,7,8,9,10,11,12,13} +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; + +const routes: Routes = [ + { + path: "auth", + loadChildren: () => import("./auth/auth.module").then((m) => m.AuthModule), + }, + + { + path: "**", + loadChildren: () => import("./home/home.module").then((m) => m.HomeModule), + }, +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule], +}) +export class AppRoutingModule {} +``` + + Update your Vue router so that all auth related requests load the `AuthView` component - - - + ```tsx title="/router/index.ts" +import { createRouter, createWebHistory } from "vue-router"; +import HomeView from "../views/HomeView.vue"; +import AuthView from "../views/AuthView.vue"; + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: "/", + name: "home", + component: HomeView, + }, + { + path: "/auth/:pathMatch(.*)*", + name: "auth", + component: AuthView, + }, + ], +}); + +export default router; +``` + + ## 4. Handle Session Tokens @@ -225,22 +522,20 @@ The step serves more as a way for us to tell you how is this handled under the h After you call the `init` function, the **SDK** adds interceptors to both `fetch` and `XHR`, XMLHTTPRequest. The latter is used by the `axios` library. The interceptors save the session tokens that are generated from the authentication flow. Those tokens are then added to requests initialized by your frontend app which target the backend API. -By default, the tokens are stored through session cookies but you can also switch to [header based authentication](/docs/post-authentication/session-management/switch-between-cookies-and-header-authentication). +By default, the tokens are stored through session cookies but you can also switch to [header based authentication](/post-authentication/session-management/switch-between-cookies-and-header-authentication). ## 5. Secure Application Routes In order to prevent unauthorized access to certain parts of your frontend application you can use our utilities. Follow the code samples below to understand how to do this. - - + + You can wrap your components with the `` react component. This ensures that your component renders only if the user is logged in. If they are not logged in, the user is redirected to the login page. ```tsx import React from "react"; import { BrowserRouter, Routes, Route } from "react-router-dom"; - // highlight-next-line import { SessionAuth } from "supertokens-auth-react/recipe/session"; - // @ts-ignore import MyDashboardComponent from "./dashboard"; class App extends React.Component { @@ -251,12 +546,10 @@ Follow the code samples below to understand how to do this. {/*Components that require to be protected by authentication*/} - // highlight-end } /> @@ -265,8 +558,8 @@ Follow the code samples below to understand how to do this. } } ``` - - + + You can use the `doesSessionExist` function to check if a session exists in all your routes. ```tsx import Session from "supertokens-web-js/recipe/session"; @@ -279,8 +572,8 @@ Follow the code samples below to understand how to do this. } } ``` - - + + You can use the `doesSessionExist` function to check if a session exists in all your routes. ```tsx import Session from "supertokens-web-js/recipe/session"; @@ -293,61 +586,60 @@ Follow the code samples below to understand how to do this. } } ``` - - + + ## 6. View the login UI -You can check the login UI by visiting the `^{appInfo.websiteBasePath}` route, in your frontend application. +You can check the login UI by visiting the `/auth` route, in your frontend application. To review all the components of our pre-built UI please follow [this link](https://master--6571be2867f75556541fde98.chromatic.com/?path=/story/auth-page--playground). +
-
- - + ## 1. Install the SDK Use the following command to install the required package. - - - - + + + + ```bash npm i -s supertokens-web-js ``` - - + + - + You need to add all of the following scripts to your app - + ```html - - - - + + + + ``` - - - - + + + + :::info - If you want to implement a common authentication experience for both web and mobile, please look at our [**Unified Login guide**](/docs/authentication/unified-login/introduction). + If you want to implement a common authentication experience for both web and mobile, please look at our [**Unified Login guide**](/authentication/unified-login/introduction). ::: - - + + ```bash npm i -s supertokens-react-native # IMPORTANT: If you already have @react-native-async-storage/async-storage as a dependency, make sure the version is 1.12.1 or higher npm i -s @react-native-async-storage/async-storage ``` - - + + Add to your `settings.gradle`: ```bash dependencyResolutionManagement { @@ -365,8 +657,8 @@ Use the following command to install the required package. ``` You can find the latest version of the SDK [here](https://github.com/supertokens/supertokens-android/releases) (ignore the `v` prefix in the releases). - - + + #### Using Cocoapods @@ -386,9 +678,9 @@ Use the following command to install the required package. https://github.com/supertokens/supertokens-ios ``` - + - + Add the dependency to your pubspec.yaml @@ -398,68 +690,130 @@ supertokens_flutter: ^X.Y.Z You can find the latest version of the SDK [here](https://github.com/supertokens/supertokens-flutter/releases) (ignore the `v` prefix in the releases). - + - + - + - + ## 2. Initialise SuperTokens - Call the SDK init function at the start of your application. -The invocation includes the [main configuration details](/docs/references/frontend-sdks/reference#sdk-configuration), as well as the **recipes** that you use in your setup. - - - - - - - - - - - - - - - +The invocation includes the [main configuration details](/references/frontend-sdks/reference#sdk-configuration), as well as the **recipes** that you use in your setup. + + + + + + ```tsx {532,535,552,553,1082} +import SuperTokens from 'supertokens-web-js'; +import Session from 'supertokens-web-js/recipe/session'; +import EmailPassword from 'supertokens-web-js/recipe/emailpassword' + +SuperTokens.init({ + appInfo: { + apiDomain: "", + apiBasePath: "/auth", + appName: "...", + }, + recipeList: [ + Session.init(), + EmailPassword.init(), + ], +}); +``` + + + ```tsx +supertokens.init({ + appInfo: { + apiDomain: "", + apiBasePath: "/auth", + appName: "...", + }, + recipeList: [ + supertokensSession.init(), + supertokensEmailPassword.init(), + ], +}); +``` + + + + + + ```tsx import SuperTokens from 'supertokens-react-native'; SuperTokens.init({ - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", }); ``` - - + + Add the `SuperTokens.init` function call at the start of your application. - - - - - - + ```kotlin +import android.app.Application +import com.supertokens.session.SuperTokens + +class MainApplication: Application() { + override fun onCreate() { + super.onCreate() + + SuperTokens.Builder(this, "") + .apiBasePath("/auth") + .build() + } +} +``` + + + ```swift +import UIKit +import SuperTokensIOS + +fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + do { + try SuperTokens.initialize( + apiDomain: "", + apiBasePath: "/auth" + ) + } catch SuperTokensError.initError(let message) { + // TODO: Handle initialization error + } catch { + // Some other error + } + + return true + } + +} +``` + + ```dart import 'package:supertokens_flutter/supertokens.dart'; void main() { SuperTokens.init( - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + apiDomain: "", + apiBasePath: "/auth", ); } ``` - - - - + + + + ## 3. Add the Login UI @@ -470,12 +824,12 @@ If you are provisioning users from a different method you can skip over adding t ### 3.1 Add the Sign Up form - - + + For the **Sign Up** flow you have to first add the UI elements which render your form. After that, call the following function when the user submits the form that you have previously created. - - + + ```tsx import { signUp } from "supertokens-web-js/recipe/emailpassword"; @@ -526,11 +880,10 @@ async function signUpClicked(email: string, password: string) { } ``` - - + + ```tsx -import supertokensEmailPassword from "supertokens-web-js-script/recipe/emailpassword"; async function signUpClicked(email: string, password: string) { try { let response = await supertokensEmailPassword.signUp({ @@ -577,15 +930,15 @@ async function signUpClicked(email: string, password: string) { } ``` - - - - + + + + For the **Sign Up** flow you have to first add the UI elements which render your form. After that, call the following API when the user submits the form that you have previously created. ```bash - curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/signup' \ + curl --location --request POST '/auth/signup' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "formFields": [{ @@ -608,8 +961,8 @@ async function signUpClicked(email: string, password: string) { - `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should be displayed on the frontend. - `status: "SIGN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during MFA. The `reason` prop that's in the response body contains a support code using which you can see why the sign up was not allowed. - - + + The `formFields` input is a key-value array. You must provide it an `email` and a `password` value at a minimum. If you want to provide additional items, for example the user's name or age, you can append it to the array like so: @@ -637,49 +990,186 @@ On success, the backend sends back session tokens as part of the response header As a part of the sign up form, you may want to explicitly check that the entered email is unique. Whilst this is already done via the sign up API call, it may be a better UX to warn the user about a non unique email right after they finish typing it. - - - - - - - - - - - - + + + + + ```tsx +import { doesEmailExist } from "supertokens-web-js/recipe/emailpassword"; + +async function checkEmail(email: string) { + try { + let response = await doesEmailExist({ + email + }); + + if (response.doesExist) { + window.alert("Email already exists. Please sign in instead") + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + ```tsx +async function checkEmail(email: string) { + try { + let response = await supertokensEmailPassword.doesEmailExist({ + email + }); + + if (response.doesExist) { + window.alert("Email already exists. Please sign in instead") + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + ```bash -curl --location --request GET '^{appInfo.apiDomain}^{appInfo.apiBasePath}/emailpassword/email/exists?email=john@example.com' +curl --location --request GET '/auth/emailpassword/email/exists?email=john@example.com' ``` The response body from the API call has a `status` property in it: - `status: "OK"`: The response also contains a `exists` boolean which is `true` if the input email already belongs to an email password user. - `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should be displayed on the frontend. - - + + ### 3.2 Add the Sign In Form - - + + For the **Sign In** flow you have to first add the UI elements which render your form. After that, call the following function when the user submits the form that you have previously created. - - - - - - - - - - + + + ```tsx +import { signIn } from "supertokens-web-js/recipe/emailpassword"; + +async function signInClicked(email: string, password: string) { + try { + let response = await signIn({ + formFields: [{ + id: "email", + value: email + }, { + id: "password", + value: password + }] + }) + + if (response.status === "FIELD_ERROR") { + response.formFields.forEach(formField => { + if (formField.id === "email") { + // Email validation failed (for example incorrect email syntax). + window.alert(formField.error) + } + }) + } else if (response.status === "WRONG_CREDENTIALS_ERROR") { + window.alert("Email password combination is incorrect.") + } else if (response.status === "SIGN_IN_NOT_ALLOWED") { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in was not allowed. + window.alert(response.reason) + } else { + // sign in successful. The session tokens are automatically handled by + // the frontend SDK. + window.location.href = "/homepage" + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + ```tsx +async function signInClicked(email: string, password: string) { + try { + let response = await supertokensEmailPassword.signIn({ + formFields: [{ + id: "email", + value: email + }, { + id: "password", + value: password + }] + }) + + if (response.status === "FIELD_ERROR") { + // one of the input formFields failed validation + response.formFields.forEach(formField => { + if (formField.id === "email") { + // Email validation failed (for example incorrect email syntax). + window.alert(formField.error) + } + }) + } else if (response.status === "WRONG_CREDENTIALS_ERROR") { + window.alert("Email password combination is incorrect.") + } else if (response.status === "SIGN_IN_NOT_ALLOWED") { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in was not allowed. + window.alert(response.reason) + } else { + // sign in successful. The session tokens are automatically handled by + // the frontend SDK. + window.location.href = "/homepage" + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + + + + For the **Sign In** flow you have to first add the UI elements which render your form. After that, call the following API when the user submits the form that you have previously created. - + ```bash +curl --location --request POST '/auth/signin' \ +--header 'Content-Type: application/json; charset=utf-8' \ +--data-raw '{ + "formFields": [{ + "id": "email", + "value": "john@example.com" + }, { + "id": "password", + "value": "somePassword123" + }] +}' +``` The response body from the API call has a `status` property in it: - `status: "OK"`: User sign in was successful. The response also contains more information about the user, for example their user ID. @@ -688,8 +1178,8 @@ The response body from the API call has a `status` property in it: - `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should be displayed on the frontend. - `status: "SIGN_IN_NOT_ALLOWED"`: This can happen during automatic account linking or during MFA. The `reason` prop that's in the response body contains a support code using which you can see why the sign in was not allowed. - - + + On success, the backend sends back session tokens as part of the response headers which are automatically handled by our frontend SDK for you. @@ -704,11 +1194,10 @@ For other platforms, like mobile apps, we use a bearer token in the `Authorizati ### With the Frontend SDK - - + + -:::success -No action required. +:::success[No action required.] ::: Our frontend SDK handles everything for you. You only need to make sure that you have called `supertokens.init` before making any network requests. @@ -718,45 +1207,34 @@ Our SDK adds interceptors to `fetch` and `XHR` (used by `axios`) to save and add By default, our web SDKs use cookies to provide credentials. - + - + - + - - + + Our frontend SDK handles everything for you. You only need to make sure that you have added our network interceptors as shown below - - + + -:::note -By default our mobile SDKs use a bearer token in the Authorization header to provide credentials. +:::note[By default our mobile SDKs use a bearer token in the Authorization header to provide credentials.] ::: - - - - - - - { - return ( - Are you using axios.create? - ) - }}> - + + + + + + + + ```tsx import axios from "axios"; -// highlight-next-line import SuperTokens from 'supertokens-react-native'; let axiosInstance = axios.create({/*...*/}); -// highlight-next-line SuperTokens.addAxiosInterceptors(axiosInstance); async function callAPI() { @@ -765,20 +1243,17 @@ async function callAPI() { } ``` - + - + -:::important -You must call `addAxiosInterceptors` on all `axios` imports. +:::note[You must call `addAxiosInterceptors` on all `axios` imports.] ::: ```tsx import axios from "axios"; -// highlight-start import SuperTokens from 'supertokens-react-native'; SuperTokens.addAxiosInterceptors(axios); -// highlight-end async function callAPI() { // use axios as you normally do @@ -786,32 +1261,31 @@ async function callAPI() { } ``` - - + + - + - - + + -:::success -When using `fetch`, network interceptors are added automatically when you call `supertokens.init`. So no action needed here. +:::success[When using `fetch`, network interceptors are added automatically when you call `supertokens.init`. So no action needed here.] ::: - + - + - + - + - - + + ```kotlin import android.app.Application @@ -843,12 +1317,11 @@ class MainApplication: Application() { } ``` -:::note -When making network requests you do not need to call `HttpURLConnection.connect` because SuperTokens does this for you. +:::note[When making network requests you do not need to call `HttpURLConnection.connect` because SuperTokens does this for you.] ::: - - + + ```kotlin import android.content.Context @@ -881,20 +1354,19 @@ class NetworkManager { } ``` - - + + -:::note -By default our mobile SDKs use a bearer token in the Authorization header to provide credentials. +:::note[By default our mobile SDKs use a bearer token in the Authorization header to provide credentials.] ::: - + - + - + - +

Using URLSession.shared

@@ -926,9 +1398,9 @@ fileprivate class NetworkManager { } ``` -
+
- + ```swift import Foundation @@ -946,22 +1418,20 @@ fileprivate class NetworkManager { } ``` - + - + -:::note -By default our mobile SDKs use a bearer token in the Authorization header to provide credentials. +:::note[By default our mobile SDKs use a bearer token in the Authorization header to provide credentials.] ::: -
+ - + - + - + You can make requests as you normally would with `http`, the only difference is that you import the client from the SuperTokens package instead. @@ -997,8 +1467,8 @@ Future makeRequest() async { } ``` - - + +

Add the SuperTokens interceptor

@@ -1033,34 +1503,32 @@ void setup() { } ``` - - +
+ -:::note -By default our mobile SDKs use a bearer token in the Authorization header to provide credentials. +:::note[By default our mobile SDKs use a bearer token in the Authorization header to provide credentials.] ::: -
+ - + -
-
+ + ### Without the Frontend SDK -:::caution -We highly recommend using our frontend SDK to handle session token management. It saves you a lot of time. +:::warning[We highly recommend using our frontend SDK to handle session token management. It saves you a lot of time.] ::: In this case, you need to manually handle the tokens and session refreshing, and decide if you are going to use header or cookie-based sessions. For browsers, we recommend cookies, while for mobile apps (or if you don't want to use the built-in cookie manager) you should use header-based sessions. - + - + #### During the Login Action @@ -1115,12 +1583,11 @@ You can call the refresh API as follows: ```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/session/refresh' \ +curl --location --request POST '/auth/session/refresh' \ --header 'Cookie: sRefreshToken=...' ``` -:::note -- You may also need to add the `anti-csrf` header to the request if that was provided to you during sign in. +:::note[- You may also need to add the `anti-csrf` header to the request if that was provided to you during sign in.] - The cURL command above shows the `sRefreshToken` cookie as well, but this is added by the web browser automatically, so you don't need to add it explicitly. ::: @@ -1129,9 +1596,9 @@ The result of a session refresh is either: - Status code `200`: This implies a successful refresh. The set of tokens returned here is the same as when the user logs in, so you can handle them in the same way. - Status code `401`: This means that the refresh token is invalid, or has been revoked. You must ask the user to login again. Remember to clear the `front-token` that you saved on the frontend earlier. - + - + ##### During the Login Action @@ -1159,7 +1626,7 @@ You can call the refresh API as follows: ```bash -curl --location --request POST '^{appInfo.apiDomain}^{appInfo.apiBasePath}/session/refresh' \ +curl --location --request POST '/auth/session/refresh' \ --header 'authorization: Bearer {refresh-token}' ``` @@ -1168,20 +1635,20 @@ The result of a session refresh is either: - Status code `200`: This implies a successful refresh. The set of tokens returned here is the same as when the user logs in, so you can handle them in the same way. - Status code `401`: This means that the refresh token is invalid, or has been revoked. You must ask the user to login again. Remember to clear the `st-refresh-token` and `st-access-token` that you saved on the frontend earlier. - + - + ## 5. Protect Frontend Routes - + - + - + - + You can use the `doesSessionExist` function to check if a session exists. @@ -1197,14 +1664,13 @@ async function doesSessionExist() { } ``` - + - + You can use the `doesSessionExist` function to check if a session exists. ```tsx -import Session from 'supertokens-web-js-script/recipe/session'; async function doesSessionExist() { if (await Session.doesSessionExist()) { // user is logged in @@ -1214,16 +1680,16 @@ async function doesSessionExist() { } ``` - - + + - + - + - + - + You can use the `doesSessionExist` function to check if a session exists. @@ -1239,9 +1705,9 @@ async function doesSessionExist() { } ``` - + - + You can use the `doesSessionExist` function to check if a session exists. @@ -1260,9 +1726,9 @@ class MainApplication: Application() { } ``` - + - + You can use the `doesSessionExist` function to check if a session exists. @@ -1281,9 +1747,9 @@ fileprivate class ViewController: UIViewController { } ``` - + - + You can use the `doesSessionExist` function to check if a session exists. @@ -1295,74 +1761,69 @@ Future doesSessionExist() async { } ``` - + - + - + - + ## 6. Add a Sign Out Action The `signOut` method revokes the session on the frontend and on the backend. Calling this function without a valid session also yields a successful response. - - - - + + + + ```tsx import Session from "supertokens-web-js/recipe/session"; async function logout () { - // highlight-next-line await Session.signOut(); window.location.href = "/auth"; // or to wherever your logic page is } ``` - - - ```tsx - import supertokensSession from "supertokens-web-js-script/recipe/session"; + + + ```tsx {2} async function logout () { - // highlight-next-line await supertokensSession.signOut(); window.location.href = "/auth"; // or to wherever your logic page is } ``` - - - - - - - -```tsx + + + + + + + +```tsx {4} import SuperTokens from "supertokens-react-native"; async function logout () { - // highlight-next-line await SuperTokens.signOut(); // navigate to the login screen.. } ``` - - + + -```kotlin +```kotlin {6} import android.app.Application import com.supertokens.session.SuperTokens class MainApplication: Application() { fun logout() { - // highlight-next-line SuperTokens.signOut(this); // navigate to the login screen.. } } ``` - - + + ```swift import UIKit @@ -1382,8 +1843,8 @@ fileprivate class ViewController: UIViewController { } } ``` - - + + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -1395,18 +1856,18 @@ Future signOut() async { ); } ``` - - - - + + + + - On success, the `signOut` function does not redirect the user to another page, so you must redirect the user yourself. - The `signOut` function calls the sign out API exposed by the session recipe on the backend. - If you call the `signOut` function whilst the access token has expired, but the refresh token still exists, our SDKs do an automatic session refresh before revoking the session. -
+ -:::success 🎉 Congratulations 🎉 +:::success[🎉 Congratulations 🎉] Congratulations! You've successfully integrated your frontend app with SuperTokens. diff --git a/docs/quickstart/integrations/_category_.json b/docs/quickstart/integrations/_category_.json deleted file mode 100644 index 0563a646eb..0000000000 --- a/docs/quickstart/integrations/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Integrations", - "position": 7 -} diff --git a/docs/quickstart/integrations/aws-lambda/_category_.json b/docs/quickstart/integrations/aws-lambda/_category_.json deleted file mode 100644 index 11aa72d541..0000000000 --- a/docs/quickstart/integrations/aws-lambda/_category_.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "label": "AWS Lambda", - "collapsible": true, - "collapsed": true, - "position": 2 -} diff --git a/docs/quickstart/integrations/aws-lambda/appsync-integration.mdx b/docs/quickstart/integrations/aws-lambda/appsync-integration.mdx index 900c1f8a8b..18e0f52b0d 100644 --- a/docs/quickstart/integrations/aws-lambda/appsync-integration.mdx +++ b/docs/quickstart/integrations/aws-lambda/appsync-integration.mdx @@ -1,27 +1,18 @@ --- -id: appsync-integration title: AppSync integration -hide_title: true -sidebar_position: 6 -pagination_next: null -llms_txt_title: AWS Lambda - AppSync integration -description: >- - Integrate Supertokens with AppSync using Lambda Authorizer for secure API - Gateway configuration. -page_type: tutorial -category: quickstart +description: Integrate Supertokens with AppSync using Lambda Authorizer for secure API Gateway configuration. +sidebar: + order: 6 --- -# AppSync integration - ## Overview -A Lambda Authorizer configured like in the [Authorizer guide](/docs/quickstart/integrations/aws-lambda/session-verification#using-lambda-authorizers) can help integrate SuperTokens with an AppSync service. +A Lambda Authorizer configured like in the [Authorizer guide](/quickstart/integrations/aws-lambda/session-verification#using-lambda-authorizers) can help integrate SuperTokens with an AppSync service. ## Before you start The following steps assume that you already have configured **SuperTokens** in AWS Lambda. -If not, please refer to the [AWS Lambda integration guide](/docs/quickstart/integrations/aws-lambda/quickstart-guide). +If not, please refer to the [AWS Lambda integration guide](/quickstart/integrations/aws-lambda/quickstart-guide). ## Steps @@ -31,7 +22,7 @@ Set up the AppSync service with an API key authorization. For more details, plea ### 2. Configure the API Gateway with the authorizer -Follow the [Authorizer guide](/docs/quickstart/integrations/aws-lambda/session-verification#using-lambda-authorizers) to set up the API Gateway with the `/auth`, and `/graphql` resources set up. `/auth` should be pointed to a lambda that handles the auth APIs. +Follow the [Authorizer guide](/quickstart/integrations/aws-lambda/session-verification#using-lambda-authorizers) to set up the API Gateway with the `/auth`, and `/graphql` resources set up. `/auth` should be pointed to a lambda that handles the auth APIs. When setting up the POST method on `/graphql`, you should use the following settings: - Integration type: AWS service diff --git a/docs/quickstart/integrations/aws-lambda/meta.ts b/docs/quickstart/integrations/aws-lambda/meta.ts new file mode 100644 index 0000000000..2b0b2c4e4f --- /dev/null +++ b/docs/quickstart/integrations/aws-lambda/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "AWS Lambda", + "order": 2, + "collapsed": true +}); diff --git a/docs/quickstart/integrations/aws-lambda/quickstart-guide.mdx b/docs/quickstart/integrations/aws-lambda/quickstart-guide.mdx index 99fbd6bbb2..e7c0e83dde 100644 --- a/docs/quickstart/integrations/aws-lambda/quickstart-guide.mdx +++ b/docs/quickstart/integrations/aws-lambda/quickstart-guide.mdx @@ -1,30 +1,22 @@ --- title: Quickstart Guide -hide_title: true -toc_max_heading_level: 4 -sidebar_position: 1 -llms_txt_title: AWS Lambda - Quickstart Guide description: Learn how to integrate SuperTokens with AWS Lambda -page_type: tutorial -category: quickstart +sidebar: + order: 1 --- - - -# Quickstart Guide - The following guide shows you how to use **SuperTokens** in an AWS Lambda environment. You can also check out the [example repository](https://github.com/supertokens/supertokens-node/tree/master/examples/aws/with-emailpassword) for a full implementation. ## Before you start -These instructions assume that you have completed the [quickstart guide](/docs/quickstart/frontend-setup). +These instructions assume that you have completed the [quickstart guide](/quickstart/frontend-setup). If not, please go through it and create the example application before you start this tutorial. ## Steps -:::caution -Follow the [quickstart guide](/docs/quickstart/frontend-setup) first to learn how to set up the frontend. +:::warning +Follow the [quickstart guide](/quickstart/frontend-setup) first to learn how to set up the frontend. ::: ### 1. Set up API Gateway @@ -33,7 +25,7 @@ Follow the [quickstart guide](/docs/quickstart/frontend-setup) first to learn ho We will be using AWS API Gateway to create a REST API that will be used to communicate with our Lambda functions. -Create API gateway step UI +Create API gateway step UI #### 1.2 Set up authentication routes @@ -41,20 +33,18 @@ Create a `/auth` resource and then `/auth/{proxy+}` resources. This will act as a catch-all for all SuperTokens auth routes. **Enable CORS** while creating the proxy resource. -Create proxy route step UI +Create proxy route step UI -Route creation complete step UI +Route creation complete step UI #### 1.3 Attach lambda to the `ANY` method of the proxy resource Click on the "ANY" method and then "Integration" to configure the lambda function. Check **Lambda proxy integration** and then select your lambda function. -Configure lambda integration UI - -:::important +Configure lambda integration UI -Ensure that the **Lambda proxy integration** toggle is turned on. +:::note[Ensure that the **Lambda proxy integration** toggle is turned on.] ::: @@ -62,33 +52,32 @@ Ensure that the **Lambda proxy integration** toggle is turned on. Click on the `{proxy+}` resource and then "Enable CORS" button to open the CORS configuration page. -Enable CORS for the proxy path UI +Enable CORS for the proxy path UI In the CORS configuration page do the following: - Select the 'Default 4XX' and 'Default 5XX' checkboxes under Gateway responses - Select the 'OPTIONS' checkbox under Methods - Add `rid,fdi-version,anti-csrf,st-auth-mode` to the existing `Access-Control-Allow-Headers` - - Set `Access-Control-Allow-Origin` to `'^{appInfo.websiteDomain}'` + - Set `Access-Control-Allow-Origin` to ``''`` - Select `Access-Control-Allow-Credentials` checkbox -CORS configuration page +CORS configuration page #### 1.5 Deploy the API Gateway Click the **Deploy API** button in the top right corner to deploy the API. During deployment, you'll be prompted to create a stage; for this tutorial, name the stage `dev`. After deployment, you will receive your `Invoke URL`. -:::important -Update `apiDomain`, `apiBasePath`, and `apiGatewayPath` in both Lambda configuration and your frontend config if they have changed post API Gateway configuration. +:::note[Update `apiDomain`, `apiBasePath`, and `apiGatewayPath` in both Lambda configuration and your frontend config if they have changed post API Gateway configuration.] ::: ### 2. Set up Lambda layer #### 2.1 Create Lambda layer with required libraries - + - + ```bash mkdir lambda && cd lambda @@ -98,8 +87,8 @@ mkdir nodejs && cp -r node_modules nodejs zip -r supertokens-node.zip nodejs/ ``` - - + + ```bash mkdir lambda && cd lambda @@ -109,70 +98,68 @@ cd python && rm -r *dist-info **/__pycache__ && cd .. zip -r supertokens-python.zip python/ ``` - - + + #### 2.2 Upload SuperTokens lambda layer Open AWS Lambda dashboard and click on layers: -AWS Lambda sidebar UI +AWS Lambda sidebar UI Click "Create Layer" button: -Create layer button UI +Create layer button UI Give a name for your layer, upload the zip and select the runtime - - - Lambda layer node configuration UI - - - Lambda layer python configuration UI - - + + + Lambda layer node configuration UI + + + Lambda layer python configuration UI + + ### 3. Set up Lambda #### 3.1 Create a new lambda Click "Create Function" in the AWS Lambda dashboard, enter the function name and runtime, and create your Lambda function. - - - Create new Lambda configurations UI Node - - - Create new Lambda configurations UI Python - - + + + Create new Lambda configurations UI Node + + + Create new Lambda configurations UI Python + + #### 3.2 Link lambda layer with the lambda function Scroll to the bottom and look for the `Layers` tab. Click on `Add a layer` -Link Lambda function with the Lambda layer +Link Lambda function with the Lambda layer Select `Custom Layer` and then select the layer we created in the first step: - - - Link custom layer with Lambda function Node - - - Link custom layer with Lambda function Python - - + + + Link custom layer with Lambda function Node + + + Link custom layer with Lambda function Python + + #### 3.3 Create a backend config file Using the editor provided by AWS, create a new config file and write the following code: - + + - - - -```tsx title="config.mjs" showAppTypeSelect +```tsx title="config.mjs" import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -180,16 +167,16 @@ export function getBackendConfig() { return { framework: "awsLambda", supertokens: { - connectionURI: "^{coreInfo.uri}", - // apiKey: "^{coreInfo.key}", + connectionURI: "", + // apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", apiGatewayPath: "/dev" }, recipeList: [ @@ -202,26 +189,26 @@ export function getBackendConfig() { ``` - + - + -```python title="config.py" showAppTypeSelect +```python title="config.py" from supertokens_python.recipe import emailpassword, session from supertokens_python import SupertokensConfig, InputAppInfo supertokens_config = SupertokensConfig( - connection_uri="^{coreInfo.uri}", - # api_key="^{coreInfo.key}" + connection_uri="", + # api_key="" ) app_info = InputAppInfo( # learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}", + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth", api_gateway_path="/dev", ) @@ -233,13 +220,12 @@ recipe_list = [ ] ``` - + - + -:::important -In the above code, notice the extra config of `apiGatewayPath` that was added to the `appInfo` object. +:::note[In the above code, notice the extra config of `apiGatewayPath` that was added to the `appInfo` object.] The value of this should be whatever you have set as the value of your [AWS stage](https://docs.aws.amazon.com/apigateway/latest/developerguide/stages.html) which scopes your API endpoints. For example, you may have a stage name per development environment: - One for development (`/dev`). @@ -251,21 +237,19 @@ So the value of `apiGatewayPath` should be set according to the above based on t You also need to change the `apiBasePath` on the frontend config to append the stage to the path. For example, if the frontend is query the development stage and the value of `apiBasePath` is `/auth`, you should change it to `/dev/auth`. ::: -:::note -You may edit the `apiBasePath` and `apiGatewayPath` value later if you haven't setup the API Gateway yet. +:::note[You may edit the `apiBasePath` and `apiGatewayPath` value later if you haven't setup the API Gateway yet.] ::: #### 3.4 Add the SuperTokens auth middleware Using the editor provided by AWS, create/replace the handler file contents with the following code: - - + + ```tsx title="index.mjs" import supertokens from "supertokens-node"; import { middleware } from "supertokens-node/framework/awsLambda"; -// @ts-ignore import { getBackendConfig } from "./config.mjs"; import middy from "@middy/core"; import cors from "@middy/http-cors"; @@ -273,7 +257,6 @@ import cors from "@middy/http-cors"; supertokens.init(getBackendConfig()); export const handler = middy( - // @ts-ignore middleware((event) => { // SuperTokens middleware didn't handle the route, return your custom response return { @@ -297,21 +280,21 @@ export const handler = middy( }); ``` -Add SuperTokens auth middleware UI -
-:::important +Add SuperTokens auth middleware UI +
+:::note Since, we are using `esm` imports, we will need to set `NODE_OPTIONS="--experimental-specifier-resolution=node"` flag in the lambda environment variables. See the [Node.js](https://nodejs.org/docs/latest-v16.x/api/esm.html#customizing-esm-specifier-resolution-algorithm) documentation for more information. -Configuring environment variables UI +Configuring environment variables UI ::: -
+ - + ```python title="handler.py" -import nest_asyncio # type: ignore -nest_asyncio.apply() # type: ignore +import nest_asyncio +nest_asyncio.apply() from fastapi import FastAPI from starlette.middleware.cors import CORSMiddleware @@ -320,13 +303,13 @@ from mangum import Mangum from supertokens_python import init, get_all_cors_headers from supertokens_python.framework.fastapi import get_middleware -import config # type: ignore +import config init( - supertokens_config=config.supertokens_config, # type: ignore - app_info=config.app_info, # type: ignore - framework=config.framework, # type: ignore - recipe_list=config.recipe_list, # type: ignore + supertokens_config=config.supertokens_config, + app_info=config.app_info, + framework=config.framework, + recipe_list=config.recipe_list, mode="asgi", ) @@ -337,7 +320,7 @@ app.add_middleware(get_middleware()) app = CORSMiddleware( app=app, allow_origins=[ - config.app_info.website_domain # type: ignore + config.app_info.website_domain ], allow_credentials=True, allow_methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], @@ -347,10 +330,10 @@ app = CORSMiddleware( handler = Mangum(app) ``` - -
+ + -#### 3.5 Filter additional plugins or extensions {{optional}} +#### 3.5 Filter additional plugins or extensions (optional) If you are using AWS Lambda plugins, extensions, or anything that adds events to the lambda function (e.g. `serverless-plugin-warmup`), then you may need to prevent calling SuperTokens with them. @@ -362,7 +345,6 @@ Here's an example of how you can filter them out: ```tsx title="index.mjs" import supertokens from "supertokens-node"; import { middleware } from "supertokens-node/framework/awsLambda"; -// @ts-ignore import { getBackendConfig } from "./config.mjs"; import middy from "@middy/core"; import cors from "@middy/http-cors"; @@ -370,7 +352,6 @@ import cors from "@middy/http-cors"; supertokens.init(getBackendConfig()); const httpHandler = middy( - // @ts-ignore middleware((event) => { // SuperTokens middleware didn't handle the route, return your custom response return { @@ -393,7 +374,6 @@ const httpHandler = middy( throw request.error; }); -// @ts-expect-error const postAuth = async (event, context) => { // Plugins generally inject a `source` property in the event object. if (event.source === 'serverless-plugin-warmup') { diff --git a/docs/quickstart/integrations/aws-lambda/session-verification.mdx b/docs/quickstart/integrations/aws-lambda/session-verification.mdx index d585c430cc..57f195ef22 100644 --- a/docs/quickstart/integrations/aws-lambda/session-verification.mdx +++ b/docs/quickstart/integrations/aws-lambda/session-verification.mdx @@ -1,22 +1,17 @@ --- title: Session Verification -hide_title: true -sidebar_position: 2 -llms_txt_title: AWS Lambda - Session Verification description: Verify user sessions when integrating SuperTokens with AWS Lambda. -page_type: tutorial -category: quickstart +sidebar: + order: 2 --- - -import OAuthVerifyTokensCallout from "../../../_blocks/oauth-tokens-callout.mdx"; - -# Session verification - The following page shows you three different ways to verify sessions in a lambda integration. Choose the one that works best based on the particularities of your use case. - +:::warning[This guide only applies to scenarios which involve **SuperTokens Session Access Tokens**.] + +If you are implementing either, [**Unified Login**](/authentication/unified-login/introduction) or [**Microservice Authentication**](/authentication/m2m/introduction), features that make use of **OAuth2 Access Tokens**, please check the [separate page](/authentication/unified-login/verify-tokens) that shows you how to verify those types of tokens. +::: ## Using Session Verification @@ -27,21 +22,19 @@ In this guide, we will be creating a `/user` `GET` route that will return the cu ### 1. Add `/user` `GET` route in your API Gateway -Create a `/user` resource and then `GET` method in your API Gateway. Configure the lambda integration and CORS just like we did [for the auth routes](/docs/quickstart/integrations/aws-lambda/quickstart-guide#13-attach-lambda-to-the-any-method-of-the-proxy-resource). +Create a `/user` resource and then `GET` method in your API Gateway. Configure the lambda integration and CORS just like we did [for the auth routes](/quickstart/integrations/aws-lambda/quickstart-guide#13-attach-lambda-to-the-any-method-of-the-proxy-resource). ### 2. Create a file in your lambda to handle the `/user` route. - - + + An example of this is [here](https://github.com/supertokens/supertokens-node/blob/master/examples/aws/with-emailpassword/backend/user.mjs). ```tsx title="user.mjs" import supertokens from "supertokens-node"; -// @ts-ignore import { getBackendConfig } from "./config.mjs"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; -import { APIGatewayAuthorizerEvent, PolicyDocument, Statement, AuthResponse, StatementEffect } from "aws-lambda"; // REMOVE_FROM_OUTPUT import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda"; import middy from "@middy/core"; import cors from "@middy/http-cors"; @@ -77,27 +70,21 @@ export const handler = middy(verifySession(lambdaHandler)) Now, import this function in your `index.mjs` handler file as shown below: -```tsx title="index.mjs" +```tsx title="index.mjs" {6,13,14} import supertokens from "supertokens-node"; import { middleware } from "supertokens-node/framework/awsLambda"; -// @ts-ignore import { getBackendConfig } from "./config.mjs"; import middy from "@middy/core"; import cors from "@middy/http-cors"; -// highlight-start -// @ts-ignore import { handler as userHandler } from "./user.mjs"; -// highlight-end supertokens.init(getBackendConfig()); export const handler = middy( middleware((event) => { - // highlight-start if (event.path === "/user") { return userHandler(event); - // highlight-end } return { @@ -121,18 +108,17 @@ export const handler = middy( }); ``` -:::note -The `verifySession` middleware automatically returns a 401 Unauthorised error if the session is not valid. You can alter the default behaviour by passing `{ sessionRequired: false }` as the second argument to the `verifySession` middleware. +:::note[The `verifySession` middleware automatically returns a 401 Unauthorised error if the session is not valid. You can alter the default behaviour by passing `{ sessionRequired: false }` as the second argument to the `verifySession` middleware.] If each API route has its own lambda function, you can skip using the SuperTokens auth middleware. Instead, ensure to call `supertokens.init` and include the `Session` recipe in the `recipeList` for each respective lambda function. ::: - - + + -```python title="handler.py" -import nest_asyncio # type: ignore -nest_asyncio.apply() # type: ignore +```python title="handler.py" {23,24,25,26,27,28,29,30,31,32,33} +import nest_asyncio +nest_asyncio.apply() from fastapi import FastAPI from starlette.middleware.cors import CORSMiddleware @@ -141,19 +127,18 @@ from mangum import Mangum from supertokens_python import init, get_all_cors_headers from supertokens_python.framework.fastapi import get_middleware -import config # type: ignore +import config init( - supertokens_config=config.supertokens_config, # type: ignore - app_info=config.app_info, # type: ignore - framework=config.framework, # type: ignore - recipe_list=config.recipe_list, # type: ignore + supertokens_config=config.supertokens_config, + app_info=config.app_info, + framework=config.framework, + recipe_list=config.recipe_list, mode="asgi", ) app = FastAPI(title="SuperTokens Example") -# highlight-start from fastapi import Depends from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.session import SessionContainer @@ -165,14 +150,13 @@ def user(s: SessionContainer = Depends(verify_session())): "userId": s.get_user_id(), "accessTokenPayload": s.get_access_token_payload() } -# highlight-end app.add_middleware(get_middleware()) app = CORSMiddleware( app=app, allow_origins=[ - config.app_info.website_domain # type: ignore + config.app_info.website_domain ], allow_credentials=True, allow_methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], @@ -181,15 +165,14 @@ app = CORSMiddleware( handler = Mangum(app) ``` -:::note -The `verify_session` middleware automatically returns a 401 Unauthorised error if the session is not valid. You can alter the default behaviour by passing `session_required=False` the `verify_session` middleware. +:::note[The `verify_session` middleware automatically returns a 401 Unauthorised error if the session is not valid. You can alter the default behaviour by passing `session_required=False` the `verify_session` middleware.] If each API route has its own lambda function, you can skip using the SuperTokens auth middleware. Instead, ensure to call `init` function and include the `session` recipe in the `recipe_list` for each respective lambda function. ::: - + - + --- @@ -200,19 +183,19 @@ You can use a lambda as an authorizer in API Gateways. This will enable you to u ### 1. Add configurations and dependencies -Refer to the [frontend](/docs/quickstart/frontend-setup), [lambda layer](/docs/quickstart/integrations/aws-lambda/quickstart-guide#2-set-up-lambda-layer), and [lambda setup](/docs/quickstart/integrations/aws-lambda/quickstart-guide#3-set-up-lambda). +Refer to the [frontend](/quickstart/frontend-setup), [lambda layer](/quickstart/integrations/aws-lambda/quickstart-guide#2-set-up-lambda-layer), and [lambda setup](/quickstart/integrations/aws-lambda/quickstart-guide#3-set-up-lambda). ### 2. Add code to the lambda function handler - - + + Use the code below as the handler for the lambda. Remember that whenever we want to use any functions from the `supertokens-python` lib, we have to call the `init` function at the top of that serverless function file. We can then use `get_session()` to get the session. ```python title="auth.py" -import nest_asyncio # type: ignore +import nest_asyncio import json -nest_asyncio.apply() # type: ignore +nest_asyncio.apply() from typing import Optional, Dict, Any @@ -223,13 +206,13 @@ from mangum import Mangum from supertokens_python import init, get_all_cors_headers from supertokens_python.framework.fastapi import get_middleware -import config # type: ignore +import config init( - supertokens_config=config.supertokens_config, # type: ignore - app_info=config.app_info, # type: ignore - framework=config.framework, # type: ignore - recipe_list=config.recipe_list, # type: ignore + supertokens_config=config.supertokens_config, + app_info=config.app_info, + framework=config.framework, + recipe_list=config.recipe_list, mode="asgi", ) app = FastAPI(title="SuperTokens Example") @@ -299,7 +282,7 @@ app.add_middleware(get_middleware()) app = CORSMiddleware( app=app, allow_origins=[ - config.app_info.website_domain # type: ignore + config.app_info.website_domain ], allow_credentials=True, allow_methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], @@ -318,8 +301,8 @@ def handler(event: Dict[str, Any], context: Any): return response ``` - - + + Use the code below as the handler for the lambda. Remember that whenever we want to use any functions from the `supertokens-node` lib, we have to call the `supertokens.init` function at the top of that serverless function file. @@ -328,10 +311,8 @@ We can then use `getSession()` to get the session. ```tsx title="index.mjs" import supertokens from "supertokens-node"; import { SessionEvent } from "supertokens-node/framework/awsLambda"; -import { APIGatewayAuthorizerEvent, PolicyDocument, Statement, AuthResponse, StatementEffect } from "aws-lambda"; // REMOVE_FROM_OUTPUT import Session from "supertokens-node/recipe/session"; -// @ts-expect-error import { getBackendConfig } from "./config.mjs"; supertokens.init(getBackendConfig()); @@ -399,8 +380,8 @@ const generateDeny = function (principalId: string, resource: string, context?: }; ``` - - + + ### 3. Configure the Authorizer @@ -415,12 +396,12 @@ const generateDeny = function (principalId: string, resource: string, context?: ### 4. Configure API Gateway -- In your API Gateway, create the resources and methods you require, enabling CORS if necessary (see [setup API gateway](/docs/quickstart/integrations/aws-lambda/quickstart-guide#1-set-up-api-gateway) for details) +- In your API Gateway, create the resources and methods you require, enabling CORS if necessary (see [setup API gateway](/quickstart/integrations/aws-lambda/quickstart-guide#1-set-up-api-gateway) for details) - Select each method you want to enable the Authorizer and configure it to use the new `Authorizer` - Click on "Method Request" - Edit the "Authorization" field in Settings and set it to the one we just created. - Go back to the method configuration and click on "Integration Request" - - Set up the integration you require (see [AppSync](/docs/quickstart/integrations/aws-lambda/appsync-integration) for an example) + - Set up the integration you require (see [AppSync](/quickstart/integrations/aws-lambda/appsync-integration) for an example) - Add a header mapping to make use of the context set in the lambda. - Open "HTTP Headers" - Add all headers required (e.g., "x-user-id" mapped to "context.authorizer.principalId") @@ -439,7 +420,7 @@ const generateDeny = function (principalId: string, resource: string, context?: - Select "Access Denied" - Click "Edit" - Add response headers: - - Add `Access-Control-Allow-Origin` with value `'^{appInfo.websiteDomain}'` + - Add `Access-Control-Allow-Origin` with value ``''`` - Add `Access-Control-Allow-Credentials` with value `'true'`. **Don't miss out on those quotes else it won't get configured correctly.** - Add "Set-Cookie" with value `context.authorizer.setCookie` **no quotes** - Under response templates: @@ -448,7 +429,7 @@ const generateDeny = function (principalId: string, resource: string, context?: - Click "Save" - Select "Unauthorized" - Add response headers: - - Add `Access-Control-Allow-Origin` with value `'^{appInfo.websiteDomain}'` + - Add `Access-Control-Allow-Origin` with value ``''`` - Add `Access-Control-Allow-Credentials` with value `'true'`. **Don't miss out on those quotes else it won't get configured correctly.** - Click "Save" - Deploy your API and test it @@ -457,47 +438,44 @@ const generateDeny = function (principalId: string, resource: string, context?: ## Using JWT Authorizers -:::caution +:::warning -AWS supports JWT authorizers for HTTP APIs and not REST APIs on the API Gateway service. For REST APIs follow the [Lambda authorizer](/docs/quickstart/integrations/aws-lambda/session-verification#using-lambda-authorizers) guide +AWS supports JWT authorizers for HTTP APIs and not REST APIs on the API Gateway service. For REST APIs follow the [Lambda authorizer](/quickstart/integrations/aws-lambda/session-verification#using-lambda-authorizers) guide This guide will work if you are using **SuperTokens Session Tokens**. -If you implementing an **OAuth2** setup, through the [**Unified Login**](/docs/authentication/unified-login/introduction) or the [**Microservice Authentication**](/docs/authentication/m2m/client-credentials) features, you will have to manually set the token audience property. +If you implementing an **OAuth2** setup, through the [**Unified Login**](/authentication/unified-login/introduction) or the [**Microservice Authentication**](/authentication/m2m/client-credentials) features, you will have to manually set the token audience property. Please check the referenced pages for more information. ::: ### 1. Add the `aud` claim in the JWT based on the authorizer configuration - - + - + -```tsx title="config.mjs" showAppTypeSelect +```tsx title="config.mjs" {20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44} import Session from 'supertokens-node/recipe/session' -import SuperTokensTypes from 'supertokens-node/types'; // REMOVE_FROM_OUTPUT export function getBackendConfig() { return { framework: "awsLambda", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/session/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", }, recipeList: [ - // highlight-start Session.init({ exposeAccessTokenToFrontendInCookieBasedAuth: true, override: { @@ -523,16 +501,15 @@ export function getBackendConfig() { }, }), ], - // highlight-end isInServerlessEnv: true, } } ``` - + - + -```python title="config.py" showAppTypeSelect +```python title="config.py" {28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,54,55,56,57,58,59} from supertokens_python.recipe import session from supertokens_python import ( InputAppInfo, @@ -544,23 +521,22 @@ from typing import Any, Dict, Optional from supertokens_python.types import RecipeUserId supertokens_config = SupertokensConfig( - connection_uri="^{coreInfo.uri}", - api_key="^{coreInfo.key}" + connection_uri="", + api_key="" ) app_info = InputAppInfo( # learn more about this on https://supertokens.com/docs/session/appinfo - app_name="^{appInfo.appName}", - api_domain="^{appInfo.apiDomain}", - website_domain="^{appInfo.websiteDomain}", - api_base_path="^{appInfo.apiBasePath}", - website_base_path="^{appInfo.websiteBasePath}", + app_name="", + api_domain="", + website_domain="", + api_base_path="/auth", + website_base_path="/auth", api_gateway_path="/dev", ) framework = "fastapi" -# highlight-start def override_session_functions(oi: SessionRecipeInterface) -> SessionRecipeInterface: oi_create_new_session = oi.create_new_session @@ -577,7 +553,6 @@ def override_session_functions(oi: SessionRecipeInterface) -> SessionRecipeInter # The value for this claim should be the same as the # value you set when creating the authorizer - # highlight-next-line if access_token_payload is None: access_token_payload = {} @@ -586,24 +561,21 @@ def override_session_functions(oi: SessionRecipeInterface) -> SessionRecipeInter oi.create_new_session = create_new_session return oi -# highlight-end recipe_list = [ - # highlight-start session.init( override=session.InputOverrideConfig( functions=override_session_functions, ), expose_access_token_to_frontend_in_cookie_based_auth=True, ), - # highlight-end ] ``` - + - + ### 2. Configure your authorizer @@ -612,7 +584,7 @@ recipe_list = [ - Click "Create", in the creation screen select "JWT" as the "Authorizer type" - Enter a name for your authorizer (You can enter any name for this field) - Use `$request.header.Authorization` for the "Identity source". This means that API requests will contain the JWT as a Bearer token under the request header "Authorization". -- Use `^{appInfo.apiDomain}//^{appInfo.apiBasePath}` for the "Issuer URL". +- Use `///auth` for the "Issuer URL". - Set a value for the "Audience" field, this will be the value you expect the JWT to have under the `aud` claim. In the backend config above the value is set to `"jwtAuthorizers"` ### 3. Add the authorizer to your API @@ -626,6 +598,3 @@ recipe_list = [ Once the JWT authorizer successfully validates the JWT, the claims of the JWT will be available to your lambda functions via `$event.requestContext.authorizer.jwt.claims`. You should check for the right authorization access here. For example, if one of your lambda functions requires that the user's email is verified, then it should check for the `jwt` payload's `st-ev` claim value to be `{v: true, t:...}`, else it should reject the request. Similar checks need to be done to enforce the right user role or if 2FA is completed or not. This is required because SuperTokens issues JWTs immediately after the user signs up / logs in, regardless of if all the authorisation checks pass or not. Functions exposed by our SDK like `verifySession` or `getSession` do these authorisation checks on their own, but since these functions are not used in the this flow, you will have to check them on your own. - - - diff --git a/docs/quickstart/integrations/graphql.mdx b/docs/quickstart/integrations/graphql.mdx index 39ebd49e58..8b4c0ef175 100644 --- a/docs/quickstart/integrations/graphql.mdx +++ b/docs/quickstart/integrations/graphql.mdx @@ -1,31 +1,26 @@ --- title: GraphQL -hide_title: true -sidebar_position: 3 -description: >- - Set up backend session verification in GraphQL resolvers using SuperTokens for - user authentication. -page_type: tutorial -category: quickstart +description: Set up backend session verification in GraphQL resolvers using SuperTokens for user authentication. +sidebar: + order: 3 --- -import OAuthVerifyTokensCallout from "../../_blocks/oauth-tokens-callout.mdx"; - -# GraphQL Session Verification - ## Before you start These instructions only show you how to perform **session verification** in a GraphQL context. -You will first have to go through the [quickstart guide](/docs/quickstart/frontend-setup) to configure **SuperTokens** and then return to this page. +You will first have to go through the [quickstart guide](/quickstart/frontend-setup) to configure **SuperTokens** and then return to this page. - +:::warning[This guide only applies to scenarios which involve **SuperTokens Session Access Tokens**.] + +If you are implementing either, [**Unified Login**](/authentication/unified-login/introduction) or [**Microservice Authentication**](/authentication/m2m/introduction), features that make use of **OAuth2 Access Tokens**, please check the [separate page](/authentication/unified-login/verify-tokens) that shows you how to verify those types of tokens. +::: ## Using the GraphQL context We want to use the `Session.getSession` function in the `context` function to verify the session, and add the `userId` into our context so that our resolvers can read it. If the user id not logged in, we will set the `userId` to `undefined` in the context -```tsx +```tsx {24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41} import { ApolloServer } from "@apollo/server"; import express from "express"; import { expressMiddleware } from "@apollo/server/express4"; @@ -49,7 +44,6 @@ server.start().then(() => { // but the arguments received by `context` vary by integration. // This means they vary for Express, Fastify, Lambda, etc. context: async ({ req, res }) => { - // highlight-start try { let session = await Session.getSession(req, res, { sessionRequired: false @@ -68,7 +62,6 @@ server.start().then(() => { } throw err; } - // highlight-end }, })) @@ -121,7 +114,7 @@ In the above function, we attempt to verify the session using `Session.getSessio For this resolver to work, we will have to add the `req` and `res` object into the GraphQL context. This can be done as follows: -```tsx +```tsx {22,23,24} import { ApolloServer } from "@apollo/server"; import express from "express"; import { expressMiddleware } from "@apollo/server/express4"; @@ -143,11 +136,9 @@ server.start().then(() => { // but the arguments received by `context` vary by integration. // This means they vary for Express, Fastify, Lambda, etc. context: async ({req, res}) => { - // highlight-start return { req, res }; - // highlight-end }, })) @@ -159,18 +150,14 @@ server.start().then(() => { Finally, we can use our `withSession` in our resolvers as shown below: -```tsx +```tsx {8,9,10,11,12,13,14,15,16,17,18} import { ApolloServer } from "@apollo/server"; -declare let getUserName: any; // REMOVE_FROM_OUTPUT -declare let withSession: (contextValue: any, func: (sessoin: any) => Promise) => Promise; // REMOVE_FROM_OUTPUT -declare let typeDefs: any; // REMOVE_FROM_OUTPUT const server = new ApolloServer({ typeDefs, resolvers: { Query: { userProfile: async (_: any, __: any, contextValue) => { - // highlight-start // starts of your resolver code.. return await withSession(contextValue, async (session) => { // getUserName is a custom application function... @@ -182,11 +169,8 @@ const server = new ApolloServer({ name }; }); - // highlight-end } }, }, }) ``` - - diff --git a/docs/quickstart/integrations/hasura.mdx b/docs/quickstart/integrations/hasura.mdx index 36395bd97a..f3f423532a 100644 --- a/docs/quickstart/integrations/hasura.mdx +++ b/docs/quickstart/integrations/hasura.mdx @@ -1,29 +1,22 @@ --- title: Hasura -hide_title: true -sidebar_position: 4 -toc_max_heading_level: 4 description: Learn how to use SuperTokens with Hasura -page_type: tutorial -category: quickstart +sidebar: + order: 4 --- - -import OAuthVerifyTokensCallout from "../../_blocks/oauth-tokens-callout.mdx"; - - -# Hasura Guide - - ## Before you start The tutorial assumes that you already have a working application integrated with **SuperTokens**. -If you have not, please check the [Quickstart Guide](/docs/quickstart/introduction). +If you have not, please check the [Quickstart Guide](/quickstart/introduction). Using SuperTokens with Hasura requires you to host your own API layer that uses our Backend SDK. If you do not want to host your own server you can use a serverless environment to achieve this. - +:::warning[This guide only applies to scenarios which involve **SuperTokens Session Access Tokens**.] + +If you are implementing either, [**Unified Login**](/authentication/unified-login/introduction) or [**Microservice Authentication**](/authentication/m2m/introduction), features that make use of **OAuth2 Access Tokens**, please check the [separate page](/authentication/unified-login/verify-tokens) that shows you how to verify those types of tokens. +::: ## Steps @@ -33,10 +26,10 @@ If you do not want to host your own server you can use a serverless environment For cookie based auth, the access token is not available on the frontend by default. In order to expose it, you need to set the `exposeAccessTokenToFrontendInCookieBasedAuth` config to `true`. - - + + -```tsx +```tsx {15} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -51,17 +44,15 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - //highlight-start exposeAccessTokenToFrontendInCookieBasedAuth: true - //highlight-end }) ] }); ``` - - + + -```go +```go {11} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -72,45 +63,42 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - //highlight-start ExposeAccessTokenToFrontendInCookieBasedAuth: true, - //highlight-end }), }, }) } ``` - - + + -```python +```python {10} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import session init( app_info=InputAppInfo( api_domain="...", app_name="...", website_domain="..."), - framework='...', # type: ignore + framework='...', recipe_list=[ session.init( - # highlight-next-line expose_access_token_to_frontend_in_cookie_based_auth=True, ) ] ) ``` - - + + ### 2. Add custom claims to the JWT Hasura requires claims to be set in a specific way, read the [official documentation](https://hasura.io/docs/latest/graphql/core/auth/authentication/jwt.html) to know more. - - + + -```tsx +```tsx {21,22,23,24,25,26,27,28} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -131,7 +119,6 @@ SuperTokens.init({ return { ...originalImplementation, createNewSession: async function (input) { - //highlight-start input.accessTokenPayload = { ...input.accessTokenPayload, "https://hasura.io/jwt/claims": { @@ -140,7 +127,6 @@ SuperTokens.init({ "x-hasura-allowed-roles": ["user"], } }; - //highlight-end return originalImplementation.createNewSession(input); }, @@ -151,10 +137,10 @@ SuperTokens.init({ ] }); ``` - - + + -```go +```go {22,23,24,25,26,27,28} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -176,7 +162,6 @@ func main() { accessTokenPayload = map[string]interface{}{} } - //highlight-start hasuraClaims := map[string]interface{}{ "x-hasura-user-id": userID, "x-hasura-default-role": "user", @@ -184,7 +169,6 @@ func main() { } accessTokenPayload["https://hasura.io/jwt/claims"] = hasuraClaims - //highlight-end return originalCreateNewSession(userID, accessTokenPayload, sessionDataInDatabase, disableAntiCsrf, tenantId, userContext) } @@ -197,8 +181,8 @@ func main() { }) } ``` - - + + ```python from supertokens_python import init, InputAppInfo @@ -248,7 +232,7 @@ def override_functions(original_implementation: RecipeInterface): init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ session.init( override=session.InputOverrideConfig(functions=override_functions), @@ -258,8 +242,8 @@ init( ) ``` - - + + ### 3. Configure Hasura environment variables @@ -276,16 +260,16 @@ When configuring Hasura, you can set the `jwk_url` property. ```json { - "jwk_url": "^{appInfo.apiDomain}/^{appInfo.apiBasePath}/jwt/jwks.json" + "jwk_url": "//auth/jwt/jwks.json" } ``` -You can get the JWKS URL for your backend by using the method explained [here](/docs/additional-verification/session-verification/protect-api-routes#using-a-jwt-verification-library) +You can get the JWKS URL for your backend by using the method explained [here](/additional-verification/session-verification/protect-api-routes#using-a-jwt-verification-library) #### Using a key string Hasura let's you provide a PEM string in the configuration. -Refer to [this page](/docs/additional-verification/session-verification/protect-api-routes##with-the-public-key-string) to know how to get a public key as a string, you can then use that key string in the Hasura config: +Refer to [this page](/additional-verification/session-verification/protect-api-routes##with-the-public-key-string) to know how to get a public key as a string, you can then use that key string in the Hasura config: ```json { @@ -310,60 +294,53 @@ Functions exposed by our SDK like `verifySession` or `getSession` do these autho #### 5.1 Get the JWT on the frontend - + - + - - + + -```tsx +```tsx {4} import Session from "supertokens-web-js/recipe/session"; async function getToken(): Promise { - // highlight-next-line const accessToken = await Session.getAccessToken(); console.log(accessToken); } ``` - - + + -```tsx -import supertokensSession from "supertokens-web-js-script/recipe/session"; -import supertokensEmailVerification from "supertokens-web-js-script/recipe/emailverification"; +```tsx {2} async function getToken(): Promise { - // highlight-next-line const accessToken = await supertokensSession.getAccessToken(); console.log(accessToken); } ``` - - - + + + - + - - + + -```tsx +```tsx {4} import SuperTokens from 'supertokens-react-native'; async function getToken(): Promise { - // highlight-next-line const accessToken = await SuperTokens.getAccessToken(); console.log(accessToken); } ``` - + - + ```kotlin import android.app.Application @@ -376,9 +353,9 @@ class MainApplication: Application() { } ``` - + - + ```swift import UIKit @@ -391,9 +368,9 @@ fileprivate class ViewController: UIViewController { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -403,27 +380,25 @@ Future getToken() async { } ``` - - + + - + #### 5.2 Make an HTTP requests -```tsx +```tsx {7,8,9} import axios from "axios"; async function makeRequest() { let url = "..."; let jwt = "..."; // Refer to step 5.a let response = await axios.get(url, { - // highlight-start headers: { "Authorization": `Bearer ${jwt}`, }, - // highlight-end }); } ``` @@ -434,4 +409,4 @@ async function makeRequest() { If you are using Hasura cloud and testing your backend APIs in your local environment, JWT verification will fail because Hasura will not be able to query the JWKS endpoint (because the cloud can not query your local environment i.e localhost, 127.0.0.1). To solve this problem you will need to expose your locally hosted backend APIs to the internet. For example you can use [ngrok](https://ngrok.com/). -After that, you need to configure Hasura to use the `/^{appInfo.apiBasePath}/jwt/jwks.json` as the JWKS endpoint (explained in [step 4](#4-configure-hasura-environment-variables)) +After that, you need to configure Hasura to use the `//auth/jwt/jwks.json` as the JWKS endpoint (explained in [step 4](#4-configure-hasura-environment-variables)) diff --git a/docs/quickstart/integrations/meta.ts b/docs/quickstart/integrations/meta.ts new file mode 100644 index 0000000000..ff9c654dd4 --- /dev/null +++ b/docs/quickstart/integrations/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Integrations", + "icon": "puzzle", + "order": 7 +}); diff --git a/docs/quickstart/integrations/nestjs.mdx b/docs/quickstart/integrations/nestjs.mdx index 8008fc9b69..b1434ea401 100644 --- a/docs/quickstart/integrations/nestjs.mdx +++ b/docs/quickstart/integrations/nestjs.mdx @@ -1,21 +1,10 @@ --- title: NestJS -hide_title: true -sidebar_position: 5 -toc_max_heading_level: 4 -description: >- - Integrate SuperTokens with NestJS backend, covering modules, services, - middleware, and session management. -page_type: tutorial -category: quickstart +description: Integrate SuperTokens with NestJS backend, covering modules, services, middleware, and session management. +sidebar: + order: 5 --- - - - - -# NestJS guide - ## Overview @@ -25,7 +14,7 @@ To aid the process you can use the `supertokens-nestjs` package which exposes ab ## Before you start -This guide assumes that you have already completed the [main quickstart guide](/docs/quickstart/introduction). +This guide assumes that you have already completed the [main quickstart guide](/quickstart/introduction). If not, please go through it before continuing with this page. You need to first understand how to configure the required recipes and run a sample project. @@ -77,7 +66,7 @@ export class AppModule {} ``` -:::info Tip +:::info[Tip] You can use the `SuperTokensModule.forRootAsync` if you want to load the configuration asynchronously. ::: @@ -91,9 +80,7 @@ And, the global filter ensures that all authentication related errors get handle import supertokens from 'supertokens-node' import { SuperTokensExceptionFilter } from 'supertokens-nestjs' import { NestFactory } from '@nestjs/core' -// @ts-expect-error import { AppModule } from './app.module' -// @ts-expect-error import { appInfo } from './config' @@ -185,7 +172,7 @@ class AppController { } ``` -:::info tip +:::info[tip] With the `VerifySession` decorator, you can specify the following options: | Option | Type | Description | |--------|------|-------------| @@ -200,25 +187,19 @@ With the `VerifySession` decorator, you can specify the following options: ### 6. Configure SuperTokens core - { - return ( - Are you using https://try.supertokens.com as the connection URI in the init function? - ) - }} defaultAnswer="Yes"> - + + You need to setup an instance of the SuperTokens core for your app (that your backend should connect to). You have two options: -- [Managed service](/docs/quickstart/next-steps#configure-the-core-service) -- [Self hosted](/docs/deployment/self-host-supertokens) +- [Managed service](/quickstart/next-steps#configure-the-core-service) +- [Self hosted](/deployment/self-host-supertokens) - - + + -:::success -You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section. +:::success[You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section.] ::: - - + + diff --git a/docs/quickstart/integrations/netlify.mdx b/docs/quickstart/integrations/netlify.mdx index 2d1e385af0..8f686025a0 100644 --- a/docs/quickstart/integrations/netlify.mdx +++ b/docs/quickstart/integrations/netlify.mdx @@ -1,21 +1,10 @@ --- title: Netlify -hide_title: true -sidebar_position: 6 -toc_max_heading_level: 4 -description: >- - Learn to set up SuperTokens authentication with Netlify using serverless - functions. -page_type: tutorial -category: quickstart +description: Learn to set up SuperTokens authentication with Netlify using serverless functions. +sidebar: + order: 6 --- - -import OAuthVerifyTokensCallout from "../../_blocks/oauth-tokens-callout.mdx"; - -# Netlify Guide - - ## Overview The following guide gets you though how to add SuperTokens to a Netlify serverless API. @@ -24,13 +13,13 @@ You can also check out the [example repository](https://github.com/supertokens/s ## Before you start This guide assumes that you are using Netlify for hosting your serverless API functions. -If this is not the case, and you are only hosting your frontend using Netlify, please follow the [Quick setup guide](/docs/quickstart/frontend-setup) instead. +If this is not the case, and you are only hosting your frontend using Netlify, please follow the [Quick setup guide](/quickstart/frontend-setup) instead. ## Steps ### 1. Setup the frontend -Follow the [initial quickstart guide](/docs/quickstart/frontend-setup) to configure the frontend. +Follow the [initial quickstart guide](/quickstart/frontend-setup) to configure the frontend. ### 2. Setup the backend @@ -48,9 +37,8 @@ An example of this file can be found [here](https://github.com/supertokens/super #### 2.3 Create a backend configuration function - -```tsx title="/config/supertokensConfig.ts" showAppTypeSelect +```tsx title="/config/supertokensConfig.ts" import EmailPassword from 'supertokens-node/recipe/emailpassword'; import Session from 'supertokens-node/recipe/session' @@ -59,16 +47,16 @@ function getBackendConfig() { return { framework: "awsLambda", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo: { // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}", + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", }, recipeList: [ EmailPassword.init(), @@ -99,7 +87,6 @@ import supertokens from "supertokens-node"; import { middleware } from "supertokens-node/framework/awsLambda"; import middy from "@middy/core"; import cors from "@middy/http-cors"; -// @ts-ignore import { getBackendConfig } from "../../config/supertokensConfig"; supertokens.init(getBackendConfig()); @@ -128,8 +115,7 @@ module.exports.handler = middy(middleware(async (event, context) => { }); ``` -:::important -- Notice that we called `supertokens.init` above. We will need to call this in all API endpoints that use any functions related to SuperTokens. +:::note[- Notice that we called `supertokens.init` above. We will need to call this in all API endpoints that use any functions related to SuperTokens.] - `CORS` is only needed if you are hosting your frontend using a separate domain (if your website domain is different that your API's domain). ::: @@ -138,7 +124,10 @@ If you are now able to sign in or sign up, this means the backend setup is done ### 4. Add session verification - +:::warning[This guide only applies to scenarios which involve **SuperTokens Session Access Tokens**.] + +If you are implementing either, [**Unified Login**](/authentication/unified-login/introduction) or [**Microservice Authentication**](/authentication/m2m/introduction), features that make use of **OAuth2 Access Tokens**, please check the [separate page](/authentication/unified-login/verify-tokens) that shows you how to verify those types of tokens. +::: For this guide, we will assume that we want an API `/.netlify/functions/user GET` which returns the current session information. @@ -152,7 +141,6 @@ Remember that whenever we want to use any functions from the `supertokens-node` ```tsx title="netlify/functions/user.ts" import supertokens from "supertokens-node"; -// @ts-ignore import { getBackendConfig } from "../../config/supertokensConfig"; supertokens.init(getBackendConfig()) @@ -168,7 +156,6 @@ import { verifySession } from "supertokens-node/recipe/session/framework/awsLamb import { SessionEvent } from "supertokens-node/framework/awsLambda" import middy from "@middy/core"; import cors from "@middy/http-cors"; -// @ts-ignore import { getBackendConfig } from "../../config/supertokensConfig"; supertokens.init(getBackendConfig()); diff --git a/docs/quickstart/integrations/nextjs/_category_.json b/docs/quickstart/integrations/nextjs/_category_.json deleted file mode 100644 index a8490532b0..0000000000 --- a/docs/quickstart/integrations/nextjs/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "NextJS", - "position": 6 -} diff --git a/docs/quickstart/integrations/nextjs/app-directory/_category_.json b/docs/quickstart/integrations/nextjs/app-directory/_category_.json deleted file mode 100644 index c2cfb08191..0000000000 --- a/docs/quickstart/integrations/nextjs/app-directory/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "App Directory", - "position": 1 -} diff --git a/docs/quickstart/integrations/nextjs/app-directory/about.mdx b/docs/quickstart/integrations/nextjs/app-directory/about.mdx index f632b77a2e..169ffc36a5 100644 --- a/docs/quickstart/integrations/nextjs/app-directory/about.mdx +++ b/docs/quickstart/integrations/nextjs/app-directory/about.mdx @@ -1,22 +1,14 @@ --- -id: about title: About -hide_title: true -show_ui_switcher: true -sidebar_position: 1 -description: >- - Integrate SuperTokens with Next.js for authentication, session verification, - and route protection. -page_type: tutorial -category: quickstart +description: Integrate SuperTokens with Next.js for authentication, session verification, and route protection. +sidebar: + order: 1 --- + - + - - -# Overview steps Integrating SuperTokens with a Next.js app involves: - Calling the frontend and backend init functions @@ -38,15 +30,14 @@ npx create-supertokens-app@latest --frontend=next --recipe=emailpassword - + - + -# Overview steps Integrating SuperTokens with a Next.js app involves: - Calling the frontend and backend init functions -- Building the various auth flows as per the [custom UI setup guide](../../custom-ui/init/frontend). +- Building the various auth flows as per the [custom UI setup guide](/quickstart/frontend-setup). - Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default) - Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page - Performing session verification: @@ -61,8 +52,7 @@ Download and run an example Next.js app quickly using the following command: npx create-supertokens-app@latest --frontend=next --recipe=emailpassword ``` -:::note -This example app uses our pre-built UI +:::note[This example app uses our pre-built UI] ::: - + diff --git a/docs/quickstart/integrations/nextjs/app-directory/init.mdx b/docs/quickstart/integrations/nextjs/app-directory/init.mdx index 42f1050835..c0fa59720d 100644 --- a/docs/quickstart/integrations/nextjs/app-directory/init.mdx +++ b/docs/quickstart/integrations/nextjs/app-directory/init.mdx @@ -1,22 +1,13 @@ --- -id: init title: 1. Configuration -hide_title: true -show_ui_switcher: true -sidebar_position: 2 -description: >- - Configure SuperTokens for authentication in your Next.js app with frontend and - backend setup. -page_type: tutorial -category: quickstart +description: Configure SuperTokens for authentication in your Next.js app with frontend and backend setup. +sidebar: + order: 2 --- + -# 1. Configuration - - - - + ## 1. Install `supertokens` package ```bash @@ -31,24 +22,23 @@ yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors ## 3. Create the `appInfo` configuration. - ```tsx title="app/config/appInfo.ts" export const appInfo = { // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" } ``` - + - + ## 1. Install `supertokens` package ```bash @@ -63,31 +53,29 @@ yarn add supertokens-node supertokens-web-js nextjs-cors ## 3. Create the `appInfo` configuration. - ```tsx title="app/config/appInfo.ts" export const appInfo = { // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo - appName: "^{appInfo.appName}", - websiteDomain: "^{appInfo.websiteDomain}", - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + appName: "", + websiteDomain: "", + apiDomain: "", + apiBasePath: "/auth", } ``` - + - + ## 4. Create a frontend config function ```tsx title="app/config/frontend.tsx" import EmailPasswordReact from 'supertokens-auth-react/recipe/emailpassword' import SessionReact from 'supertokens-auth-react/recipe/session' -// @ts-ignore import { appInfo } from './appInfo' import { useRouter } from "next/navigation"; import { SuperTokensConfig } from 'supertokens-auth-react/lib/build/types' @@ -123,16 +111,15 @@ export const frontendConfig = (): SuperTokensConfig => { } ``` - + - + ## 4. Create a frontend config function ```tsx title="app/config/frontend.tsx" import EmailPasswordWebJs from 'supertokens-web-js/recipe/emailpassword' import SessionWebJs from 'supertokens-web-js/recipe/session' -// @ts-ignore import { appInfo } from './appInfo' import { SuperTokensConfig } from "supertokens-web-js/types" @@ -147,16 +134,15 @@ export const frontendConfig = (): SuperTokensConfig => { } ``` - + ## 5. Create a backend config function -```tsx title="app/config/backend.ts" showAppTypeSelect +```tsx title="app/config/backend.ts" import SuperTokens from "supertokens-node"; import EmailPasswordNode from 'supertokens-node/recipe/emailpassword' import SessionNode from 'supertokens-node/recipe/session' -// @ts-ignore import { appInfo } from './appInfo' import { TypeInput } from "supertokens-node/types"; @@ -164,8 +150,8 @@ export const backendConfig = (): TypeInput => { return { framework: "custom", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo, recipeList: [ @@ -189,7 +175,7 @@ export function ensureSuperTokensInit() { `ensureSuperTokensinit` is a helper function that can be used in your API routes to make sure SuperTokens is initialised before using any functionality exposed by the backend SDKs. - + ## 6. Call the frontend `init` functions and wrap with `` component @@ -199,12 +185,9 @@ export function ensureSuperTokensInit() { ```tsx title="/app/components/supertokensProvider.tsx" 'use client'; -declare let frontendConfig: any; // REMOVE_FROM_OUTPUT -declare let setRouter: any; // REMOVE_FROM_OUTPUT import React from 'react'; import { SuperTokensWrapper } from 'supertokens-auth-react'; import SuperTokensReact from 'supertokens-auth-react'; -// @ts-ignore import { frontendConfig, setRouter } from '../config/frontend'; import { usePathname, useRouter } from 'next/navigation'; @@ -223,11 +206,9 @@ export const SuperTokensProvider: React.FC> = ({ ``` ```tsx title="/app/layout.tsx" -declare let SuperTokensProvider: any; // REMOVE_FROM_OUTPUT import './globals.css' import type { Metadata } from 'next' import { Inter } from 'next/font/google' -// @ts-ignore import { SuperTokensProvider } from "./components/supertokensProvider"; const inter = Inter({ subsets: ['latin'] }) @@ -252,9 +233,9 @@ export default function RootLayout({ } ``` - + - + ## 7. Call the frontend `init` functions and wrap with `` component @@ -265,7 +246,6 @@ export default function RootLayout({ 'use client'; import React from 'react'; import SuperTokensWebJs from 'supertokens-web-js' -// @ts-ignore import { frontendConfig } from '../config/frontend'; if (typeof window !== 'undefined') { @@ -281,13 +261,10 @@ export const SuperTokensInit: React.FC> = ({ ``` ```tsx title="/app/layout.tsx" -declare let frontendConfig: () => any; // REMOVE_FROM_OUTPUT import './globals.css' import type { Metadata } from 'next' import { Inter } from 'next/font/google' -// @ts-ignore import { frontendConfig } from '../config/frontend'; -// @ts-ignore import { SuperTokensInit } from "./components/supertokensInit"; const inter = Inter({ subsets: ['latin'] }) @@ -312,4 +289,4 @@ export default function RootLayout({ } ``` - + diff --git a/docs/quickstart/integrations/nextjs/app-directory/meta.ts b/docs/quickstart/integrations/nextjs/app-directory/meta.ts new file mode 100644 index 0000000000..7dde597468 --- /dev/null +++ b/docs/quickstart/integrations/nextjs/app-directory/meta.ts @@ -0,0 +1,6 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "App Directory", + "order": 1 +}); diff --git a/docs/quickstart/integrations/nextjs/app-directory/next-steps.mdx b/docs/quickstart/integrations/nextjs/app-directory/next-steps.mdx index 2059d25ac3..ec4c5504e6 100644 --- a/docs/quickstart/integrations/nextjs/app-directory/next-steps.mdx +++ b/docs/quickstart/integrations/nextjs/app-directory/next-steps.mdx @@ -1,38 +1,23 @@ --- -id: next-steps title: 7. Next steps -hide_title: true -sidebar_position: 8 -pagination_next: null -description: >- - Set up SuperTokens core for your app using managed service or self-hosting - options. -page_type: tutorial -category: quickstart +description: Set up SuperTokens core for your app using managed service or self-hosting options. +sidebar: + order: 8 --- - -# 7. Next steps - ## Setting up the core and database - { - return ( - Are you using https://try.supertokens.com as the connection URI in the init function? - ) - }} defaultAnswer="Yes"> - + + You need to now setup an instance of the SuperTokens core for your app (that your backend should connect to). You have two options: -- [Managed service](/docs/quickstart/next-steps#configure-the-core-service) -- [Self hosted](/docs/deployment/self-host-supertokens) +- [Managed service](/quickstart/next-steps#configure-the-core-service) +- [Self hosted](/deployment/self-host-supertokens) - - + + -:::success -You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section. +:::success[You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section.] ::: - - + + diff --git a/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/_category_.json b/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/_category_.json deleted file mode 100644 index e08ee8e3e6..0000000000 --- a/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "5. Checking Sessions in API Routes", - "position": 6 -} diff --git a/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/meta.ts b/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/meta.ts new file mode 100644 index 0000000000..240176fb21 --- /dev/null +++ b/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "5. Checking Sessions in API Routes", + "icon": "shield-check", + "order": 6 +}); diff --git a/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-middleware.mdx b/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-middleware.mdx index f4290847b1..090d021b91 100644 --- a/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-middleware.mdx +++ b/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-middleware.mdx @@ -1,30 +1,24 @@ --- -id: session-verification-middleware title: Using the Next.js middleware -hide_title: true -sidebar_position: 2 -description: >- - Implement session verification in Next.js middleware to manage user - authentication and retrieve user IDs. -page_type: tutorial -category: quickstart +description: Implement session verification in Next.js middleware to manage user authentication and retrieve user IDs. +sidebar: + order: 2 --- +:::warning[OAuth2 token verification] +Verify OAuth2 access tokens with your OAuth2/OIDC library instead of the SuperTokens Session SDK. +::: -# Using the Next.js middleware - - - -:::important -This method is an alternative method for using sessions in an API. If you are already using [session guards](./session-verification-session-guard.mdx), you can skip this step. +:::note +This method is an alternative method for using sessions in an API. If you are already using [session guards](./session-verification-session-guard), you can skip this step. ::: ## Setting up the middleware In the middleware we check if a session exists using the `withSession` helper function and set the user's user id to the request headers using the session object. You can set other information in the same way. -:::caution -You cannot pass the full session container through the middleware because the Next.js middleware does not allow objects to be passed. If you need to access the full session container in your APIs switch to using [session guards](./session-verification-session-guard.mdx). +:::warning +You cannot pass the full session container through the middleware because the Next.js middleware does not allow objects to be passed. If you need to access the full session container in your APIs switch to using [session guards](./session-verification-session-guard). ::: ```tsx title="middleware.ts" @@ -32,7 +26,6 @@ import { withSession } from "supertokens-node/nextjs"; import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { SessionContainer } from 'supertokens-node/recipe/session'; -// @ts-ignore import { ensureSuperTokensInit } from "./app/config/backend"; ensureSuperTokensInit(); @@ -80,7 +73,6 @@ The middleware will run for all routes, we can read information set by the middl ```tsx title="app/api/userid/route.ts" import { NextResponse, NextRequest } from "next/server"; -// @ts-ignore import { ensureSuperTokensInit } from '../../config/backend'; ensureSuperTokensInit(); diff --git a/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-session-guard.mdx b/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-session-guard.mdx index c340d4065b..3da347b1d2 100644 --- a/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-session-guard.mdx +++ b/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-session-guard.mdx @@ -1,22 +1,15 @@ --- -id: session-verification-session-guard title: Adding a session guard to each API route -hide_title: true -sidebar_position: 1 -description: >- - Implement session guards for API routes to manage user authentication and - session validation. -page_type: tutorial -category: quickstart +description: Implement session guards for API routes to manage user authentication and session validation. +sidebar: + order: 1 --- +:::warning[OAuth2 token verification] +Verify OAuth2 access tokens with your OAuth2/OIDC library instead of the SuperTokens Session SDK. +::: -# Adding a session guard to each API route - - - -:::note -This is applicable for when the frontend calls an API in the `/app/api` folder. +:::note[This is applicable for when the frontend calls an API in the `/app/api` folder.] ::: For this guide, we will assume that we want an API `/api/user GET` which returns the current session information. @@ -28,7 +21,6 @@ Create a new file `/app/api/user/route.ts` ```ts title="app/api/user/route.ts" import { withSession } from "supertokens-node/nextjs"; import { NextResponse, NextRequest } from "next/server"; -// @ts-ignore import { ensureSuperTokensInit } from '../../config/backend'; ensureSuperTokensInit(); diff --git a/docs/quickstart/integrations/nextjs/app-directory/protecting-route.mdx b/docs/quickstart/integrations/nextjs/app-directory/protecting-route.mdx index fdb5c31c0e..157a05188d 100644 --- a/docs/quickstart/integrations/nextjs/app-directory/protecting-route.mdx +++ b/docs/quickstart/integrations/nextjs/app-directory/protecting-route.mdx @@ -1,25 +1,19 @@ --- -id: protecting-route title: 4. Checking for sessions in frontend routes -hide_title: true -sidebar_position: 5 -description: >- - Learn to protect frontend routes by checking user sessions and handling - session-related events. -page_type: tutorial -category: quickstart +description: Learn to protect frontend routes by checking user sessions and handling session-related events. +sidebar: + order: 5 --- - -# 4. Checking for sessions in frontend routes - - +:::warning[OAuth2 token verification] +Check authentication with your OAuth2/OIDC library when using Unified Login. +::: Protecting a website route means that it cannot be accessed unless a user is signed in. If a non signed in user tries to access it, they will be redirected to the login page. - + - + ## Sessions with Client Components @@ -45,8 +39,7 @@ export const HomeClientComponent = () => { `SessionAuth` is a component exposed by the SuperTokens React SDK, it checks if a session exists and if it does not exist it will redirect the user to the login page. It also does session claim checking on the frontend and take appropriate action if the claim validators fail. For example, if you have set the email verification recipe to be `"REQUIRED"`, and the user's email is not verified, this component will redirect the user to the email verification page. -:::caution -At the moment the `SessionAuth` component does not support server side rendering and will only work on the client side. On the server side, this component renders an empty screen. +:::warning[At the moment the `SessionAuth` component does not support server side rendering and will only work on the client side. On the server side, this component renders an empty screen.] Refer to the next section of this page to learn how to use sessions on the server side. ::: @@ -73,7 +66,7 @@ export const HomeClientComponent = () => {

- Client side component got userId: {session.userId}
+ Client side component got userId: {session.userId}

@@ -83,11 +76,10 @@ export const HomeClientComponent = () => { `useSessionContext` lets you access the session information on the client side using the React Context API. `session.loading` indicates if the session is currently being loaded into the context, this will also refresh the session for you if it is expired. You can use `session.doesSessionExist` to check if a valid session exists and handle it accordingly. -:::info -`useSessionContext` does not need to be used along with `SessionAuth`. Since our app is wrapped by the `SuperTokensWrapper` component, the `useSessionContext` hook can be used in any of our components. +:::info[`useSessionContext` does not need to be used along with `SessionAuth`. Since our app is wrapped by the `SuperTokensWrapper` component, the `useSessionContext` hook can be used in any of our components.] ::: -:::tip Test by navigating to `/` +:::tip[Test by navigating to `/`] You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection. ::: @@ -178,18 +170,15 @@ We then create a server component that can check if the session exists and retur ```tsx title="app/components/home.tsx" import { cookies } from "next/headers"; -declare let SessionAuthForNextJS: any; // REMOVE_FROM_OUTPUT import { redirect } from "next/navigation"; -// @ts-ignore import { TryRefreshComponent } from "./tryRefreshClientComponent"; -// @ts-ignore import { SessionAuthForNextJS } from "./sessionAuthForNextJS"; import jwksClient from "jwks-rsa"; import JsonWebToken from "jsonwebtoken"; import type { JwtHeader, JwtPayload, SigningKeyCallback } from "jsonwebtoken"; const client = jwksClient({ - jwksUri: "^{coreInfo.uri}/.well-known/jwks.json", + jwksUri: "/.well-known/jwks.json", }); async function getAccessToken() { @@ -291,9 +280,7 @@ The `TryRefreshComponent` is a client component that checks if a session exists And then we can modify the `/app/page.tsx` file to use our server component ```tsx title="app/page.tsx" -declare let HomePage: any; // REMOVE_FROM_OUTPUT import styles from './page.module.css' -// @ts-ignore import { HomePage } from "./components/home"; export default function Home() { @@ -305,17 +292,17 @@ export default function Home() { } ``` -:::tip Test by navigating to `/` +:::tip[Test by navigating to `/`] You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection. ::: -:::important +:::note An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/page.tsx). ::: -
+ - + ## Sessions with Client Components @@ -324,7 +311,7 @@ Checking for sessions in client components involves: - Using the `Session` recipe to manually check if a session exists, rendering some default UI while you check. - Render your UI if a session exists. -To learn more about how to do this refer to [this page](/docs/additional-verification/session-verification/protect-frontend-routes). +To learn more about how to do this refer to [this page](/additional-verification/session-verification/protect-frontend-routes). ## Sessions with Server Components @@ -379,16 +366,14 @@ Lets modify the Home page server component we created earlier: ```tsx title="app/components/home.tsx" import { cookies } from "next/headers"; -declare let TryRefreshComponent: any; // REMOVE_FROM_OUTPUT import { redirect } from "next/navigation"; -// @ts-ignore import { TryRefreshComponent } from "./tryRefreshClientComponent"; import jwksClient from "jwks-rsa"; import JsonWebToken from "jsonwebtoken"; import type { JwtHeader, JwtPayload, SigningKeyCallback } from "jsonwebtoken"; const client = jwksClient({ - jwksUri: "^{coreInfo.uri}/.well-known/jwks.json", + jwksUri: "/.well-known/jwks.json", }); async function getAccessToken() { @@ -484,9 +469,7 @@ The `TryRefreshComponent` is a client component that checks if a session exists And then we can modify the `/app/page.tsx` file to use our server component ```tsx title="app/page.tsx" -declare let HomePage: any; // REMOVE_FROM_OUTPUT import styles from './page.module.css' -// @ts-ignore import { HomePage } from "./components/home"; export default function Home() { @@ -498,10 +481,10 @@ export default function Home() { } ``` -:::tip Test by navigating to `/` +:::tip[Test by navigating to `/`] You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection. For custom UI SuperTokens provides no login UI, the code above will redirect the user to the `/auth` route but you will have to build some UI that is served on that route. ::: - + diff --git a/docs/quickstart/integrations/nextjs/app-directory/server-components-requests.mdx b/docs/quickstart/integrations/nextjs/app-directory/server-components-requests.mdx index 1ad63d0326..231685fe10 100644 --- a/docs/quickstart/integrations/nextjs/app-directory/server-components-requests.mdx +++ b/docs/quickstart/integrations/nextjs/app-directory/server-components-requests.mdx @@ -1,39 +1,27 @@ --- -id: server-components-requests title: 6. Making requests from Server Components -hide_title: true -sidebar_position: 7 -description: >- - Learn to make API requests from server components using access tokens in - Next.js. -page_type: tutorial -category: quickstart +description: Learn to make API requests from server components using access tokens in Next.js. +sidebar: + order: 7 --- +Lets modify the Home page we made in a [previous step](/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-session-guard) to make a call to this API -# 6. Making requests from Server Components + -Lets modify the Home page we made in a [previous step](/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-session-guard) to make a call to this API + - - - - -```tsx title="app/components/home.tsx" +```tsx title="app/components/home.tsx" {94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119} import { cookies } from "next/headers"; -declare let TryRefreshComponent: any; // REMOVE_FROM_OUTPUT -declare let SessionAuthForNextJS: any; // REMOVE_FROM_OUTPUT import { redirect } from "next/navigation"; -// @ts-ignore import { TryRefreshComponent } from "./tryRefreshClientComponent"; -// @ts-ignore import { SessionAuthForNextJS } from "./sessionAuthForNextJS"; import jwksClient from "jwks-rsa"; import JsonWebToken from "jsonwebtoken"; import type { JwtHeader, JwtPayload, SigningKeyCallback } from "jsonwebtoken"; const client = jwksClient({ - jwksUri: "^{coreInfo.uri}/.well-known/jwks.json", + jwksUri: "/.well-known/jwks.json", }); async function getAccessToken() { @@ -117,7 +105,6 @@ export async function HomePage() { return ; } - // highlight-start const userInfoResponse = await fetch('http://localhost:3000/api/user', { headers: { /** @@ -144,7 +131,6 @@ export async function HomePage() { } // You can use `userInfoResponse` to read the users session information - // highlight-end return ( @@ -158,21 +144,19 @@ export async function HomePage() { We read the access token of the user from cookies. We can then send the access token as a header to the API. When the API calls `withSession` it will try to read the access token from the headers and if a session exists it will return the session information. - + - + -```tsx title="app/components/home.tsx" +```tsx title="app/components/home.tsx" {91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119} import { cookies } from "next/headers"; -declare let TryRefreshComponent: any; // REMOVE_FROM_OUTPUT import { redirect } from "next/navigation"; -// @ts-ignore import { TryRefreshComponent } from "./tryRefreshClientComponent";import jwksClient from "jwks-rsa"; import JsonWebToken from "jsonwebtoken"; import type { JwtHeader, JwtPayload, SigningKeyCallback } from "jsonwebtoken"; const client = jwksClient({ - jwksUri: "^{coreInfo.uri}/.well-known/jwks.json", + jwksUri: "/.well-known/jwks.json", }); async function getAccessToken() { @@ -255,7 +239,6 @@ export async function HomePage() { return ; } - // highlight-start const userInfoResponse = await fetch('http://localhost:3000/api/user', { headers: { /** @@ -285,7 +268,6 @@ export async function HomePage() { } // You can use `userInfoResponse` to read the users session information - // highlight-end return (
@@ -297,6 +279,6 @@ export async function HomePage() { APIs that require sessions will return status: - `401` if there is no valid session or if the session has expired. In this case we return the `TryRefreshComponent` component which will try to refresh the session or redirect to the login page if the session cant be refreshed. -- `403` if one or more of the session claims fail their validation. In this case you should check which session claim failed and redirect the user accordingly. For example to check for the email verification claim you can refer to [this page](/docs/additional-verification/email-verification/protecting-routes). +- `403` if one or more of the session claims fail their validation. In this case you should check which session claim failed and redirect the user accordingly. For example to check for the email verification claim you can refer to [this page](/additional-verification/email-verification/protecting-routes). - + diff --git a/docs/quickstart/integrations/nextjs/app-directory/setting-up-backend.mdx b/docs/quickstart/integrations/nextjs/app-directory/setting-up-backend.mdx index 15d5f9f114..f685dd5a00 100644 --- a/docs/quickstart/integrations/nextjs/app-directory/setting-up-backend.mdx +++ b/docs/quickstart/integrations/nextjs/app-directory/setting-up-backend.mdx @@ -1,18 +1,10 @@ --- -id: setting-up-backend title: 3. Adding auth APIs -hide_title: true -sidebar_position: 4 -description: >- - Add authentication APIs to your backend using SuperTokens for sign in and sign - up functionality. -page_type: tutorial -category: quickstart +description: Add authentication APIs to your backend using SuperTokens for sign in and sign up functionality. +sidebar: + order: 4 --- - -# 3. Adding auth APIs - We will add all the backend APIs for auth on `/api/auth`. This can be changed by setting the `apiBasePath` property in the `appInfo` object in the `appInfo.ts` file. For the rest of this page, we will assume you are using `/api/auth`. ## 1. Create the `app/api/auth/[[...path]]/route.ts` route @@ -22,13 +14,10 @@ We will add all the backend APIs for auth on `/api/auth`. This can be changed by ## 2. Expose the SuperTokens APIs - ```tsx title="app/api/auth/[[...path]]/route.ts" -declare let ensureSuperTokensInit: () => void; // REMOVE_FROM_OUTPUT import { getAppDirRequestHandler } from 'supertokens-node/nextjs'; import { NextRequest, NextResponse } from 'next/server'; -// @ts-ignore import { ensureSuperTokensInit } from '../../../config/backend'; ensureSuperTokensInit(); @@ -68,8 +57,7 @@ export async function HEAD(request: NextRequest) { } ``` -:::note -In the snippet above we add the `Cache-Control` header to the responses for all auth APIs with the `GET` method. This is required if you are deploying your app with Vercel because API responses are automatically cached for production deployments. This results in problems because APIs such as `/session/refresh` return older session tokens resulting in infinite calls to refresh if an API returns unauthorised status. Setting the header ensures that Vercel does not cache any of the auth API responses. +:::note[In the snippet above we add the `Cache-Control` header to the responses for all auth APIs with the `GET` method. This is required if you are deploying your app with Vercel because API responses are automatically cached for production deployments. This results in problems because APIs such as `/session/refresh` return older session tokens resulting in infinite calls to refresh if an API returns unauthorised status. Setting the header ensures that Vercel does not cache any of the auth API responses.] ::: ## 3. Use the login widget diff --git a/docs/quickstart/integrations/nextjs/app-directory/setting-up-frontend.mdx b/docs/quickstart/integrations/nextjs/app-directory/setting-up-frontend.mdx index 4957ce7d17..6b67568bac 100644 --- a/docs/quickstart/integrations/nextjs/app-directory/setting-up-frontend.mdx +++ b/docs/quickstart/integrations/nextjs/app-directory/setting-up-frontend.mdx @@ -1,19 +1,13 @@ --- -id: setting-up-frontend title: 2. Showing the Login UI -hide_title: true -sidebar_position: 3 description: Implement a login UI using SuperTokens in a Next.js application. -page_type: tutorial -category: quickstart +sidebar: + order: 3 --- + -# 2. Showing the Login UI - - - - + ## 1. Create the `app/auth/[[...path]]/page.tsx` page - Be sure to create the `auth/[[...path]]` folder in the `app` folder. @@ -57,10 +51,10 @@ If you see a login UI, then you have successfully completed this step! You can a If you cannot see the UI in your app, please feel free to ask questions on [Discord](https://supertokens.com/discord) - + - + -You need to build your own UI. You will have to check each [authentication method tutorial](/docs/authentication/overview) for detailed instructions how how to achieve this. +You need to build your own UI. You will have to check each [authentication method tutorial](/authentication/overview) for detailed instructions how how to achieve this. - + diff --git a/docs/quickstart/integrations/nextjs/meta.ts b/docs/quickstart/integrations/nextjs/meta.ts new file mode 100644 index 0000000000..50ca541602 --- /dev/null +++ b/docs/quickstart/integrations/nextjs/meta.ts @@ -0,0 +1,6 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "NextJS", + "order": 6 +}); diff --git a/docs/quickstart/integrations/nextjs/pages-directory/_category_.json b/docs/quickstart/integrations/nextjs/pages-directory/_category_.json deleted file mode 100644 index 925eddf18b..0000000000 --- a/docs/quickstart/integrations/nextjs/pages-directory/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Pages Directory", - "position": 1 -} diff --git a/docs/quickstart/integrations/nextjs/pages-directory/about.mdx b/docs/quickstart/integrations/nextjs/pages-directory/about.mdx index a7920d578d..9a5fde7123 100644 --- a/docs/quickstart/integrations/nextjs/pages-directory/about.mdx +++ b/docs/quickstart/integrations/nextjs/pages-directory/about.mdx @@ -1,21 +1,14 @@ --- -id: about title: About -hide_title: true -sidebar_position: 1 -description: >- - Integrate SuperTokens with Next.js for authentication, session verification, - and route protection. -page_type: tutorial -category: quickstart +description: Integrate SuperTokens with Next.js for authentication, session verification, and route protection. +sidebar: + order: 1 --- + - + - - -# Overview steps Integrating SuperTokens with a Next.js app involves: - Calling the frontend and backend init functions @@ -33,15 +26,14 @@ Download and run an example Next.js app quickly using the following command: npx create-supertokens-app@latest --frontend=next --recipe=emailpassword ``` - + - + -# Overview steps Integrating SuperTokens with a Next.js app involves: - Calling the frontend and backend init functions -- Building the various auth flows as per the [custom UI setup guide](../custom-ui/init/frontend). +- Building the various auth flows as per the [custom UI setup guide](/quickstart/frontend-setup). - Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default) - Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page - Performing session verification: @@ -56,8 +48,7 @@ Download and run an example Next.js app quickly using the following command: npx create-supertokens-app@latest --frontend=next --recipe=emailpassword ``` -:::note -This example app uses our pre-built UI +:::note[This example app uses our pre-built UI] ::: - + diff --git a/docs/quickstart/integrations/nextjs/pages-directory/init.mdx b/docs/quickstart/integrations/nextjs/pages-directory/init.mdx index ce003c535e..dab01274aa 100644 --- a/docs/quickstart/integrations/nextjs/pages-directory/init.mdx +++ b/docs/quickstart/integrations/nextjs/pages-directory/init.mdx @@ -1,21 +1,13 @@ --- -id: init title: 1. Configuration -hide_title: true -sidebar_position: 2 -description: >- - Configure SuperTokens for authentication in your Next.js app with frontend and - backend setup. -page_type: tutorial -category: quickstart +description: Configure SuperTokens for authentication in your Next.js app with frontend and backend setup. +sidebar: + order: 2 --- + -# 1. Configuration - - - - + ## 1. Install `supertokens` package ```bash @@ -31,24 +23,23 @@ yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors ## 3. Create the `appInfo` configuration. - ```tsx title="/config/appInfo.ts" export const appInfo = { // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - websiteDomain: "^{appInfo.websiteDomain}", - apiBasePath: "^{appInfo.apiBasePath}", - websiteBasePath: "^{appInfo.websiteBasePath}" + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" } ``` - + - + ## 1. Install `supertokens` package ```bash @@ -64,30 +55,28 @@ yarn add supertokens-node supertokens-web-js nextjs-cors ## 3. Create the `appInfo` configuration. - ```tsx title="/config/appInfo.ts" export const appInfo = { // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo - appName: "^{appInfo.appName}", - apiDomain: "^{appInfo.apiDomain}", - apiBasePath: "^{appInfo.apiBasePath}", + appName: "", + apiDomain: "", + apiBasePath: "/auth", } ``` - + - + ## 4. Create a frontend config function ```tsx title="/config/frontendConfig.ts" import EmailPasswordReact from 'supertokens-auth-react/recipe/emailpassword' import SessionReact from 'supertokens-auth-react/recipe/session' -// @ts-ignore import { appInfo } from './appInfo' import Router from 'next/router' @@ -113,16 +102,15 @@ export const frontendConfig = () => { } ``` - + - + ## 4. Create a frontend config function ```tsx title="/config/frontendConfig.ts" import EmailPasswordWebJs from 'supertokens-web-js/recipe/emailpassword' import SessionWebJs from 'supertokens-web-js/recipe/session' -// @ts-ignore import { appInfo } from './appInfo' export const frontendConfig = () => { @@ -136,15 +124,14 @@ export const frontendConfig = () => { } ``` - + ## 5. Create a backend config function -```tsx title="/config/backendConfig.ts" showAppTypeSelect +```tsx title="/config/backendConfig.ts" import EmailPasswordNode from 'supertokens-node/recipe/emailpassword' import SessionNode from 'supertokens-node/recipe/session' -// @ts-ignore import { appInfo } from './appInfo' import { TypeInput } from "supertokens-node/types"; @@ -152,8 +139,8 @@ export const backendConfig = (): TypeInput => { return { framework: "express", supertokens: { - connectionURI: "^{coreInfo.uri}", - apiKey: "^{coreInfo.key}", + connectionURI: "", + apiKey: "", }, appInfo, recipeList: [ @@ -167,34 +154,30 @@ export const backendConfig = (): TypeInput => { ``` - + ## 6. Call the frontend `init` functions and wrap with `` component - Create a `/pages/_app.tsx` file. You can learn more about this file [here](https://nextjs.org/docs/advanced-features/custom-app). -```tsx title="/pages/_app.tsx" +```tsx title="/pages/_app.tsx" {10,15,17} import '../styles/globals.css' import React from 'react' import { AppProps } from 'next/app' import SuperTokensReact, { SuperTokensWrapper } from 'supertokens-auth-react' -// @ts-ignore import { frontendConfig } from '../config/frontendConfig' if (typeof window !== 'undefined') { // we only want to call this init function on the frontend, so we check typeof window !== 'undefined' - // highlight-next-line SuperTokensReact.init(frontendConfig()) } function MyApp({ Component, pageProps }: AppProps) { return ( - // highlight-next-line - // highlight-next-line ); } @@ -202,27 +185,25 @@ function MyApp({ Component, pageProps }: AppProps) { export default MyApp ``` - + - + ## 7. Call the frontend `init` functions - Create a `/pages/_app.tsx` file. You can learn more about this file [here](https://nextjs.org/docs/advanced-features/custom-app). -```tsx title="/pages/_app.ts" +```tsx title="/pages/_app.ts" {10} import '../styles/globals.css' import React from 'react' import { AppProps } from 'next/app' import SuperTokensWebJs from 'supertokens-web-js' -// @ts-ignore import { frontendConfig } from '../config/frontendConfig' if (typeof window !== 'undefined') { // we only want to call this init function on the frontend, so we check typeof window !== 'undefined' - // highlight-next-line SuperTokensWebJs.init(frontendConfig()) } @@ -235,4 +216,4 @@ function MyApp({ Component, pageProps }: AppProps) { export default MyApp ``` - + diff --git a/docs/quickstart/integrations/nextjs/pages-directory/meta.ts b/docs/quickstart/integrations/nextjs/pages-directory/meta.ts new file mode 100644 index 0000000000..cb33e7b433 --- /dev/null +++ b/docs/quickstart/integrations/nextjs/pages-directory/meta.ts @@ -0,0 +1,6 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Pages Directory", + "order": 1 +}); diff --git a/docs/quickstart/integrations/nextjs/pages-directory/next-steps.mdx b/docs/quickstart/integrations/nextjs/pages-directory/next-steps.mdx index e530063272..f48f4159a5 100644 --- a/docs/quickstart/integrations/nextjs/pages-directory/next-steps.mdx +++ b/docs/quickstart/integrations/nextjs/pages-directory/next-steps.mdx @@ -1,38 +1,23 @@ --- -id: next-steps title: 6. Next steps -hide_title: true -sidebar_position: 7 -pagination_next: null -description: >- - Set up SuperTokens core and database for your app with managed or self-hosted - options. -page_type: tutorial -category: quickstart +description: Set up SuperTokens core and database for your app with managed or self-hosted options. +sidebar: + order: 7 --- - -# 6. Next steps - ## Setting up the core and database - { - return ( - Are you using https://try.supertokens.com as the connection URI in the init function? - ) - }} defaultAnswer="Yes"> - + + You need to now setup an instance of the SuperTokens core for your app (that your backend should connect to). You have two options: -- [Managed service](/docs/quickstart/next-steps#configure-the-core-service) -- [Self hosted](/docs/deployment/self-host-supertokens) +- [Managed service](/quickstart/next-steps#configure-the-core-service) +- [Self hosted](/deployment/self-host-supertokens) - - + + -:::success -You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section. +:::success[You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section.] ::: - - + + diff --git a/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/_category_.json b/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/_category_.json deleted file mode 100644 index 65357b8f1b..0000000000 --- a/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Checking Sessions in API Routes", - "position": 6 -} diff --git a/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-api.mdx b/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-api.mdx index 1bdf9f5229..1561f7f686 100644 --- a/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-api.mdx +++ b/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-api.mdx @@ -1,22 +1,15 @@ --- -id: in-api title: 5a. Session verification in an API call -hide_title: true -sidebar_position: 1 -description: >- - Implement session verification in API calls to securely fetch user session - data. -page_type: tutorial -category: quickstart +description: Implement session verification in API calls to securely fetch user session data. +sidebar: + order: 1 --- +:::warning[OAuth2 token verification] +Verify OAuth2 access tokens with your OAuth2/OIDC library instead of the SuperTokens Session SDK. +::: -# 5a. Session verification in an API call - - - -:::note -This is applicable for when the frontend calls an API in the `/pages/api` folder. +:::note[This is applicable for when the frontend calls an API in the `/pages/api` folder.] ::: For this guide, we will assume that we want an API `/api/user GET` which returns the current session information. @@ -28,7 +21,6 @@ Remember that whenever we want to use any functions from the `supertokens-node` ```tsx title="pages/api/user.ts" import supertokens from 'supertokens-node' -// @ts-ignore import { backendConfig } from '../../../config/backendConfig' supertokens.init(backendConfig()) @@ -36,13 +28,11 @@ supertokens.init(backendConfig()) ## 3. Call the `verifySession` session function - ```tsx title="pages/api/user.ts" import { superTokensNextWrapper } from 'supertokens-node/nextjs' import { verifySession } from 'supertokens-node/recipe/session/framework/express' import supertokens from 'supertokens-node' -// @ts-ignore import { backendConfig } from '../../../config/backendConfig' import NextCors from "nextjs-cors"; @@ -53,7 +43,7 @@ export default async function user(req: any, res: any) { // NOTE: We need CORS only if we are querying the APIs from a different origin await NextCors(req, res, { methods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"], - origin: "^{appInfo.websiteDomain}", + origin: "", credentials: true, allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()], }); @@ -79,4 +69,4 @@ export default async function user(req: any, res: any) { ``` - If no session exists, the API will return a `401` error to the client. In this case, the code `return res.json` will not be executed at all. -- In case the session does exist, `req.session` can be used to get session information. Learn more about this object [here](/docs/additional-verification/session-verification/protect-api-routes#using-verify-session). +- In case the session does exist, `req.session` can be used to get session information. Learn more about this object [here](/additional-verification/session-verification/protect-api-routes#using-verify-session). diff --git a/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-ssr.mdx b/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-ssr.mdx index 548138b8c4..cced9d24b7 100644 --- a/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-ssr.mdx +++ b/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-ssr.mdx @@ -1,22 +1,15 @@ --- -id: in-ssr title: 5b. Session verification in getServerSideProps -hide_title: true -sidebar_position: 2 -description: >- - Verify user sessions in Next.js using `getServerSideProps` for secure route - access. -page_type: tutorial -category: quickstart +description: Verify user sessions in Next.js using `getServerSideProps` for secure route access. +sidebar: + order: 2 --- +:::warning[OAuth2 token verification] +Verify OAuth2 access tokens with your OAuth2/OIDC library instead of the SuperTokens Session SDK. +::: -# 5b. Session verification in getServerSideProps - - - -:::note -This is applicable for when verifying a session in `getServerSideProps` or `getInitialProps`. +:::note[This is applicable for when verifying a session in `getServerSideProps` or `getInitialProps`.] ::: For this guide, we will assume that we want to pass the logged in user's ID as a prop to a protected route. @@ -29,7 +22,7 @@ import type { JwtHeader, JwtPayload, SigningKeyCallback } from "jsonwebtoken"; import { GetServerSidePropsContext } from 'next'; const client = jwksClient({ - jwksUri: "^{coreInfo.uri}/.well-known/jwks.json", + jwksUri: "/.well-known/jwks.json", async fetcher(jwksUri) { return fetch(jwksUri).then((res) => res.json()); }, @@ -116,15 +109,14 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { } ``` -:::caution -Don't use `getSession` or `verifySession` here. They might update the session tokens, and since our request interceptors don't run server-side, the updated token won't be propagated to the client side. +:::warning[Don't use `getSession` or `verifySession` here. They might update the session tokens, and since our request interceptors don't run server-side, the updated token won't be propagated to the client side.] ::: ## 2. Doing manual refresh on the frontend - + - + - The following will refresh a session if needed, for all your website pages - This goes in the `/pages/_app.tsx` file @@ -174,9 +166,9 @@ function MyApp({ Component, pageProps }: AppProps<{fromSupertokens: string}>) { export default MyApp ``` - + - + ```tsx title="/pages/_app.tsx" import React, { useEffect } from "react"; @@ -224,7 +216,7 @@ function MyApp({ Component, pageProps }: AppProps<{fromSupertokens: string}>) { export default MyApp ``` - + ## 3. Consume the `userId` returned by getServerSideProps in your component @@ -232,7 +224,6 @@ On success, `getServerSideProps` returns ```tsx { // Refer to Step 1) - // @ts-ignore props: { userId: accessTokenPayload.sub } } ``` diff --git a/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/meta.ts b/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/meta.ts new file mode 100644 index 0000000000..408f642dee --- /dev/null +++ b/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Checking Sessions in API Routes", + "icon": "shield-check", + "order": 6 +}); diff --git a/docs/quickstart/integrations/nextjs/pages-directory/protecting-route.mdx b/docs/quickstart/integrations/nextjs/pages-directory/protecting-route.mdx index 094a7a9757..8f4cb4ec14 100644 --- a/docs/quickstart/integrations/nextjs/pages-directory/protecting-route.mdx +++ b/docs/quickstart/integrations/nextjs/pages-directory/protecting-route.mdx @@ -1,24 +1,19 @@ --- -id: protecting-route title: 4. Protecting a website route -hide_title: true -sidebar_position: 5 -description: >- - Protect website routes by requiring user authentication and redirecting - unauthenticated users to login. -page_type: tutorial -category: quickstart +description: Protect website routes by requiring user authentication and redirecting unauthenticated users to login. +sidebar: + order: 5 --- -import { OAuthFrontendVerificationCallout } from "/src/components/Callouts"; +:::warning +This information only applies when using **SuperTokens Session Access Tokens**. -# 4. Protecting a website route - - +When implementing [Unified Login](/authentication/unified-login/introduction), check the authentication state using your OAuth2/OIDC library. +::: - + - + Protecting a website route means that it cannot be accessed unless a user is signed in. If a non signed in user tries to access it, they will be redirected to the login page. @@ -28,7 +23,6 @@ Let's say we want to protect the home page of your website (`/` route). In this import React from 'react' import dynamic from 'next/dynamic' import { SessionAuth } from 'supertokens-auth-react/recipe/session' -// @ts-ignore import ProtectedPage from "./protectedPage"; export default function Home() { @@ -41,13 +35,13 @@ export default function Home() { } ``` -:::tip Test by navigating to `/` +:::tip[Test by navigating to `/`] You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection. ::: - + - + Protecting a website route means that it cannot be accessed unless a user is signed in. If a non signed in user tries to access it, they will be redirected to the login page. @@ -65,4 +59,4 @@ async function doesSessionExist() { } ``` - + diff --git a/docs/quickstart/integrations/nextjs/pages-directory/setting-up-backend.mdx b/docs/quickstart/integrations/nextjs/pages-directory/setting-up-backend.mdx index afea60506c..ff7ad0c7af 100644 --- a/docs/quickstart/integrations/nextjs/pages-directory/setting-up-backend.mdx +++ b/docs/quickstart/integrations/nextjs/pages-directory/setting-up-backend.mdx @@ -1,18 +1,10 @@ --- -id: setting-up-backend title: 3. Adding auth APIs -hide_title: true -sidebar_position: 4 -description: >- - Add authentication APIs to your backend using SuperTokens for user sign-in and - sign-up. -page_type: tutorial -category: quickstart +description: Add authentication APIs to your backend using SuperTokens for user sign-in and sign-up. +sidebar: + order: 4 --- - -# 3. Adding auth APIs - We will add all the backend APIs for auth on `/api/auth`. This can be changed by setting the `apiBasePath` property in the `appInfo` object in the `appInfo.ts` file. For the rest of this page, we will assume you are using `/api/auth`. ## 1. Create the `pages/api/auth/[[...path]].tsx` page @@ -21,7 +13,6 @@ We will add all the backend APIs for auth on `/api/auth`. This can be changed by ## 2. Expose the SuperTokens APIs - ```tsx title="pages/api/auth/[[...path]].ts" import { superTokensNextWrapper } from 'supertokens-node/nextjs' @@ -29,7 +20,6 @@ import { middleware } from 'supertokens-node/framework/express' import { NextApiRequest, NextApiResponse } from 'next' import { Request, Response } from 'express'; import supertokens from 'supertokens-node' -// @ts-ignore import { backendConfig } from '../../../config/backendConfig' import NextCors from "nextjs-cors"; @@ -42,7 +32,7 @@ export default async function superTokens( await NextCors(req, res, { methods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"], - origin: "^{appInfo.websiteDomain}", + origin: "", credentials: true, allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()], }); @@ -64,8 +54,7 @@ export default async function superTokens( } ``` -:::note -In the snippet above we add the `Cache-Control` header to the responses for all auth APIs. This is required if you are deploying your app with Vercel because API responses are automatically cached for production deployments. This results in problems because APIs such as `/session/refresh` return older session tokens resulting in infinite calls to refresh if an API returns unauthorised status. Setting the header ensures that Vercel does not cache any of the auth API responses. +:::note[In the snippet above we add the `Cache-Control` header to the responses for all auth APIs. This is required if you are deploying your app with Vercel because API responses are automatically cached for production deployments. This results in problems because APIs such as `/session/refresh` return older session tokens resulting in infinite calls to refresh if an API returns unauthorised status. Setting the header ensures that Vercel does not cache any of the auth API responses.] ::: ## 3. Use the login widget diff --git a/docs/quickstart/integrations/nextjs/pages-directory/setting-up-frontend.mdx b/docs/quickstart/integrations/nextjs/pages-directory/setting-up-frontend.mdx index b1e00792d9..a89ada2a7b 100644 --- a/docs/quickstart/integrations/nextjs/pages-directory/setting-up-frontend.mdx +++ b/docs/quickstart/integrations/nextjs/pages-directory/setting-up-frontend.mdx @@ -1,19 +1,13 @@ --- -id: setting-up-frontend title: 2. Showing Login UI -hide_title: true -sidebar_position: 3 description: Implement a login UI using SuperTokens in a Next.js application. -page_type: tutorial -category: quickstart +sidebar: + order: 3 --- + -# 2. Showing the Login UI - - - - + ## 1. Create the `pages/auth/[[...path]].tsx` page - Be sure to create the `auth` folder in the `pages` folder. @@ -54,10 +48,10 @@ If you see a login UI, then you have successfully completed this step! You can a If you cannot see the UI in your app, please feel free to ask questions on [Discord](https://supertokens.com/discord) - + - + -You need to build your own UI. You will have to check each [authentication method tutorial](/docs/authentication/overview) for detailed instructions how how to achieve this. +You need to build your own UI. You will have to check each [authentication method tutorial](/authentication/overview) for detailed instructions how how to achieve this. - + diff --git a/docs/quickstart/integrations/overview.mdx b/docs/quickstart/integrations/overview.mdx index 8502eea13d..caf0f44a44 100644 --- a/docs/quickstart/integrations/overview.mdx +++ b/docs/quickstart/integrations/overview.mdx @@ -1,100 +1,59 @@ --- title: Overview -sidebar_position: 1 -pagination_next: null -pagination_prev: null -hide_table_of_contents: true -skip_llms_txt: true -description: >- - Explore different integration guides that present how to use SuperTokens with - different platforms and frameworks. -page_type: tutorial -category: quickstart +description: Explore different integration guides that present how to use SuperTokens with different platforms and frameworks. +sidebar: + order: 1 --- +Explore different integration guides that present how to use SuperTokens with different platforms and frameworks. +--- -# Overview - - Explore different integration guides that present how to use SuperTokens with different platforms and frameworks. - +## Frameworks - + + + + -## Frameworks + + + + - - - - Next.js App Router - - - - - Next.js Pages Router - - - - - - NestJS - - - - - GraphQL - - - - - - RedwoodJS - - - - - Capacitor - - - + + + + + + + + ## Cloud Platforms - - - - AWS Lambda - - - - - Netlify - - - - - - Vercel - - - - - Hasura - - - - - - - Supabase - - - - + + + + + + + + + + + + + + + + + + diff --git a/docs/quickstart/integrations/supabase.mdx b/docs/quickstart/integrations/supabase.mdx index 750af661ce..36c1eba9a4 100644 --- a/docs/quickstart/integrations/supabase.mdx +++ b/docs/quickstart/integrations/supabase.mdx @@ -1,17 +1,10 @@ --- title: Supabase -hide_title: true -sidebar_position: 8 -description: >- - Integrate SuperTokens with Supabase in a Next.js app for secure user data - management. -page_type: tutorial -category: quickstart +description: Integrate SuperTokens with Supabase in a Next.js app for secure user data management. +sidebar: + order: 8 --- - -# Supabase Guide - ## Overview The following guide shows you how to integrate a Next.js app with SuperTokens and Supabase. @@ -27,7 +20,7 @@ You can also check an [example repository](https://github.com/supertokens/supert ## Before you start The guide does not include instructions on how to setup a Next.js app with SuperTokens. -To do this you can follow the [app router](/docs/quickstart/integrations/nextjs/app-directory/about) or [pages router](/docs/quickstart/integrations/nextjs/app-directory/about) instructions. +To do this you can follow the [app router](/quickstart/integrations/nextjs/app-directory/about) or [pages router](/quickstart/integrations/nextjs/app-directory/about) instructions. ## Steps @@ -43,7 +36,7 @@ Supabase provides a database with authentication and authorization features. Thi 4. Select the same Region you host your app's backend in. 5. Click Create new project. -![Supabase dashboard](/img/thirdpartyemailpassword/supabase/supabase_dashboard_create.png) +![Supabase dashboard](/docs/img/thirdpartyemailpassword/supabase/supabase_dashboard_create.png) #### 1.2 Create the user table in Supabase @@ -56,7 +49,7 @@ Supabase provides a database with authentication and authorization features. Thi - email as `varchar` 6. Click `Save` to create the new table. -![Supabase table create](/img/thirdpartyemailpassword/supabase/supabase_table_create.png) +![Supabase table create](/docs/img/thirdpartyemailpassword/supabase/supabase_table_create.png) ### 2. Setup JWT creation @@ -65,7 +58,7 @@ This token is used on the frontend and backend to read and write to Supabase's d #### 2.1 Integrate your Next.js app with SuperTokens -Follow either the [app router](/docs/quickstart/integrations/nextjs/app-directory/about) or [pages router](/docs/quickstart/integrations/nextjs/app-directory/about) guides for instructions on how to configure your application. +Follow either the [app router](/quickstart/integrations/nextjs/app-directory/about) or [pages router](/quickstart/integrations/nextjs/app-directory/about) guides for instructions on how to configure your application. #### 2.2 Save the Supabase configuration values @@ -120,7 +113,6 @@ let backendConfig = (): TypeInput => { }, appInfo, recipeList: [ - // @ts-ignore EmailPassword.init({/*...*/}), SessionNode.init({ override: { @@ -217,7 +209,7 @@ let backendConfig = (): TypeInput => { }, appInfo, recipeList: [ - ^{recipeNameCapitalLetters}.init({ + .init({ override: { apis: (originalImplementation) => { return { @@ -269,9 +261,9 @@ When a user signs up, the `supabase_token` is retrieved from the user's `accessT ### 5. Retrieve the user email on the frontend - + - + With the backend setup, the frontend can be modified to retrieve the user's email from Supabase. @@ -342,9 +334,9 @@ function ProtectedPage() { } ``` - + - + With the backend setup, the frontend can be modified to retrieve the user's email from Supabase. @@ -370,7 +362,7 @@ async function getEmailFromSupabase() { } ``` - + As seen above, the access token payload is fetched from SuperTokens to retrieve the authenticated user's Supabase access token which can be used to fetch the user's email from Supabase. @@ -410,11 +402,11 @@ The first policy checks whether the user is the owner of the email being retriev - Select `Authentication` from the Supabase sidebar menu, click `Policies`, and then `New Policy` on the `Users` table. - ![Create policy](/img/thirdpartyemailpassword/supabase/create_policy.png) + ![Create policy](/docs/img/thirdpartyemailpassword/supabase/create_policy.png) - From the modal, select `Create a policy from scratch` and add the following. - ![select policy](/img/thirdpartyemailpassword/supabase/policy_config_select.png) + ![select policy](/docs/img/thirdpartyemailpassword/supabase/policy_config_select.png) - This policy is calling the PostgreSQL function we just created to get the currently logged in user's ID `auth.user_id()` and checking whether this matches the `user_id` column for the current `email`. If it does, then it allows the user to select it, otherwise it continues to deny. @@ -426,7 +418,7 @@ The second policy checks whether the `user_id` being inserted is the same as the - Create another policy and add the following: - ![insert policy](/img/thirdpartyemailpassword/supabase/policy_config_insert.png) + ![insert policy](/docs/img/thirdpartyemailpassword/supabase/policy_config_insert.png) Similar to the previous policy, the PostgreSQL function that was created is called to get the currently logged in user's ID and check whether this matches the `user_id` column for the row being inserted. If it does, then it allows the user to insert the row, otherwise it continues to deny. @@ -436,8 +428,8 @@ Click `Review` and then `Save policy`. You can now sign up and you should see the following screen: -![auth screen](/img/thirdpartyemailpassword/supabase/supabase_app_authenticated_screen.png) +![auth screen](/docs/img/thirdpartyemailpassword/supabase/supabase_app_authenticated_screen.png) If you navigate to your table you should see a new row with the user's `user_id` and `email`. -![table with user](/img/thirdpartyemailpassword/supabase/table_with_user.png) +![table with user](/docs/img/thirdpartyemailpassword/supabase/table_with_user.png) diff --git a/docs/quickstart/integrations/vercel.mdx b/docs/quickstart/integrations/vercel.mdx index 4f749d4688..f01968d732 100644 --- a/docs/quickstart/integrations/vercel.mdx +++ b/docs/quickstart/integrations/vercel.mdx @@ -1,31 +1,23 @@ --- title: Vercel -hide_title: true -show_ui_switcher: true description: 'Learn how to integrate SuperTokens with Vercel ' -page_type: tutorial -category: quickstart --- - -# Vercel Guide - - This page only talks about what environment variables to use when you are deploying an application on Vercel. -For a full set of instructions on how to integrate **SuperTokens** in a **Next.js** project, please see either our [app router](/docs/quickstart/integrations/nextjs/app-directory/about) or [pages router](/docs/quickstart/integrations/nextjs/app-directory/about) guides. +For a full set of instructions on how to integrate **SuperTokens** in a **Next.js** project, please see either our [app router](/quickstart/integrations/nextjs/app-directory/about) or [pages router](/quickstart/integrations/nextjs/app-directory/about) guides. ## Working with Vercel's inspect and production URL Vercel provides one production URL per app and one unique inspect URL per deployment. -To get SuperTokens to work with dynamic URLs, you need to make the following changes to the [`appInfo` object](/docs/references/frontend-sdks/reference#sdk-configuration): +To get SuperTokens to work with dynamic URLs, you need to make the following changes to the [`appInfo` object](/references/frontend-sdks/reference#sdk-configuration): ### On the frontend - + - + ```text appInfo = { @@ -36,17 +28,17 @@ appInfo = { ``` - + - + ```text appInfo = { apiDomain: window.location.origin ... } ``` - + ### On the backend @@ -60,10 +52,7 @@ appInfo = { Vercel adds an environment variable to the backend - `VERCEL_URL`, which points to the current URL that the app is deployed on. This allows SuperTokens to work on all inspect URLs generated by Vercel without you having to keep changing your code. -:::note -The above setting works only if your backend and frontend are deployed on the same URL. If you are using a different backend and using Vercel only for your frontend, then: +:::note[The above setting works only if your backend and frontend are deployed on the same URL. If you are using a different backend and using Vercel only for your frontend, then:] - Set the `apiDomain` on the frontend and backend to point to your backend. - The `websiteDomain` on the frontend should be `window.location.origin`, but on the backend, it should be equal to your production deployment URL. This will break certain features of the app for inspect URL deployments, but it will work as expected for production deployments. ::: - - diff --git a/docs/quickstart/introduction.mdx b/docs/quickstart/introduction.mdx index c468a8b783..f2e72a9e2a 100644 --- a/docs/quickstart/introduction.mdx +++ b/docs/quickstart/introduction.mdx @@ -1,26 +1,16 @@ --- -id: introduction title: Introduction -hide_title: true -sidebar_position: 1 -description: >- - Set up user authentication with SuperTokens using Email/Password login and - customizable UI components. -page_type: tutorial -category: quickstart +description: Set up user authentication with SuperTokens using Email/Password login and customizable UI components. +sidebar: + order: 1 --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - -# Introduction - ## Overview This quickstart will guide you through how to set up a basic project that uses **SuperTokens** to authenticate users. The tutorial shows an **Email/Password** login flow, rendered by either our **Prebuilt UI components** or by your own **Custom UI**. - + If you want to skip straight to an example application you can choose between: - Checking our live [demo application](https://emailpassword.demo.supertokens.com/auth) @@ -29,7 +19,7 @@ If you want to skip straight to an example application you can choose between: ```bash npx create-supertokens-app@latest --recipe=emailpassword ``` - + ## Before you start @@ -46,28 +36,22 @@ From there, the **Backend SDKs** are used to expose new authentication routes. T You can check the following diagram for a high level overview of how the services will interact within an authentication setup that involves **SuperTokens**. - - + + Flowchart of architecture when using SuperTokens managed service - - + + Flowchart of architecture when self-hosting SuperTokens - + -:::info Edge Cases +:::info[Edge Cases] - You can also host the **SuperTokens Core** yourself. In that case your backend will communicate with a service that exists inside your infrastructure. - If you are using a backend for which we do not have an SDK, you will have to spin up an additional auth service in a language for which we do have a backend SDK (NodeJS, Python or Golang). diff --git a/docs/quickstart/meta.ts b/docs/quickstart/meta.ts new file mode 100644 index 0000000000..eeb36554be --- /dev/null +++ b/docs/quickstart/meta.ts @@ -0,0 +1,8 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Quickstart", + "icon": "zap", + "order": 2, + "collapsed": false +}); diff --git a/docs/quickstart/next-steps.mdx b/docs/quickstart/next-steps.mdx index 5f7df74ef6..6dadaec6cb 100644 --- a/docs/quickstart/next-steps.mdx +++ b/docs/quickstart/next-steps.mdx @@ -1,19 +1,10 @@ --- -id: next-steps title: Next Steps -hide_title: true -pagination_next: null -sidebar_position: 4 -description: >- - Configure SuperTokens for production-ready authentication, explore additional - methods, and customize flows. -page_type: tutorial -category: quickstart +description: Configure SuperTokens for production-ready authentication, explore additional methods, and customize flows. +sidebar: + order: 4 --- - -# Next Steps - ## Overview Now that you have completed the quickstart guide there are a few more things that you need to take care of on the road towards a production ready authentication experience. @@ -24,7 +15,7 @@ If you have signed up and deployed a SuperTokens environment already, you can sk Otherwise, please follow these instructions to use the correct **SuperTokens Core** instance in your application. The steps show you how to connect to a **SuperTokens Managed Service Environment**. -If you want to self host the core instance please check the [following guide](/docs/deployment/self-host-supertokens). +If you want to self host the core instance please check the [following guide](/deployment/self-host-supertokens). ### 1. Sign up for a SuperTokens account @@ -37,7 +28,7 @@ Select the account that you want to use and wait for the action to complete. Integration with SuperTokens SDKs After you have signed up, select **Managed** and create a deployment. @@ -46,9 +37,7 @@ Choose a region that is closest to where your services are hosted, enter a deplo Our internal service will deploy a separate environment based on your selection. After this process is complete, open the new deployment from the list. -:::info - -The initial setup flow only configures a development environment. +:::info[The initial setup flow only configures a development environment.] In order to use SuperTokens in production, you will have to create a separate deployment. ::: @@ -58,26 +47,24 @@ In order to use SuperTokens in production, you will have to create a separate de SuperTokens managed service dashboard connectionURI and API key Open the newly created deployment and stay on its **Overview** page. In the **Connection Information** section, copy the `Connection URI` and an `API Key` and paste them in your backend code. You can use **Generate Key** to create an additional API key. - + - + -```tsx +```tsx {4,5,6,7} import supertokens from "supertokens-node"; supertokens.init({ - // highlight-start supertokens: { connectionURI: "", apiKey: "", }, - // highlight-end appInfo: { apiDomain: "...", appName: "...", @@ -87,95 +74,66 @@ supertokens.init({ }); ``` - - + + -```go +```go {5,6,7,8} import "github.com/supertokens/supertokens-golang/supertokens" func main() { supertokens.Init(supertokens.TypeInput{ - // highlight-start Supertokens: &supertokens.ConnectionInfo{ ConnectionURI: "", APIKey: "", }, - // highlight-end }) } ``` - - + + -```python +```python {5,6,7,8} from supertokens_python import init, InputAppInfo, SupertokensConfig init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - # highlight-start supertokens_config=SupertokensConfig( connection_uri='', api_key='' ), - # highlight-end - framework='...', # type: ignore + framework='...', recipe_list=[ #... ] ) ``` - - + + ## Add More Authentication Methods Besides the simple email/password example that you just completed, **SuperTokens** exposes additional authentication methods that can easily be enabled. - - - - Passwordless - - - Authentication through magic links or one-time codes. - - - - - Social Login - - - Login flow that uses third-party providers for authentication. - - - - - Enterprise Login - - - Instructions on how to configure your application to support multiple tenants and enterprise authentication methods. - - - - - Unified Login - - - Details on how to create a common authentication experience for all your products. - - - - - Machine to Machine Authentication - - - Guides on authenticating microservices using SuperTokens. - - - + + +Authentication through magic links or one-time codes. + + +Login flow that uses third-party providers for authentication. + + +Instructions on how to configure your application to support multiple tenants and enterprise authentication methods. + + +Details on how to create a common authentication experience for all your products. + + +Guides on authenticating microservices using SuperTokens. + + ## Customize Your Authentication Flow @@ -184,53 +142,43 @@ After you have connected the Backend SDK to a specific **SuperTokens Core Servic Several sections show you how to customize the authentication experience to fit your specific needs. Some of the most common subjects are: - - - Add Email Verification - Use an additional verification step to secure your sign up process. - - - Add a Custom Redirect Action - Redirect users after sign up/login. - - - Use Custom Session Management - Adjust the session management to fit your needs. - - - Share Sessions Across Subdomains - Manage multiple subdomains from a single SuperTokens Core instance. - - - Post Sign In Actions - Add custom logic in the authentication flow. - - + + +Use an additional verification step to secure your sign up process. + + +Redirect users after sign up/login. + + +Adjust the session management to fit your needs. + + +Manage multiple subdomains from a single SuperTokens Core instance. + + +Add custom logic in the authentication flow. + + ## Explore Additional Features You can also review the additional features that **SuperTokens** exposes. Those can help you extend the authentication implementation on different levels. - - - Self Host SuperTokens Core - Run the SuperTokens in your own infrastructure. - - - Migration Guide - Migrate your data from other authentication providers. - - - Multi Factor Authentication - Set up additional authentication layers in your sign-in process. - - - User Management Dashboard - Administrate your users from the SuperTokens Dashboard. - - - User Roles and Permissions - Adjust the authorization settings in your application. - - + + +Run the SuperTokens in your own infrastructure. + + +Migrate your data from other authentication providers. + + +Set up additional authentication layers in your sign-in process. + + +Administrate your users from the SuperTokens Dashboard. + + +Adjust the authorization settings in your application. + + diff --git a/docs/references/_category_.json b/docs/references/_category_.json deleted file mode 100644 index 299f1d0553..0000000000 --- a/docs/references/_category_.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "label": "References", - "customProps": { - "isMainCategory": true - }, - "position": 1 -} diff --git a/docs/references/backend-sdks/_category_.json b/docs/references/backend-sdks/_category_.json deleted file mode 100644 index 0800d5ddbc..0000000000 --- a/docs/references/backend-sdks/_category_.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "label": "Backend SDKs", - "customProps": { - "isMainCategory": true - }, - "position": 4 -} diff --git a/docs/references/backend-sdks/api-overrides.mdx b/docs/references/backend-sdks/api-overrides.mdx index fb8b9aca78..8fcddb0ef6 100644 --- a/docs/references/backend-sdks/api-overrides.mdx +++ b/docs/references/backend-sdks/api-overrides.mdx @@ -1,18 +1,10 @@ --- title: API Overrides -hide_title: true -sidebar_position: 3 -toc_max_heading_level: 4 -description: >- - Override APIs to control frontend-backend interactions and customize - input/output specifications. -page_type: sdk-reference -category: backend-sdk +description: Override APIs to control frontend-backend interactions and customize input/output specifications. +sidebar: + order: 3 --- - -# APIs override - ## Overview Overriding APIs allows you to take full control of what happens when the frontend SDK calls the backend authentication endpoints. @@ -23,12 +15,12 @@ You can send analytics events, synchronize additional information in the databas ## General example -Like with the [functions override](/docs/references/backend-sdks/function-overrides) feature, the original implementation reference must be called to avoid any errors in the authentication flow. +Like with the [functions override](/references/backend-sdks/function-overrides) feature, the original implementation reference must be called to avoid any errors in the authentication flow. - - + + -```ts +```ts {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,45,46,47,48,49,50} import SuperTokens from "supertokens-node"; import EmailPassword from "supertokens-node/recipe/emailpassword"; import Session from "supertokens-node/recipe/session"; @@ -44,7 +36,6 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-start override: { apis: (originalImplementation) => { return { @@ -66,7 +57,6 @@ SuperTokens.init({ } } } - // highlight-end }), EmailPassword.init({ override: { @@ -75,14 +65,12 @@ SuperTokens.init({ ...originalImplementation, emailExistsGET: async function (input) { - // highlight-start // send a custom response like this: input.options.res.setStatusCode(200); // or any other status code input.options.res.sendJSONResponse({ message: "my custom response", //... }) - // highlight-end // this return doesn't matter. But we must do it // cause the function signature expects a response. @@ -100,10 +88,10 @@ SuperTokens.init({ ``` - - + + -```go +```go {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,38,39,40,41,42,43,44,45,46,47} import ( "encoding/json" @@ -118,7 +106,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - //highlight-start Override: &sessmodels.OverrideStruct{ APIs: func(originalImplementation sessmodels.APIInterface) sessmodels.APIInterface { // First we make a copy of the original implementation @@ -135,7 +122,6 @@ func main() { return originalImplementation }, }, - //highlight-end }), emailpassword.Init(&epmodels.TypeInput{ Override: &epmodels.OverrideStruct{ @@ -143,7 +129,6 @@ func main() { (*originalImplementation.EmailExistsGET) = func(email, tenantId string, options epmodels.APIOptions, userContext supertokens.UserContext) (epmodels.EmailExistsGETResponse, error) { - // highlight-start // create a custom response. options.Res.Header().Set("Content-Type", "application/json; charset=utf-8") options.Res.WriteHeader(200) @@ -154,7 +139,6 @@ func main() { bytes, _ := json.Marshal(responseJson) options.Res.Write(bytes) - // highlight-end // this return doesn't matter. But we must do it // cause the function signature expects a response. @@ -174,10 +158,10 @@ func main() { } ``` - - + + -```python +```python {12,13,14,15,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,47} from supertokens_python import init, InputAppInfo from supertokens_python.recipe.emailpassword.interfaces import APIOptions as EmailPasswordAPIOptions, EmailExistsGetOkResult, APIInterface as EmailPasswordAPIInterface from supertokens_python.recipe.session.interfaces import APIOptions as SessionAPIOptions, APIInterface as SessionAPIInterface @@ -189,12 +173,10 @@ def override_emailpassword_apis(original_implementation: EmailPasswordAPIInterfa async def email_exists_get(email: str, tenant_id: str, api_options: EmailPasswordAPIOptions, user_context: Dict[str, Any]): - # highlight-start # send custom response like this - api_options.response.set_status_code(200) # type: ignore + api_options.response.set_status_code(200) json_dict = {'message': 'Custom response'} - api_options.response.set_json_content(json_dict) # type: ignore - # highlight-end + api_options.response.set_json_content(json_dict) # this return doesn't matter. But we must do it # cause the function signature expects a response. @@ -203,7 +185,6 @@ def override_emailpassword_apis(original_implementation: EmailPasswordAPIInterfa original_implementation.email_exists_get = email_exists_get return original_implementation -# highlight-start def override_session_apis(original_implementation: SessionAPIInterface): original_signout_post = original_implementation.signout_post @@ -221,24 +202,20 @@ def override_session_apis(original_implementation: SessionAPIInterface): return original_implementation -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ session.init( - # highlight-start override=session.InputOverrideConfig(apis=override_session_apis) - # highlight-end ), emailpassword.init(override=emailpassword.InputOverrideConfig(apis=override_emailpassword_apis)) ], ) ``` - - + + --- @@ -251,10 +228,10 @@ For custom UI, you can read this response and display the message in an error UI The next example shows how to prevent the user from signing up unless their email is pre-approved by the application's admin. - - + + -```ts +```ts {12,13,14,15} import EmailPassword from "supertokens-node/recipe/emailpassword"; EmailPassword.init({ @@ -266,12 +243,10 @@ EmailPassword.init({ let email = input.formFields.find(i => i.id === "email")!.value as string; if (emailNotAllowed(email)) { - // highlight-start return { status: "GENERAL_ERROR", message: "You are not allowed to sign up. Please contact the app's admin to get permission" } - // highlight-end } return oI.signUpPOST!(input); } @@ -286,10 +261,10 @@ function emailNotAllowed(email: string) { } ``` - - + + -```go +```go {27,28,29,30,31} import ( "errors" @@ -316,13 +291,11 @@ func main() { } } if (emailNotAllowed(email)) { - // highlight-start return epmodels.SignUpPOSTResponse{ GeneralError: &supertokens.GeneralErrorResponse{ Message: "You are not allowed to sign up. Please contact the app's admin to get permission", }, }, nil - // highlight-end } return originalSignUp(formFields, tenantId, options, userContext) } @@ -339,10 +312,10 @@ func emailNotAllowed(email string) bool { } ``` - - + + -```python +```python {39,40,41} from supertokens_python.recipe import emailpassword from supertokens_python.recipe.emailpassword.interfaces import ( APIInterface, @@ -381,11 +354,9 @@ def override_apis(original_implementation: APIInterface): email = form_fields[i].value if is_not_allowed(email): - # highlight-start return GeneralErrorResponse( message="You are not allowed to sign up. Please contact the app's admin to get permission" ) - # highlight-end return await original_sign_up( form_fields, @@ -409,31 +380,24 @@ def is_not_allowed(email: str): emailpassword.init(override=emailpassword.InputOverrideConfig(apis=override_apis)) ``` - - + + --- ## Disable APIs - - + + To disable an API entirely, all you need to do is override the API implementation with `undefined`. For example, if you want to disable the sign up / sign in API from this recipe, all you do is this: -= v8.0.0', value: 'greater' }, - { label: '< v8.0.0', value: 'lesser' }, - ]}> - - -```tsx + + + +```tsx {16,17,18,19,20,21,22,23,24,27,28,29,30,31,32,33,34} import SuperTokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty"; import EmailPassword from "supertokens-node/recipe/emailpassword"; @@ -449,7 +413,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start override: { apis: (originalImplementation) => { return { @@ -459,10 +422,8 @@ SuperTokens.init({ } } } - // highlight-end }), ThirdParty.init({ - // highlight-start override: { apis: (originalImplementation) => { return { @@ -471,16 +432,15 @@ SuperTokens.init({ } } } - // highlight-end }) ] }); ``` - - + + -```tsx +```tsx {15,16,17,18,19,20,21,22} import SuperTokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty"; @@ -495,7 +455,6 @@ SuperTokens.init({ }, recipeList: [ ThirdParty.init({ - // highlight-start override: { apis: (originalImplementation) => { return { @@ -504,23 +463,22 @@ SuperTokens.init({ } } } - // highlight-end }) ] }); ``` - + - - + + To disable an API entirely, all you need to do is override the API implementation with `nil`. For example, if you want to disable the sign up / sign in API from this recipe, all you do is this: -```go +```go {13,14,15,16,17,18,19,20,21,22,25,26,27,28,29,30,31,32,33,34,35,36} import ( "github.com/supertokens/supertokens-golang/recipe/emailpassword" "github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels" @@ -533,7 +491,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ thirdparty.Init(&tpmodels.TypeInput{ - //highlight-start Override: &tpmodels.OverrideStruct{ APIs: func(originalImplementation tpmodels.APIInterface) tpmodels.APIInterface { @@ -544,10 +501,8 @@ func main() { }, }, - //highlight-end }), emailpassword.Init(&epmodels.TypeInput{ - //highlight-start Override: &epmodels.OverrideStruct{ APIs: func(originalImplementation epmodels.APIInterface) epmodels.APIInterface { @@ -560,20 +515,19 @@ func main() { return originalImplementation }, }, - //highlight-end }), }, }) } ``` - - + + To disable an API entirely, all you need to do is override the API disable `bool` value to `True`. For example, if you want to disable the sign up / sign in API from this recipe, all you do is this: -```python +```python {11,12,13,14,15,18,19,20,21,22,23,24,31,34,35,36} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import thirdparty, emailpassword from supertokens_python.recipe.thirdparty.interfaces import ( @@ -584,16 +538,13 @@ from supertokens_python.recipe.emailpassword.interfaces import ( ) -# highlight-start def thirdparty_apis_override(original_impl: ThirdPartyAPIInterface): # disable sign in & up with third party original_impl.disable_sign_in_up_post = True return original_impl -# highlight-end -# highlight-start def emailpassword_apis_override(original_impl: EmailPasswordAPIInterface): # disable sign up with email & password original_impl.disable_sign_up_post = True @@ -601,33 +552,28 @@ def emailpassword_apis_override(original_impl: EmailPasswordAPIInterface): # disable sign in with email & password original_impl.disable_sign_in_post = True return original_impl -# highlight-end init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ thirdparty.init( - # highlight-start override=thirdparty.InputOverrideConfig(apis=thirdparty_apis_override), - # highlight-end ), emailpassword.init( - # highlight-start override=emailpassword.InputOverrideConfig( apis=emailpassword_apis_override ), - # highlight-end ), ], ) ``` - - + + -:::info Important -You then need to define routes that handle this API call. You can see the [Frontend driver interface API spec here](/docs/references/fdi/introduction) +:::info[Important] +You then need to define routes that handle this API call. You can see the [Frontend driver interface API spec here](/references/fdi/introduction) ::: @@ -635,12 +581,12 @@ You then need to define routes that handle this API call. You can see the [Front ## Read custom request information - - + + The `getRequestFromUserContext` function provided by the SDK is used to get the request object from the user context. -```tsx +```tsx {14,15,16,17,18,19,20,21,22,23,24,25,26,27} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -654,12 +600,10 @@ Session.init({ throw Error("Signout API is disabled"); } - // highlight-start let customHeaderValue = ""; const request = SuperTokens.getRequestFromUserContext(input.userContext); if (request !== undefined) { - //@ts-ignore customHeaderValue = request.getHeaderValue("customHeader"); } else { /** @@ -670,7 +614,6 @@ Session.init({ customHeaderValue = "default"; } - // highlight-end // Perform custom logic based on the value of customHeaderValue @@ -682,12 +625,12 @@ Session.init({ }) ``` - - + + The `GetRequestFromUserContext` function provided by the SDK is used to get the request object from the user context. -```go +```go {14,15,16,17,18,19,20,21,22,23,24,25,26} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -701,7 +644,6 @@ func main() { originalSignOutPost := *originalImplementation.SignOutPOST *originalImplementation.SignOutPOST = func(sessionContainer sessmodels.SessionContainer, options sessmodels.APIOptions, userContext supertokens.UserContext) (sessmodels.SignOutPOSTResponse, error) { - // highlight-start customHeadervalue := "" request := supertokens.GetRequestFromUserContext(userContext) @@ -715,7 +657,6 @@ func main() { */ customHeadervalue = "default"; } - // highlight-end print(customHeadervalue) @@ -731,12 +672,12 @@ func main() { } ``` - - + + The `get_request_from_user_context` function provided by the SDK is used to get the request object from the user context. -```python +```python {11,12,13,14,15,16,17,18,19,20,21,22} from supertokens_python import get_request_from_user_context from supertokens_python.recipe import session from supertokens_python.recipe.session.interfaces import APIInterface, APIOptions @@ -747,7 +688,6 @@ def override_session_apis(original_implementation: APIInterface): original_signout_post = original_implementation.signout_post async def signout_post(session: session.SessionContainer, api_options: APIOptions, user_context: Dict[str, Any]): - # highlight-start request=get_request_from_user_context(user_context) customHeaderValue="" @@ -760,7 +700,6 @@ def override_session_apis(original_implementation: APIInterface): # In this case set a reasonable default value to use # customHeaderValue="default" - # highlight-end print(customHeaderValue) # Perform custom logic based on the value of customHeadervalue @@ -777,5 +716,5 @@ session.init( ) ``` - - + + diff --git a/docs/references/backend-sdks/backend-sdk-core-interceptor.mdx b/docs/references/backend-sdks/backend-sdk-core-interceptor.mdx index 43e2afee52..2474bbb489 100644 --- a/docs/references/backend-sdks/backend-sdk-core-interceptor.mdx +++ b/docs/references/backend-sdks/backend-sdk-core-interceptor.mdx @@ -1,17 +1,10 @@ --- title: Network interceptor -hide_title: true -sidebar_position: 7 -description: >- - Intercept and modify outgoing backend SDK requests to the core in NodeJS, - Python, and GoLang. -page_type: sdk-reference -category: backend-sdk +description: Intercept and modify outgoing backend SDK requests to the core in NodeJS, Python, and GoLang. +sidebar: + order: 7 --- - -# Backend SDK core interceptor - ## Overview This hook intercepts all outgoing requests from the backend SDK to the core. @@ -20,7 +13,7 @@ Users can modify the HTTP method, query params, headers, and body of the request ## Prerequisites -:::info Important +:::info[Important] This feature is only available for SDKs versions: - NodeJS >= `v16.5.0` - Python >= `v0.16.8` @@ -29,10 +22,10 @@ This feature is only available for SDKs versions: ## Example - - + + -```tsx +```tsx {8,9,10,11,12} import { HttpRequest } from "supertokens-node/types"; import SuperTokens from "supertokens-node"; @@ -40,13 +33,11 @@ SuperTokens.init({ supertokens: { connectionURI: "...", apiKey: "...", - // highlight-start networkInterceptor: (request: HttpRequest, userContext: any) => { console.log("http request to core: ", request) // this can also be used to return a modified request object. return request; }, - // highlight-end }, appInfo: { apiDomain: "...", @@ -59,10 +50,10 @@ SuperTokens.init({ }); ``` - - + + -```go +```go {13,14,15,16} import ( "log" "net/http" @@ -75,12 +66,10 @@ supertokens.Init(supertokens.TypeInput{ Supertokens: &supertokens.ConnectionInfo{ ConnectionURI: "...", APIKey: "...", - // highlight-start NetworkInterceptor: func(request *http.Request, context supertokens.UserContext) (*http.Request, error) { log.Print("http request to core: %+v", request) return request, nil }, - // highlight-end }, AppInfo: supertokens.AppInfo{ AppName: "...", @@ -92,14 +81,13 @@ supertokens.Init(supertokens.TypeInput{ } ``` - - + + -```python +```python {4,5,6,7,8,9,10,11,12,13,24} from typing import Dict, Any, Optional from supertokens_python import init, InputAppInfo, SupertokensConfig -# highlight-start def intercept( url: str, method: str, @@ -110,7 +98,6 @@ def intercept( ): print("http request to core: ", url, method, headers, params, body) return url, method, headers, params, body -# highlight-end init( app_info=InputAppInfo( @@ -121,7 +108,6 @@ init( supertokens_config=SupertokensConfig( connection_uri="...", api_key="...", - # highlight-next-line network_interceptor=intercept, ), framework="django", # works with other frameworks as well @@ -131,5 +117,5 @@ init( ) ``` - - + + diff --git a/docs/references/backend-sdks/function-overrides.mdx b/docs/references/backend-sdks/function-overrides.mdx index 9131278fc8..c414fba57e 100644 --- a/docs/references/backend-sdks/function-overrides.mdx +++ b/docs/references/backend-sdks/function-overrides.mdx @@ -1,17 +1,10 @@ --- title: Function Overrides -hide_title: true -sidebar_position: 2 -description: >- - Override backend authentication functions to implement cover custome use - cases. -page_type: sdk-reference -category: backend-sdk +description: Override backend authentication functions to implement cover custome use cases. +sidebar: + order: 2 --- - -# Function overrides - ## Overview **Function overrides** let you customize the behavior of the functions used internally, by the SDKs. @@ -23,21 +16,20 @@ Similarly, if you already have a sign-in/sign-up flow and want to integrate with You can even implement a custom `userId` format by mapping `userIds` to those generated by SuperTokens. - ## Example The code snippet shows the general flow of overriding a function. Custom logic can be injected while also calling the original implementation of the function. - - + + :::info See all the [functions that can be overridden here](https://supertokens.com/docs/nodejs/modules/recipe_thirdparty.html#RecipeInterface) ::: -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; import ThirdParty from "supertokens-node/recipe/thirdparty"; @@ -53,7 +45,6 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -72,13 +63,11 @@ SuperTokens.init({ } } } - // highlight-end }), ThirdParty.init({ signInAndUpFeature: { providers: [/* ... */] }, - // highlight-start override: { functions: (originalImplementation) => { return { @@ -97,21 +86,20 @@ SuperTokens.init({ } } } - // highlight-end }) ] }); ``` - - + + :::info See all the [functions that can be overridden here](https://pkg.go.dev/github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels#RecipeInterface) ::: -```go +```go {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -124,7 +112,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ session.Init(&sessmodels.TypeInput{ - //highlight-start Override: &sessmodels.OverrideStruct{ Functions: func(originalImplementation sessmodels.RecipeInterface) sessmodels.RecipeInterface { // First we make a copy of the original implementation @@ -141,10 +128,8 @@ func main() { return originalImplementation }, }, - //highlight-end }), thirdparty.Init(&tpmodels.TypeInput{ - //highlight-start Override: &tpmodels.OverrideStruct{ Functions: func(originalImplementation tpmodels.RecipeInterface) tpmodels.RecipeInterface { @@ -164,21 +149,20 @@ func main() { return originalImplementation }, }, - //highlight-end }), }, }) } ``` - - + + :::info See all the [functions that can be overridden here](https://supertokens.com/docs/python/recipe/thirdparty/interfaces.html#supertokens_python.recipe.thirdparty.interfaces.RecipeInterface) ::: -```python +```python {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,87,90,91,92} from typing import Any, Dict, Optional, Union from supertokens_python import InputAppInfo, init @@ -194,7 +178,6 @@ from supertokens_python.recipe.thirdparty.types import RawUserInfoFromProvider from supertokens_python.types import RecipeUserId -# highlight-start def override_thirdparty_functions(original_implementation: ThirdPartyRecipeInterface): original_sign_in_up = original_implementation.sign_in_up @@ -229,7 +212,6 @@ def override_thirdparty_functions(original_implementation: ThirdPartyRecipeInter original_implementation.sign_in_up = sign_in_up return original_implementation -# highlight-start def override_session_functions(original_implementation: SessionRecipeInterface): original_create_new_session = original_implementation.create_new_session @@ -259,26 +241,17 @@ def override_session_functions(original_implementation: SessionRecipeInterface): return original_implementation -# highlight-end - - -# highlight-end - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ session.init( - # highlight-start override=session.InputOverrideConfig(functions=override_session_functions) - # highlight-end ), thirdparty.init( - # highlight-start override=thirdparty.InputOverrideConfig( functions=override_thirdparty_functions ), - # highlight-end sign_in_and_up_feature=thirdparty.SignInAndUpFeature( providers=[ # ... @@ -289,8 +262,8 @@ init( ) ``` - - + + --- @@ -300,10 +273,10 @@ If you want to throw a custom error from function overrides you have to handle i ### Raise the error - - + + -```ts +```ts {9,10,11,12,13,14,15,16} import Session from "supertokens-node/recipe/session"; Session.init({ @@ -312,7 +285,6 @@ Session.init({ return { ...originalImplementation, createNewSession: async function (input) { - //highlight-start const existingSessions = await Session.getAllSessionHandlesForUser(input.userId); if (existingSessions.length > 0) { // this means that the user already has a session on some other device @@ -321,7 +293,6 @@ Session.init({ // no other session exists, and so we can continue with logging in this user return originalImplementation.createNewSession(input); - //highlight-end } } } @@ -329,10 +300,10 @@ Session.init({ }) ``` - - + + -```go +```go {18,19,20,21,22,23,24,25,26,27,28,29} import ( "errors" @@ -350,7 +321,6 @@ func main() { originalCreateNewSession := *originalImplementation.CreateNewSession (*originalImplementation.CreateNewSession) = func(userID string, accessTokenPayload, sessionDataInDatabase map[string]interface{}, disableAntiCsrf *bool, tenantId string, userContext supertokens.UserContext) (sessmodels.SessionContainer, error) { - // highlight-start existingSessions, err := session.GetAllSessionHandlesForUser(userID, &tenantId, userContext) if err != nil { return nil, err @@ -363,7 +333,6 @@ func main() { // no other session exists, and so we can continue with logging in this user return originalCreateNewSession(userID, accessTokenPayload, sessionDataInDatabase, disableAntiCsrf, tenantId, userContext) - // highlight-end } return originalImplementation @@ -374,10 +343,10 @@ func main() { } ``` - - + + -```python +```python {23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38} from typing import Any, Dict, Optional from supertokens_python.recipe import session @@ -400,7 +369,6 @@ def override_session_functions(original_implementation: RecipeInterface): tenant_id: str, user_context: Dict[str, Any], ): - # highlight-start existing_sessions = await get_all_session_handles_for_user(user_id) if len(existing_sessions) > 0: @@ -417,7 +385,6 @@ def override_session_functions(original_implementation: RecipeInterface): tenant_id, user_context, ) - # highlight-end original_implementation.create_new_session = create_new_session @@ -427,15 +394,15 @@ def override_session_functions(original_implementation: RecipeInterface): session.init(override=session.InputOverrideConfig(functions=override_session_functions)) ``` - - + + ### Handle the error manually - - - - + + + + ```ts import express from "express"; @@ -454,8 +421,8 @@ app.use((err: any, req: express.Request, res: express.Response, next: express.Ne }) ``` - - + + ```ts import Hapi from "hapi"; @@ -485,8 +452,8 @@ const plugin = { await server.start(); })(); ``` - - + + ```tsx import Fastify from "fastify"; @@ -501,8 +468,8 @@ fastify.setErrorHandler(async (err: any, req, res) => { }); ``` - - + + ```ts import middy from "@middy/core"; @@ -510,7 +477,6 @@ import cors from "@middy/http-cors"; import SuperTokens from "supertokens-node"; // this is in the auth.js file import { middleware } from "supertokens-node/framework/awsLambda"; -// @ts-ignore import { getBackendConfig } from "./config"; module.exports.handler = middy(middleware()).use(cors({ @@ -526,8 +492,8 @@ module.exports.handler = middy(middleware()).use(cors({ }); ``` - - + + ```ts import Koa from "koa"; @@ -549,8 +515,8 @@ app.use(async (ctx, next) => { app.use(middleware()); ``` - - + + ```ts import { Next } from "@loopback/core"; @@ -574,12 +540,12 @@ app.middleware(middleware); app.middleware(customErrorMiddleware); ``` - - + + + - - + @@ -621,7 +587,6 @@ export default async function superTokens(req: any, res: any) { import { getAppDirRequestHandler } from "supertokens-node/nextjs"; import { NextRequest, NextResponse } from "next/server"; import SuperTokens from "supertokens-node"; -// @ts-ignore import { backendConfig } from "@/app/config/backend"; SuperTokens.init(backendConfig()); @@ -658,8 +623,8 @@ export const HEAD = withCustomErrorHandling; - - + + ```tsx import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common'; @@ -682,10 +647,10 @@ export class AppErrorHandler implements ExceptionFilter { } } ``` - - - - + + + + ```go import ( @@ -706,17 +671,17 @@ func main() { } ``` - - - - + + + + ```python from fastapi import FastAPI app = FastAPI() -@app.exception_handler(Exception) # type: ignore +@app.exception_handler(Exception) async def exception_handler(_, exc: Exception): if str(exc) == "Session already exists on another device": pass # TODO: send custom response @@ -724,15 +689,15 @@ async def exception_handler(_, exc: Exception): # TODO: Send generic 500 response ``` - - + + ```python from flask import Flask app = Flask(__name__) -@app.errorhandler(Exception) # type: ignore +@app.errorhandler(Exception) def all_exception_handler(exc: Exception): if str(exc) == "Session already exists on another device": pass # TODO: send custom response @@ -740,8 +705,8 @@ def all_exception_handler(exc: Exception): # TODO: Send generic 500 response ``` - - + + ```python # Add this middlware in settings.py @@ -753,7 +718,7 @@ from django.http import HttpRequest, HttpResponse class ErrorHandlerMiddleware: - def __init__(self, get_response): # type: ignore + def __init__(self, get_response): self.get_response = get_response def __call__(self, request: HttpRequest): @@ -767,22 +732,22 @@ class ErrorHandlerMiddleware: return HttpResponse("Error processing the request.", status=500) ``` - - - - + + + + --- ## Read custom request information - - + + We use the `getRequestFromUserContext` function provided by the SDK to get the request object from the user context. -```tsx +```tsx {10,11,12,13,14,15,16,17,18,19,20,21,22,23} import SuperTokens from "supertokens-node"; import Session from "supertokens-node/recipe/session"; @@ -792,12 +757,10 @@ Session.init({ return { ...oI, revokeSession: async (input) => { - // highlight-start let customHeaderValue = ""; const request = SuperTokens.getRequestFromUserContext(input.userContext); if (request !== undefined) { - //@ts-ignore customHeaderValue = request.getHeaderValue("customHeader"); } else { /** @@ -808,7 +771,6 @@ Session.init({ customHeaderValue = "default"; } - // highlight-end // Perform custom logic based on the value of customHeaderValue @@ -820,12 +782,12 @@ Session.init({ }) ``` - - + + We use the `GetRequestFromUserContext` function provided by the SDK to get the request object from the user context. -```go +```go {14,15,16,17,18,19,20,21,22,23,24,25,26} import ( "github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/session/sessmodels" @@ -839,7 +801,6 @@ func main() { originalRevokeSession := *originalImplementation.RevokeSession *originalImplementation.RevokeSession = func(sessionHandle string, userContext supertokens.UserContext) (bool, error) { - // highlight-start customHeadervalue := "" request := supertokens.GetRequestFromUserContext(userContext) @@ -853,7 +814,6 @@ func main() { */ customHeadervalue = "default"; } - // highlight-end print(customHeadervalue) @@ -869,12 +829,12 @@ func main() { } ``` - - + + We use the `get_request_from_user_context` function provided by the SDK to get the request object from the user context. -```python +```python {12,13,14,15,16,17,18,19,20,21,22,23} from typing import Any, Dict from supertokens_python import get_request_from_user_context @@ -886,7 +846,6 @@ def override_session_functions(original_implementation: RecipeInterface): original_revoke_session = original_implementation.revoke_session async def revoke_session(session_handle: str, user_context: Dict[str, Any]): - # highlight-start request=get_request_from_user_context(user_context) customHeaderValue="" @@ -899,7 +858,6 @@ def override_session_functions(original_implementation: RecipeInterface): # In this case set a reasonable default value to use # customHeaderValue="default" - # highlight-end print(customHeaderValue) # Perform custom logic based on the value of customHeadervalue @@ -917,5 +875,5 @@ session.init( ) ``` - - + + diff --git a/docs/references/backend-sdks/meta.ts b/docs/references/backend-sdks/meta.ts new file mode 100644 index 0000000000..7729f71da5 --- /dev/null +++ b/docs/references/backend-sdks/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Backend SDKs", + "icon": "server", + "order": 4 +}); diff --git a/docs/references/backend-sdks/other-frameworks.mdx b/docs/references/backend-sdks/other-frameworks.mdx index a3577d716e..b44745dbe9 100644 --- a/docs/references/backend-sdks/other-frameworks.mdx +++ b/docs/references/backend-sdks/other-frameworks.mdx @@ -1,13 +1,8 @@ --- -id: other-frameworks title: Supporting other backend frameworks -hide_title: false -sidebar_position: 8 -description: >- - Set up an authentication server with SuperTokens for unsupported backend - frameworks. -page_type: guide -category: backend-sdk +description: Set up an authentication server with SuperTokens for unsupported backend frameworks. +sidebar: + order: 8 --- If your backend framework is not supported by SuperTokens, you can follow this guide on setting up an authentication server to protect your frontend and backend. @@ -19,15 +14,15 @@ To illustrate how this setup works, consider an example: - SuperTokens does not have a PHP SDK, and a separate service in NodeJS starts to act as an authentication server. The SuperTokens backend SDK configures this server to handle authentication requests and the issuing of access and refresh tokens. - The architecture of setup should have the following design: -![SuperTokens Setup With Authentication server](/img/other-framework-setup.png) +![SuperTokens Setup With Authentication server](/docs/img/other-framework-setup.png) - In the architecture above the the React Frontend communicates with the PHP and node server through a reverse proxy. - Authentication requests like sign-up or sign-in route to the NodeJS server. These APIs are automatically created and handled by the `supertokens-node` SDK. On the other hand, your application-specific APIs are on the PHP server. - Once a user signs up or signs in, the system creates a session between your API server's domain and the frontend. - Application requests to the PHP server have session tokens attached to them. -- The session token is a JWT, and the PHP server can [verify it](/docs/additional-verification/session-verification/protect-api-routes#using-a-jwt-verification-library). +- The session token is a JWT, and the PHP server can [verify it](/additional-verification/session-verification/protect-api-routes#using-a-jwt-verification-library). - When verifying a request, if the session token is missing or has expired, the PHP server should return a `401` response. This prompts the SuperTokens Frontend SDK to trigger the automatic refresh flow to generate new session tokens and retry the request. -:::info Important -The method mentioned above assumes that the authentication server is running on the same domain as the PHP server. If instead, your authentication server runs on a separate subdomain, you need to [enable cookie sharing](/docs/post-authentication/session-management/advanced-workflows/multiple-api-endpoints) for cookies to be automatically attached to requests to the PHP server. +:::info[Important] +The method mentioned above assumes that the authentication server is running on the same domain as the PHP server. If instead, your authentication server runs on a separate subdomain, you need to [enable cookie sharing](/post-authentication/session-management/advanced-workflows/multiple-api-endpoints) for cookies to be automatically attached to requests to the PHP server. ::: diff --git a/docs/references/backend-sdks/reference.mdx b/docs/references/backend-sdks/reference.mdx index e5e695f974..4ac233f312 100644 --- a/docs/references/backend-sdks/reference.mdx +++ b/docs/references/backend-sdks/reference.mdx @@ -1,17 +1,10 @@ --- title: Reference -hide_title: true -sidebar_position: 1 -description: >- - Override frontend authentication functions using SuperTokens for custom - session and user sign-up logic. -page_type: overview -category: backend-sdk +description: Override frontend authentication functions using SuperTokens for custom session and user sign-up logic. +sidebar: + order: 1 --- - -# Backend SDKs - ## Overview SuperTokens has support for Node.js, Python, and Golang through its backend SDKs. @@ -19,53 +12,37 @@ Use this page to find references to each of them and about specific functionalit ## Customization - - - - Function overrides - - - - - API overrides - - + + + + + + + - - - Hooks - - + + - + ## SDK references - - - - - NodeJS - - - - - - - GoLang - - - - - - - Python - - - + + + + + + + + + + + + + ## SDK configuration @@ -83,18 +60,15 @@ let appInfo: { } ``` - - -## `appName` - + + This is the name of your application. Use it when sending password reset or email verification emails (in the default email design). An example of this is `appName: "GitHub"`. -
- -## `websiteDomain` - +
+
+ This is the domain part of your website. This is where the login UI appears. For example: @@ -107,10 +81,9 @@ By default, the login UI appears on `{websiteDomain}/auth/*`. You can change thi On the frontend, you need the domain for routing purposes, and on the backend, it generates correct email verification and password reset links. -
- -## `apiDomain` - +
+
+ This is the domain part of your API endpoint that the frontend talks to. For example: - For local development, you are likely using `localhost` with some port (ex `9000`). Then the value of this should be `"http://localhost:9000"`. - If your frontend queries `https://api.example.com/*`, then the value of this should be `"https://api.example.com"` @@ -118,32 +91,28 @@ This is the domain part of your API endpoint that the frontend talks to. For exa By default, the login widgets query `{apiDomain}/auth/*`. You can change this by using the `apiBasePath` configuration. -
- -## `websiteBasePath` - +
+
+ By default, the login UI appears on `{websiteDomain}/auth`. Other authentication-related user interfaces appear on `{websiteDomain}/auth/*`. If you want to change the `/auth` to something else, then you must set this value. For example: - If you want the login UI to show on `{websiteDomain}/user/*`, then the value of this should be `"/user"`. - If you are using a dedicated sub domain for auth, like `https://auth.example.com`, then you probably want the login UI to show up on `https://auth.example.com`. In this case, set this value to `"/"`. -:::important -Remember to set the same value for this parameter on the backend and the frontend. +:::note[Remember to set the same value for this parameter on the backend and the frontend.] ::: -
- -## `origin` - +
+
+ Can be used instead of `websiteDomain` to handle multiple frontend domains within the same SuperTokens instance. The property accepts a function that receives the original request as an input and should return a valid domain. Make sure to whitelist all the domains during CORS configuration. -
- -## `apiBasePath` - +
+
+ By default, the frontend SDK queries `{apiDomain}/auth/*`. If you want to change the `/auth` to something else, then you must set this value. For example: @@ -151,23 +120,19 @@ If you want to change the `/auth` to something else, then you must set this valu - If you want to scope the APIs not via `/auth` but via some other string like `/supertokens`, then you can set the value of this to `"/supertokens"`. This means, the APIs appear on `{apiDomain}/supertokens/*`. - If you do not want to scope the APIs at all, then you can set the values of this to be `"/"`. This means the APIs are available on `{apiDomain}/*` -:::important -Remember to set the same value for this parameter on the backend and the frontend. +:::note[Remember to set the same value for this parameter on the backend and the frontend.] ::: -:::caution -Note that setting a custom `apiBasePath` updates the refresh API path, this can cause an issue where previously issued refresh tokens no longer get sent to the new API endpoint and the user logs out. +:::warning[Note that setting a custom `apiBasePath` updates the refresh API path, this can cause an issue where previously issued refresh tokens no longer get sent to the new API endpoint and the user logs out.] For example, the default `apiBasePath` value is `/auth`, if it changes to `/supertokens`, then your refresh endpoint updates from `/auth/session/refresh` to `/supertokens/session/refresh`. Previously issued refresh tokens do not get sent to the new API endpoint and the user logs out. ::: -
- -## `apiGatewayPath` - -:::note -Most relevant if you are using an API gateway or reverse proxy +
+
+ +:::note[Most relevant if you are using an API gateway or reverse proxy] ::: If you are using an API gateway (like the one provided by AWS) or a reverse proxy (like Nginx), it may add a path to your API endpoints to scope them for different development environments. @@ -183,7 +148,6 @@ This means that the frontend SDK queries `{apiDomain}/development/supertokens/*` The reason for this distinction between `apiGatewayPath` and `apiBasePath` is that when routing, the backend SDK does not see the `apiGatewayPath` path from the request because the gateway removes them. Taking the above example, whilst the frontend queries `{apiDomain}/development/supertokens/*`, the backend SDK sees `{apiDomain}/supertokens/*`. -
- +
+
- diff --git a/docs/references/backend-sdks/supertokens-nodejs/_category_.json b/docs/references/backend-sdks/supertokens-nodejs/_category_.json deleted file mode 100644 index 55490c19e5..0000000000 --- a/docs/references/backend-sdks/supertokens-nodejs/_category_.json +++ /dev/null @@ -1 +0,0 @@ -{"label":"Node.js SDK Reference","position":7} \ No newline at end of file diff --git a/docs/references/backend-sdks/supertokens-nodejs/meta.ts b/docs/references/backend-sdks/supertokens-nodejs/meta.ts new file mode 100644 index 0000000000..73695ed922 --- /dev/null +++ b/docs/references/backend-sdks/supertokens-nodejs/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Node.js SDK Reference", + "icon": "/img/logos/nodejs-small.svg", + "order": 7 +}); diff --git a/docs/references/backend-sdks/supertokens-nodejs/package.mdx b/docs/references/backend-sdks/supertokens-nodejs/package.mdx index f382a20738..e92ca311b0 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/package.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/package.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node -page_title: SuperTokens Node -sidebar_position: 1 description: References documentation for the supertokens-node package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 1 --- -# SuperTokens Node - - ## Classes ### default @@ -177,7 +170,7 @@ Defined in: [index.ts:171](https://github.com/supertokens/supertokens-node/blob/ | Parameter | Type | | ------ | ------ | -| `userContext` | [`UserContext`](types.mdx#usercontext) | +| `userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -200,7 +193,7 @@ Defined in: [index.ts:136](https://github.com/supertokens/supertokens-node/blob/ ###### Returns -`Promise`\<[`User`](types.mdx#user)\> +`Promise`\<[`User`](types#user)\> ##### getUserCount() @@ -291,7 +284,7 @@ Defined in: [index.ts:70](https://github.com/supertokens/supertokens-node/blob/8 `Promise`\<\{ `nextPaginationToken?`: `string`; - `users`: [`User`](types.mdx#user)[]; + `users`: [`User`](types#user)[]; \}\> ##### getUsersOldestFirst() @@ -321,7 +314,7 @@ Defined in: [index.ts:52](https://github.com/supertokens/supertokens-node/blob/8 `Promise`\<\{ `nextPaginationToken?`: `string`; - `users`: [`User`](types.mdx#user)[]; + `users`: [`User`](types#user)[]; \}\> ##### isRecipeInitialized() @@ -359,13 +352,13 @@ Defined in: [index.ts:143](https://github.com/supertokens/supertokens-node/blob/ | Parameter | Type | Default value | | ------ | ------ | ------ | | `tenantId` | `string` | `undefined` | -| `accountInfo` | [`AccountInfoInput`](recipe-accountlinking-types.mdx#accountinfoinput) | `undefined` | +| `accountInfo` | [`AccountInfoInput`](recipe-accountlinking-types#accountinfoinput) | `undefined` | | `doUnionOfAccountInfo` | `boolean` | `false` | | `userContext?` | `Record`\<`string`, `any`\> | `undefined` | ###### Returns -`Promise`\<[`User`](types.mdx#user)[]\> +`Promise`\<[`User`](types#user)[]\> ##### updateOrDeleteUserIdMappingInfo() @@ -441,7 +434,7 @@ Defined in: [user.ts:91](https://github.com/supertokens/supertokens-node/blob/83 #### Implements -- [`User`](types.mdx#user) +- [`User`](types#user) #### Constructors @@ -490,7 +483,7 @@ Defined in: [user.ts:133](https://github.com/supertokens/supertokens-node/blob/8 ###### Returns -[`JSONObject`](types.mdx#jsonobject) +[`JSONObject`](types#jsonobject) ###### Implementation of @@ -675,7 +668,7 @@ Defined in: [index.ts:208](https://github.com/supertokens/supertokens-node/blob/ | Parameter | Type | | ------ | ------ | -| `userContext` | [`UserContext`](types.mdx#usercontext) | +| `userContext` | [`UserContext`](types#usercontext) | #### Returns @@ -700,7 +693,7 @@ Defined in: [index.ts:202](https://github.com/supertokens/supertokens-node/blob/ #### Returns -`Promise`\<[`User`](types.mdx#user)\> +`Promise`\<[`User`](types#user)\> *** @@ -794,7 +787,7 @@ Defined in: [index.ts:190](https://github.com/supertokens/supertokens-node/blob/ `Promise`\<\{ `nextPaginationToken?`: `string`; - `users`: [`User`](types.mdx#user)[]; + `users`: [`User`](types#user)[]; \}\> *** @@ -826,7 +819,7 @@ Defined in: [index.ts:188](https://github.com/supertokens/supertokens-node/blob/ `Promise`\<\{ `nextPaginationToken?`: `string`; - `users`: [`User`](types.mdx#user)[]; + `users`: [`User`](types#user)[]; \}\> *** @@ -843,7 +836,7 @@ Defined in: [index.ts:182](https://github.com/supertokens/supertokens-node/blob/ | Parameter | Type | | ------ | ------ | -| `config` | [`TypeInput`](types.mdx#typeinput) | +| `config` | [`TypeInput`](types#typeinput) | #### Returns @@ -884,13 +877,13 @@ Defined in: [index.ts:204](https://github.com/supertokens/supertokens-node/blob/ | Parameter | Type | Default value | | ------ | ------ | ------ | | `tenantId` | `string` | `undefined` | -| `accountInfo` | [`AccountInfoInput`](recipe-accountlinking-types.mdx#accountinfoinput) | `undefined` | +| `accountInfo` | [`AccountInfoInput`](recipe-accountlinking-types#accountinfoinput) | `undefined` | | `doUnionOfAccountInfo` | `boolean` | `false` | | `userContext?` | `Record`\<`string`, `any`\> | `undefined` | #### Returns -`Promise`\<[`User`](types.mdx#user)[]\> +`Promise`\<[`User`](types#user)[]\> *** @@ -924,22 +917,22 @@ Defined in: [index.ts:200](https://github.com/supertokens/supertokens-node/blob/ ### SuperTokensConfig -Renames and re-exports [TypeInput](types.mdx#typeinput) +Renames and re-exports [TypeInput](types#typeinput) *** ### SuperTokensPlugin -Re-exports [SuperTokensPlugin](types.mdx#supertokensplugin) +Re-exports [SuperTokensPlugin](types#supertokensplugin) *** ### SuperTokensPublicConfig -Re-exports [SuperTokensPublicConfig](types.mdx#supertokenspublicconfig) +Re-exports [SuperTokensPublicConfig](types#supertokenspublicconfig) *** ### SuperTokensPublicPlugin -Re-exports [SuperTokensPublicPlugin](types.mdx#supertokenspublicplugin) +Re-exports [SuperTokensPublicPlugin](types#supertokenspublicplugin) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking-types.mdx index 29680a2225..fb35af599a 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/accountlinking/types -page_title: Account Linking Types -sidebar_position: 8 description: References documentation for the supertokens-node/recipe/accountlinking/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 8 --- -# Account Linking Types - - ## Type Aliases ### AccountInfo @@ -83,12 +76,12 @@ Defined in: [recipe/accountlinking/types.ts:71](https://github.com/supertokens/s | ------ | ------ | ------ | | `canCreatePrimaryUser` | (`input`) => `Promise`\< \| \{ `status`: `"OK"`; `wasAlreadyAPrimaryUser`: `boolean`; \} \| \{ `description`: `string`; `primaryUserId`: `string`; `status`: \| `"RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR"` \| `"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; \}\> | [recipe/accountlinking/types.ts:84](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L84) | | `canLinkAccounts` | (`input`) => `Promise`\< \| \{ `accountsAlreadyLinked`: `boolean`; `status`: `"OK"`; \} \| \{ `description`: `string`; `primaryUserId`: `string`; `status`: `"RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; \} \| \{ `description`: `string`; `primaryUserId`: `string`; `status`: `"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; \} \| \{ `status`: `"INPUT_USER_IS_NOT_A_PRIMARY_USER"`; \}\> | [recipe/accountlinking/types.ts:113](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L113) | -| `createPrimaryUser` | (`input`) => `Promise`\< \| \{ `status`: `"OK"`; `user`: [`User`](types.mdx#user); `wasAlreadyAPrimaryUser`: `boolean`; \} \| \{ `primaryUserId`: `string`; `status`: `"RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR"`; \} \| \{ `description`: `string`; `primaryUserId`: `string`; `status`: `"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; \}\> | [recipe/accountlinking/types.ts:97](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L97) | +| `createPrimaryUser` | (`input`) => `Promise`\< \| \{ `status`: `"OK"`; `user`: [`User`](types#user); `wasAlreadyAPrimaryUser`: `boolean`; \} \| \{ `primaryUserId`: `string`; `status`: `"RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR"`; \} \| \{ `description`: `string`; `primaryUserId`: `string`; `status`: `"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; \}\> | [recipe/accountlinking/types.ts:97](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L97) | | `deleteUser` | (`input`) => `Promise`\<\{ `status`: `"OK"`; \}\> | [recipe/accountlinking/types.ts:168](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L168) | -| `getUser` | (`input`) => `Promise`\<[`User`](types.mdx#user) \| `undefined`\> | [recipe/accountlinking/types.ts:161](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L161) | -| `getUsers` | (`input`) => `Promise`\<\{ `nextPaginationToken?`: `string`; `users`: [`User`](types.mdx#user)[]; \}\> | [recipe/accountlinking/types.ts:72](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L72) | -| `linkAccounts` | (`input`) => `Promise`\< \| \{ `accountsAlreadyLinked`: `boolean`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `primaryUserId`: `string`; `status`: `"RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; `user`: [`User`](types.mdx#user); \} \| \{ `description`: `string`; `primaryUserId`: `string`; `status`: `"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; \} \| \{ `status`: `"INPUT_USER_IS_NOT_A_PRIMARY_USER"`; \}\> | [recipe/accountlinking/types.ts:136](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L136) | -| `listUsersByAccountInfo` | (`input`) => `Promise`\<[`User`](types.mdx#user)[]\> | [recipe/accountlinking/types.ts:162](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L162) | +| `getUser` | (`input`) => `Promise`\<[`User`](types#user) \| `undefined`\> | [recipe/accountlinking/types.ts:161](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L161) | +| `getUsers` | (`input`) => `Promise`\<\{ `nextPaginationToken?`: `string`; `users`: [`User`](types#user)[]; \}\> | [recipe/accountlinking/types.ts:72](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L72) | +| `linkAccounts` | (`input`) => `Promise`\< \| \{ `accountsAlreadyLinked`: `boolean`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `primaryUserId`: `string`; `status`: `"RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; `user`: [`User`](types#user); \} \| \{ `description`: `string`; `primaryUserId`: `string`; `status`: `"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; \} \| \{ `status`: `"INPUT_USER_IS_NOT_A_PRIMARY_USER"`; \}\> | [recipe/accountlinking/types.ts:136](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L136) | +| `listUsersByAccountInfo` | (`input`) => `Promise`\<[`User`](types#user)[]\> | [recipe/accountlinking/types.ts:162](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L162) | | `unlinkAccount` | (`input`) => `Promise`\<\{ `status`: `"OK"`; `wasLinked`: `boolean`; `wasRecipeUserDeleted`: `boolean`; \}\> | [recipe/accountlinking/types.ts:156](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L156) | *** @@ -105,7 +98,7 @@ Defined in: [recipe/accountlinking/types.ts:197](https://github.com/supertokens/ | Name | Type | Defined in | | ------ | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | [recipe/accountlinking/types.ts:200](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L200) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | [recipe/accountlinking/types.ts:200](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L200) | | `tenantIds` | `string`[] | [recipe/accountlinking/types.ts:198](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L198) | | `timeJoined` | `number` | [recipe/accountlinking/types.ts:199](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/types.ts#L199) | diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking.mdx index 904c5180ad..1767a1780d 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/accountlinking -page_title: Account Linking -sidebar_position: 8 description: References documentation for the supertokens-node/recipe/accountlinking package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 8 --- -# Account Linking - - ## Classes ### default @@ -34,7 +27,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/accountlinking/index.ts:24](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/index.ts#L24) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/accountlinking/index.ts:24](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/accountlinking/index.ts#L24) | #### Methods @@ -60,7 +53,7 @@ Defined in: [recipe/accountlinking/index.ts:84](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns @@ -109,7 +102,7 @@ Defined in: [recipe/accountlinking/index.ts:98](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `primaryUserId` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -160,7 +153,7 @@ Defined in: [recipe/accountlinking/index.ts:91](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns @@ -168,7 +161,7 @@ Defined in: [recipe/accountlinking/index.ts:91](https://github.com/supertokens/s `Promise`\< \| \{ `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); `wasAlreadyAPrimaryUser`: `boolean`; \} \| \{ @@ -206,13 +199,13 @@ no linking that happened. | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `session?` | `SessionContainerInterface` | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns -`Promise`\<[`User`](types.mdx#user)\> +`Promise`\<[`User`](types#user)\> ##### getPrimaryUserThatCanBeLinkedToRecipeUserId() @@ -238,12 +231,12 @@ into a primary user itself. | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns -`Promise`\<[`User`](types.mdx#user)\> +`Promise`\<[`User`](types#user)\> ##### isEmailChangeAllowed() @@ -262,7 +255,7 @@ Defined in: [recipe/accountlinking/index.ts:159](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `newEmail` | `string` | | `isVerified` | `boolean` | | `session?` | `SessionContainerInterface` | @@ -289,7 +282,7 @@ Defined in: [recipe/accountlinking/index.ts:137](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `session?` | `SessionContainerInterface` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -315,7 +308,7 @@ Defined in: [recipe/accountlinking/index.ts:121](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `newUser` | [`AccountInfoWithRecipeId`](recipe-accountlinking-types.mdx#accountinfowithrecipeid) | +| `newUser` | [`AccountInfoWithRecipeId`](recipe-accountlinking-types#accountinfowithrecipeid) | | `isVerified` | `boolean` | | `session?` | `SessionContainerInterface` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -357,7 +350,7 @@ Defined in: [recipe/accountlinking/index.ts:106](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `primaryUserId` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -367,12 +360,12 @@ Defined in: [recipe/accountlinking/index.ts:106](https://github.com/supertokens/ \| \{ `accountsAlreadyLinked`: `boolean`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `primaryUserId`: `string`; `status`: `"RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `description`: `string`; @@ -399,7 +392,7 @@ Defined in: [recipe/accountlinking/index.ts:114](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns @@ -434,7 +427,7 @@ Defined in: [recipe/accountlinking/index.ts:184](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns @@ -482,7 +475,7 @@ Defined in: [recipe/accountlinking/index.ts:186](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `primaryUserId` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -535,7 +528,7 @@ Defined in: [recipe/accountlinking/index.ts:185](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns @@ -543,7 +536,7 @@ Defined in: [recipe/accountlinking/index.ts:185](https://github.com/supertokens/ `Promise`\< \| \{ `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); `wasAlreadyAPrimaryUser`: `boolean`; \} \| \{ @@ -579,13 +572,13 @@ no linking that happened. | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `session?` | `SessionContainerInterface` | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns -`Promise`\<[`User`](types.mdx#user)\> +`Promise`\<[`User`](types#user)\> *** @@ -610,12 +603,12 @@ into a primary user itself. | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns -`Promise`\<[`User`](types.mdx#user)\> +`Promise`\<[`User`](types#user)\> *** @@ -631,11 +624,11 @@ Defined in: [recipe/accountlinking/index.ts:183](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-accountlinking-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-accountlinking-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -651,7 +644,7 @@ Defined in: [recipe/accountlinking/index.ts:193](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `newEmail` | `string` | | `isVerified` | `boolean` | | `session?` | `SessionContainerInterface` | @@ -676,7 +669,7 @@ Defined in: [recipe/accountlinking/index.ts:192](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `session?` | `SessionContainerInterface` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -699,7 +692,7 @@ Defined in: [recipe/accountlinking/index.ts:191](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `newUser` | [`AccountInfoWithRecipeId`](recipe-accountlinking-types.mdx#accountinfowithrecipeid) | +| `newUser` | [`AccountInfoWithRecipeId`](recipe-accountlinking-types#accountinfowithrecipeid) | | `isVerified` | `boolean` | | `session?` | `SessionContainerInterface` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -740,7 +733,7 @@ Defined in: [recipe/accountlinking/index.ts:187](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `primaryUserId` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -750,12 +743,12 @@ Defined in: [recipe/accountlinking/index.ts:187](https://github.com/supertokens/ \| \{ `accountsAlreadyLinked`: `boolean`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `primaryUserId`: `string`; `status`: `"RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `description`: `string`; @@ -784,7 +777,7 @@ Defined in: [recipe/accountlinking/index.ts:188](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns @@ -799,4 +792,4 @@ Defined in: [recipe/accountlinking/index.ts:188](https://github.com/supertokens/ ### RecipeInterface -Re-exports [RecipeInterface](recipe-accountlinking-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-accountlinking-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard-types.mdx index 7b648a7304..859394d3c6 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/dashboard/types -page_title: Dashboard Types -sidebar_position: 11 description: References documentation for the supertokens-node/recipe/dashboard/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 11 --- -# Dashboard Types - - ## Type Aliases ### APIFunction() @@ -29,7 +22,7 @@ Defined in: [recipe/dashboard/types.ts:68](https://github.com/supertokens/supert | `apiImplementation` | [`APIInterface`](#apiinterface) | | `tenantId` | `string` | | `options` | [`APIOptions`](#apioptions) | -| `userContext` | [`UserContext`](types.mdx#usercontext) | +| `userContext` | [`UserContext`](types#usercontext) | #### Returns @@ -65,7 +58,7 @@ Defined in: [recipe/dashboard/types.ts:54](https://github.com/supertokens/supert | Property | Type | Defined in | | ------ | ------ | ------ | -| `appInfo` | [`NormalisedAppinfo`](types.mdx#normalisedappinfo) | [recipe/dashboard/types.ts:61](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/dashboard/types.ts#L61) | +| `appInfo` | [`NormalisedAppinfo`](types#normalisedappinfo) | [recipe/dashboard/types.ts:61](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/dashboard/types.ts#L61) | | `config` | [`TypeNormalisedInput`](#typenormalisedinput) | [recipe/dashboard/types.ts:56](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/dashboard/types.ts#L56) | | `isInServerlessEnv` | `boolean` | [recipe/dashboard/types.ts:60](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/dashboard/types.ts#L60) | | `recipeId` | `string` | [recipe/dashboard/types.ts:57](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/dashboard/types.ts#L57) | @@ -142,8 +135,8 @@ Defined in: [recipe/dashboard/types.ts:46](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `userContext`: [`UserContext`](types.mdx#usercontext); \} | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input` | \{ `userContext`: [`UserContext`](types#usercontext); \} | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -161,10 +154,10 @@ Defined in: [recipe/dashboard/types.ts:47](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `config`: [`TypeNormalisedInput`](#typenormalisedinput); `req`: `BaseRequest`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `config`: [`TypeNormalisedInput`](#typenormalisedinput); `req`: `BaseRequest`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.config` | [`TypeNormalisedInput`](#typenormalisedinput) | | `input.req` | `BaseRequest` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard.mdx index 1d92c2a773..c74008a830 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/dashboard -page_title: Dashboard -sidebar_position: 11 description: References documentation for the supertokens-node/recipe/dashboard package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 11 --- -# Dashboard - - ## Classes ### default @@ -34,7 +27,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/dashboard/index.ts:19](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/dashboard/index.ts#L19) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/dashboard/index.ts:19](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/dashboard/index.ts#L19) | ## Variables @@ -50,26 +43,26 @@ Defined in: [recipe/dashboard/index.ts:22](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-dashboard-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-dashboard-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) ## References ### APIInterface -Re-exports [APIInterface](recipe-dashboard-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-dashboard-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-dashboard-types.mdx#apioptions) +Re-exports [APIOptions](recipe-dashboard-types#apioptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-dashboard-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-dashboard-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword-types.mdx index dcb0008ffb..f69b7f4ee0 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/emailpassword/types -page_title: EmailPassword Types -sidebar_position: 2 description: References documentation for the supertokens-node/recipe/emailpassword/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 2 --- -# EmailPassword Types - - ## Type Aliases ### APIInterface @@ -26,11 +19,11 @@ Defined in: [recipe/emailpassword/types.ts:208](https://github.com/supertokens/s | Property | Type | Defined in | | ------ | ------ | ------ | -| `emailExistsGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `exists`: `boolean`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/emailpassword/types.ts:209](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L209) | -| `generatePasswordResetTokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| \{ `reason`: `string`; `status`: `"PASSWORD_RESET_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/emailpassword/types.ts:219](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L219) | -| `passwordResetPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `email`: `string`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `status`: `"RESET_PASSWORD_INVALID_TOKEN_ERROR"`; \} \| \{ `failureReason`: `string`; `status`: `"PASSWORD_POLICY_VIOLATED_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/emailpassword/types.ts:240](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L240) | -| `signInPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `reason`: `string`; `status`: `"SIGN_IN_NOT_ALLOWED"`; \} \| \{ `status`: `"WRONG_CREDENTIALS_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/emailpassword/types.ts:264](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L264) | -| `signUpPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `reason`: `string`; `status`: `"SIGN_UP_NOT_ALLOWED"`; \} \| \{ `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/emailpassword/types.ts:292](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L292) | +| `emailExistsGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `exists`: `boolean`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/emailpassword/types.ts:209](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L209) | +| `generatePasswordResetTokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| \{ `reason`: `string`; `status`: `"PASSWORD_RESET_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/emailpassword/types.ts:219](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L219) | +| `passwordResetPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `email`: `string`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `status`: `"RESET_PASSWORD_INVALID_TOKEN_ERROR"`; \} \| \{ `failureReason`: `string`; `status`: `"PASSWORD_POLICY_VIOLATED_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/emailpassword/types.ts:240](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L240) | +| `signInPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `reason`: `string`; `status`: `"SIGN_IN_NOT_ALLOWED"`; \} \| \{ `status`: `"WRONG_CREDENTIALS_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/emailpassword/types.ts:264](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L264) | +| `signUpPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `reason`: `string`; `status`: `"SIGN_UP_NOT_ALLOWED"`; \} \| \{ `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/emailpassword/types.ts:292](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L292) | *** @@ -46,7 +39,7 @@ Defined in: [recipe/emailpassword/types.ts:197](https://github.com/supertokens/s | Property | Type | Defined in | | ------ | ------ | ------ | -| `appInfo` | [`NormalisedAppinfo`](types.mdx#normalisedappinfo) | [recipe/emailpassword/types.ts:199](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L199) | +| `appInfo` | [`NormalisedAppinfo`](types#normalisedappinfo) | [recipe/emailpassword/types.ts:199](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L199) | | `config` | [`TypeNormalisedInput`](#typenormalisedinput) | [recipe/emailpassword/types.ts:200](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L200) | | `emailDelivery` | `EmailDeliveryIngredient`\<[`TypeEmailPasswordEmailDeliveryInput`](#typeemailpasswordemaildeliveryinput)\> | [recipe/emailpassword/types.ts:205](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L205) | | `isInServerlessEnv` | `boolean` | [recipe/emailpassword/types.ts:202](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L202) | @@ -105,10 +98,10 @@ Defined in: [recipe/emailpassword/types.ts:167](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `tenantId`: `string`; `token`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `tenantId`: `string`; `token`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.tenantId` | `string` | | `input.token` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -142,19 +135,19 @@ Defined in: [recipe/emailpassword/types.ts:114](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `password`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `password`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | | `input.password` | `string` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; @@ -183,10 +176,10 @@ need to know which email to use to create an emailpassword account later on. | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `userId`: `string`; \} | +| `input` | \{ `email`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); `userId`: `string`; \} | | `input.email` | `string` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.userId` | `string` | ###### Returns @@ -227,21 +220,21 @@ Defined in: [recipe/emailpassword/types.ts:128](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `password`: `string`; `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `password`: `string`; `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | | `input.password` | `string` | | `input.session` | `SessionContainerInterface` \| `undefined` | | `input.shouldTryLinkingWithSessionUser` | `boolean` \| `undefined` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"WRONG_CREDENTIALS_ERROR"`; @@ -281,21 +274,21 @@ Defined in: [recipe/emailpassword/types.ts:87](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `password`: `string`; `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `password`: `string`; `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | | `input.password` | `string` | | `input.session` | `SessionContainerInterface` \| `undefined` | | `input.shouldTryLinkingWithSessionUser` | `boolean` \| `undefined` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; @@ -331,13 +324,13 @@ Defined in: [recipe/emailpassword/types.ts:176](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `applyPasswordPolicy?`: `boolean`; `email?`: `string`; `password?`: `string`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); `tenantIdForPasswordPolicy`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `applyPasswordPolicy?`: `boolean`; `email?`: `string`; `password?`: `string`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `tenantIdForPasswordPolicy`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.applyPasswordPolicy?` | `boolean` | | `input.email?` | `string` | | `input.password?` | `string` | -| `input.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `input.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `input.tenantIdForPasswordPolicy` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -374,19 +367,19 @@ Defined in: [recipe/emailpassword/types.ts:148](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `password`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `password`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | | `input.password` | `string` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"WRONG_CREDENTIALS_ERROR"`; @@ -422,7 +415,7 @@ Defined in: [recipe/emailpassword/types.ts:321](https://github.com/supertokens/s | `user` | `object` | [recipe/emailpassword/types.ts:323](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L323) | | `user.email` | `string` | [recipe/emailpassword/types.ts:326](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L326) | | `user.id` | `string` | [recipe/emailpassword/types.ts:324](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L324) | -| `user.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) \| `undefined` | [recipe/emailpassword/types.ts:325](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L325) | +| `user.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) \| `undefined` | [recipe/emailpassword/types.ts:325](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/types.ts#L325) | *** diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword.mdx index 9e887c86ea..59bca79b60 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/emailpassword -page_title: EmailPassword -sidebar_position: 2 description: References documentation for the supertokens-node/recipe/emailpassword package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 2 --- -# EmailPassword - - ## Classes ### default @@ -35,7 +28,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | | `Error` | `static` | *typeof* `default` | `SuperTokensError` | [recipe/emailpassword/index.ts:30](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/index.ts#L30) | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/emailpassword/index.ts:28](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/index.ts#L28) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/emailpassword/index.ts:28](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailpassword/index.ts#L28) | #### Methods @@ -217,7 +210,7 @@ Defined in: [recipe/emailpassword/index.ts:343](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | [`TypeEmailPasswordPasswordResetEmailDeliveryInput`](recipe-emailpassword-types.mdx#typeemailpasswordpasswordresetemaildeliveryinput) & `object` | +| `input` | [`TypeEmailPasswordPasswordResetEmailDeliveryInput`](recipe-emailpassword-types#typeemailpasswordpasswordresetemaildeliveryinput) & `object` | ###### Returns @@ -289,9 +282,9 @@ Defined in: [recipe/emailpassword/index.ts:100](https://github.com/supertokens/s `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"WRONG_CREDENTIALS_ERROR"`; @@ -339,9 +332,9 @@ Defined in: [recipe/emailpassword/index.ts:107](https://github.com/supertokens/s `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"WRONG_CREDENTIALS_ERROR"`; @@ -391,9 +384,9 @@ Defined in: [recipe/emailpassword/index.ts:32](https://github.com/supertokens/su `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; @@ -441,9 +434,9 @@ Defined in: [recipe/emailpassword/index.ts:46](https://github.com/supertokens/su `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; @@ -479,11 +472,11 @@ Defined in: [recipe/emailpassword/index.ts:255](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `applyPasswordPolicy?`: `boolean`; `email?`: `string`; `password?`: `string`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); `tenantIdForPasswordPolicy?`: `string`; `userContext?`: `Record`\<`string`, `any`\>; \} | +| `input` | \{ `applyPasswordPolicy?`: `boolean`; `email?`: `string`; `password?`: `string`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `tenantIdForPasswordPolicy?`: `string`; `userContext?`: `Record`\<`string`, `any`\>; \} | | `input.applyPasswordPolicy?` | `boolean` | | `input.email?` | `string` | | `input.password?` | `string` | -| `input.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `input.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `input.tenantIdForPasswordPolicy?` | `string` | | `input.userContext?` | `Record`\<`string`, `any`\> | @@ -677,11 +670,11 @@ Defined in: [recipe/emailpassword/index.ts:355](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-emailpassword-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-emailpassword-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -734,7 +727,7 @@ Defined in: [recipe/emailpassword/index.ts:379](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | [`TypeEmailPasswordPasswordResetEmailDeliveryInput`](recipe-emailpassword-types.mdx#typeemailpasswordpasswordresetemaildeliveryinput) & `object` | +| `input` | [`TypeEmailPasswordPasswordResetEmailDeliveryInput`](recipe-emailpassword-types#typeemailpasswordpasswordresetemaildeliveryinput) & `object` | #### Returns @@ -836,9 +829,9 @@ Defined in: [recipe/emailpassword/index.ts:361](https://github.com/supertokens/s `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"WRONG_CREDENTIALS_ERROR"`; @@ -884,9 +877,9 @@ Defined in: [recipe/emailpassword/index.ts:361](https://github.com/supertokens/s `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"WRONG_CREDENTIALS_ERROR"`; @@ -968,9 +961,9 @@ Defined in: [recipe/emailpassword/index.ts:359](https://github.com/supertokens/s `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; @@ -1016,9 +1009,9 @@ Defined in: [recipe/emailpassword/index.ts:359](https://github.com/supertokens/s `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; @@ -1056,11 +1049,11 @@ Defined in: [recipe/emailpassword/index.ts:371](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `applyPasswordPolicy?`: `boolean`; `email?`: `string`; `password?`: `string`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); `tenantIdForPasswordPolicy?`: `string`; `userContext?`: `Record`\<`string`, `any`\>; \} | +| `input` | \{ `applyPasswordPolicy?`: `boolean`; `email?`: `string`; `password?`: `string`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `tenantIdForPasswordPolicy?`: `string`; `userContext?`: `Record`\<`string`, `any`\>; \} | | `input.applyPasswordPolicy?` | `boolean` | | `input.email?` | `string` | | `input.password?` | `string` | -| `input.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `input.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `input.tenantIdForPasswordPolicy?` | `string` | | `input.userContext?` | `Record`\<`string`, `any`\> | @@ -1110,16 +1103,16 @@ Defined in: [recipe/emailpassword/index.ts:363](https://github.com/supertokens/s ### APIInterface -Re-exports [APIInterface](recipe-emailpassword-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-emailpassword-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-emailpassword-types.mdx#apioptions) +Re-exports [APIOptions](recipe-emailpassword-types#apioptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-emailpassword-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-emailpassword-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification-types.mdx index 19ad8f9576..f2f15a6325 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/emailverification/types -page_title: EmailVerification Types -sidebar_position: 6 description: References documentation for the supertokens-node/recipe/emailverification/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 6 --- -# EmailVerification Types - - ## Type Aliases ### APIInterface @@ -26,9 +19,9 @@ Defined in: [recipe/emailverification/types.ts:127](https://github.com/supertoke | Property | Type | Defined in | | ------ | ------ | ------ | -| `generateEmailVerifyTokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| \{ `newSession?`: `SessionContainerInterface`; `status`: `"EMAIL_ALREADY_VERIFIED_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/emailverification/types.ts:153](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L153) | -| `isEmailVerifiedGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `isVerified`: `boolean`; `newSession?`: `SessionContainerInterface`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/emailverification/types.ts:142](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L142) | -| `verifyEmailPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `newSession?`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`UserEmailInfo`](#useremailinfo); \} \| \{ `status`: `"EMAIL_VERIFICATION_INVALID_TOKEN_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/emailverification/types.ts:128](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L128) | +| `generateEmailVerifyTokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| \{ `newSession?`: `SessionContainerInterface`; `status`: `"EMAIL_ALREADY_VERIFIED_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/emailverification/types.ts:153](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L153) | +| `isEmailVerifiedGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `isVerified`: `boolean`; `newSession?`: `SessionContainerInterface`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/emailverification/types.ts:142](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L142) | +| `verifyEmailPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `newSession?`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`UserEmailInfo`](#useremailinfo); \} \| \{ `status`: `"EMAIL_VERIFICATION_INVALID_TOKEN_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/emailverification/types.ts:128](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L128) | *** @@ -44,7 +37,7 @@ Defined in: [recipe/emailverification/types.ts:116](https://github.com/supertoke | Property | Type | Defined in | | ------ | ------ | ------ | -| `appInfo` | [`NormalisedAppinfo`](types.mdx#normalisedappinfo) | [recipe/emailverification/types.ts:118](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L118) | +| `appInfo` | [`NormalisedAppinfo`](types#normalisedappinfo) | [recipe/emailverification/types.ts:118](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L118) | | `config` | [`TypeNormalisedInput`](#typenormalisedinput) | [recipe/emailverification/types.ts:119](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L119) | | `emailDelivery` | `EmailDeliveryIngredient`\<[`TypeEmailVerificationEmailDeliveryInput`](#typeemailverificationemaildeliveryinput)\> | [recipe/emailverification/types.ts:124](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L124) | | `isInServerlessEnv` | `boolean` | [recipe/emailverification/types.ts:121](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L121) | @@ -74,9 +67,9 @@ Defined in: [recipe/emailverification/types.ts:180](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `user` | [`User`](types.mdx#user) \| `undefined` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | -| `userContext` | [`UserContext`](types.mdx#usercontext) | +| `user` | [`User`](types#user) \| `undefined` | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | +| `userContext` | [`UserContext`](types#usercontext) | #### Returns @@ -120,11 +113,11 @@ Defined in: [recipe/emailverification/types.ts:80](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | -| `input.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `input.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -149,10 +142,10 @@ Defined in: [recipe/emailverification/types.ts:100](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | -| `input.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -172,11 +165,11 @@ Defined in: [recipe/emailverification/types.ts:102](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | -| `input.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `input.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -198,10 +191,10 @@ Defined in: [recipe/emailverification/types.ts:109](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | -| `input.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -228,11 +221,11 @@ Defined in: [recipe/emailverification/types.ts:93](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `input` | \{ `attemptAccountLinking`: `boolean`; `tenantId`: `string`; `token`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `attemptAccountLinking`: `boolean`; `tenantId`: `string`; `token`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.attemptAccountLinking` | `boolean` | | `input.tenantId` | `string` | | `input.token` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -265,7 +258,7 @@ Defined in: [recipe/emailverification/types.ts:166](https://github.com/supertoke | `user` | `object` | [recipe/emailverification/types.ts:168](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L168) | | `user.email` | `string` | [recipe/emailverification/types.ts:174](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L174) | | `user.id` | `string` | [recipe/emailverification/types.ts:172](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L172) | -| `user.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | [recipe/emailverification/types.ts:173](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L173) | +| `user.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | [recipe/emailverification/types.ts:173](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L173) | *** @@ -324,4 +317,4 @@ Defined in: [recipe/emailverification/types.ts:74](https://github.com/supertoken | Property | Type | Defined in | | ------ | ------ | ------ | | `email` | `string` | [recipe/emailverification/types.ts:76](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L76) | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | [recipe/emailverification/types.ts:75](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L75) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | [recipe/emailverification/types.ts:75](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/types.ts#L75) | diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification.mdx index a1e16f64ad..db5dd5b302 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/emailverification -page_title: EmailVerification -sidebar_position: 6 description: References documentation for the supertokens-node/recipe/emailverification package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 6 --- -# EmailVerification - - ## Classes ### default @@ -36,7 +29,7 @@ new default(): default; | ------ | ------ | ------ | ------ | ------ | | `EmailVerificationClaim` | `static` | `EmailVerificationClaimClass` | `EmailVerificationClaim` | [recipe/emailverification/index.ts:36](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/index.ts#L36) | | `Error` | `static` | *typeof* `default` | `SuperTokensError` | [recipe/emailverification/index.ts:34](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/index.ts#L34) | -| `init` | `static` | (`config`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/emailverification/index.ts:32](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/index.ts#L32) | +| `init` | `static` | (`config`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/emailverification/index.ts:32](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/emailverification/index.ts#L32) | #### Methods @@ -64,7 +57,7 @@ Defined in: [recipe/emailverification/index.ts:74](https://github.com/supertoken | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -103,7 +96,7 @@ Defined in: [recipe/emailverification/index.ts:38](https://github.com/supertoken | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -133,7 +126,7 @@ Defined in: [recipe/emailverification/index.ts:176](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -160,7 +153,7 @@ Defined in: [recipe/emailverification/index.ts:198](https://github.com/supertoke | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -182,7 +175,7 @@ Defined in: [recipe/emailverification/index.ts:256](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `input` | [`TypeEmailVerificationEmailDeliveryInput`](recipe-emailverification-types.mdx#typeemailverificationemaildeliveryinput) & `object` | +| `input` | [`TypeEmailVerificationEmailDeliveryInput`](recipe-emailverification-types#typeemailverificationemaildeliveryinput) & `object` | ###### Returns @@ -213,7 +206,7 @@ Defined in: [recipe/emailverification/index.ts:109](https://github.com/supertoke | ------ | ------ | | `tenantId` | `string` | | `userId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -244,7 +237,7 @@ Defined in: [recipe/emailverification/index.ts:233](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -287,7 +280,7 @@ Defined in: [recipe/emailverification/index.ts:162](https://github.com/supertoke `Promise`\< \| \{ `status`: `"OK"`; - `user`: [`UserEmailInfo`](recipe-emailverification-types.mdx#useremailinfo); + `user`: [`UserEmailInfo`](recipe-emailverification-types#useremailinfo); \} \| \{ `status`: `"EMAIL_VERIFICATION_INVALID_TOKEN_ERROR"`; @@ -315,7 +308,7 @@ Defined in: [recipe/emailverification/index.ts:271](https://github.com/supertoke | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -352,7 +345,7 @@ Defined in: [recipe/emailverification/index.ts:269](https://github.com/supertoke | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -401,11 +394,11 @@ Defined in: [recipe/emailverification/index.ts:265](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `config` | [`TypeInput`](recipe-emailverification-types.mdx#typeinput) | +| `config` | [`TypeInput`](recipe-emailverification-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -421,7 +414,7 @@ Defined in: [recipe/emailverification/index.ts:277](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -446,7 +439,7 @@ Defined in: [recipe/emailverification/index.ts:279](https://github.com/supertoke | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -470,7 +463,7 @@ Defined in: [recipe/emailverification/index.ts:285](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `input` | [`TypeEmailVerificationEmailDeliveryInput`](recipe-emailverification-types.mdx#typeemailverificationemaildeliveryinput) & `object` | +| `input` | [`TypeEmailVerificationEmailDeliveryInput`](recipe-emailverification-types#typeemailverificationemaildeliveryinput) & `object` | #### Returns @@ -498,7 +491,7 @@ Defined in: [recipe/emailverification/index.ts:273](https://github.com/supertoke | ------ | ------ | | `tenantId` | `string` | | `userId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -528,7 +521,7 @@ Defined in: [recipe/emailverification/index.ts:281](https://github.com/supertoke | Parameter | Type | | ------ | ------ | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `email?` | `string` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -569,7 +562,7 @@ Defined in: [recipe/emailverification/index.ts:275](https://github.com/supertoke `Promise`\< \| \{ `status`: `"OK"`; - `user`: [`UserEmailInfo`](recipe-emailverification-types.mdx#useremailinfo); + `user`: [`UserEmailInfo`](recipe-emailverification-types#useremailinfo); \} \| \{ `status`: `"EMAIL_VERIFICATION_INVALID_TOKEN_ERROR"`; @@ -579,22 +572,22 @@ Defined in: [recipe/emailverification/index.ts:275](https://github.com/supertoke ### APIInterface -Re-exports [APIInterface](recipe-emailverification-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-emailverification-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-emailverification-types.mdx#apioptions) +Re-exports [APIOptions](recipe-emailverification-types#apioptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-emailverification-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-emailverification-types#recipeinterface) *** ### UserEmailInfo -Re-exports [UserEmailInfo](recipe-emailverification-types.mdx#useremailinfo) +Re-exports [UserEmailInfo](recipe-emailverification-types#useremailinfo) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-jwt-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-jwt-types.mdx index 934c078065..e39911bb38 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-jwt-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-jwt-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/jwt/types -page_title: JWT Types -sidebar_position: 9 description: References documentation for the supertokens-node/recipe/jwt/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 9 --- -# JWT Types - - ## Type Aliases ### APIInterface @@ -26,7 +19,7 @@ Defined in: [recipe/jwt/types.ts:82](https://github.com/supertokens/supertokens- | Property | Type | Defined in | | ------ | ------ | ------ | -| `getJWKSGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `keys`: [`JsonWebKey`](#jsonwebkey)[]; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/jwt/types.ts:83](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/jwt/types.ts#L83) | +| `getJWKSGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `keys`: [`JsonWebKey`](#jsonwebkey)[]; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/jwt/types.ts:83](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/jwt/types.ts#L83) | *** @@ -101,9 +94,9 @@ Defined in: [recipe/jwt/types.ts:61](https://github.com/supertokens/supertokens- | Parameter | Type | | ------ | ------ | -| `input` | \{ `payload?`: `any`; `userContext`: [`UserContext`](types.mdx#usercontext); `useStaticSigningKey?`: `boolean`; `validitySeconds?`: `number`; \} | +| `input` | \{ `payload?`: `any`; `userContext`: [`UserContext`](types#usercontext); `useStaticSigningKey?`: `boolean`; `validitySeconds?`: `number`; \} | | `input.payload?` | `any` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.useStaticSigningKey?` | `boolean` | | `input.validitySeconds?` | `number` | @@ -133,8 +126,8 @@ Defined in: [recipe/jwt/types.ts:76](https://github.com/supertokens/supertokens- | Parameter | Type | | ------ | ------ | -| `input` | \{ `userContext`: [`UserContext`](types.mdx#usercontext); \} | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input` | \{ `userContext`: [`UserContext`](types#usercontext); \} | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-jwt.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-jwt.mdx index 738e2e0229..b1669bdb75 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-jwt.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-jwt.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/jwt -page_title: JWT -sidebar_position: 9 description: References documentation for the supertokens-node/recipe/jwt package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 9 --- -# JWT - - ## Classes ### default @@ -34,7 +27,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/jwt/index.ts:21](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/jwt/index.ts#L21) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/jwt/index.ts:21](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/jwt/index.ts#L21) | #### Methods @@ -97,7 +90,7 @@ Defined in: [recipe/jwt/index.ts:37](https://github.com/supertokens/supertokens- ###### Returns `Promise`\<\{ - `keys`: [`JsonWebKey`](recipe-jwt-types.mdx#jsonwebkey)[]; + `keys`: [`JsonWebKey`](recipe-jwt-types#jsonwebkey)[]; `validityInSeconds?`: `number`; \}\> @@ -160,7 +153,7 @@ Defined in: [recipe/jwt/index.ts:46](https://github.com/supertokens/supertokens- #### Returns `Promise`\<\{ - `keys`: [`JsonWebKey`](recipe-jwt-types.mdx#jsonwebkey)[]; + `keys`: [`JsonWebKey`](recipe-jwt-types#jsonwebkey)[]; `validityInSeconds?`: `number`; \}\> @@ -178,32 +171,32 @@ Defined in: [recipe/jwt/index.ts:44](https://github.com/supertokens/supertokens- | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-jwt-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-jwt-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) ## References ### APIInterface -Re-exports [APIInterface](recipe-jwt-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-jwt-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-jwt-types.mdx#apioptions) +Re-exports [APIOptions](recipe-jwt-types#apioptions) *** ### JsonWebKey -Re-exports [JsonWebKey](recipe-jwt-types.mdx#jsonwebkey) +Re-exports [JsonWebKey](recipe-jwt-types#jsonwebkey) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-jwt-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-jwt-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth-types.mdx index 6ef673a6e5..3190ddffa9 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/multifactorauth/types -page_title: MFA Types -sidebar_position: 7 description: References documentation for the supertokens-node/recipe/multifactorauth/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 7 --- -# MFA Types - - ## Type Aliases ### APIInterface @@ -26,7 +19,7 @@ Defined in: [recipe/multifactorauth/types.ts:118](https://github.com/supertokens | Property | Type | Defined in | | ------ | ------ | ------ | -| `resyncSessionAndFetchMFAInfoPUT` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `emails`: `Record`\<`string`, `string`[] \| `undefined`\>; `factors`: \{ `allowedToSetup`: `string`[]; `alreadySetup`: `string`[]; `next`: `string`[]; \}; `phoneNumbers`: `Record`\<`string`, `string`[] \| `undefined`\>; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/multifactorauth/types.ts:119](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multifactorauth/types.ts#L119) | +| `resyncSessionAndFetchMFAInfoPUT` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `emails`: `Record`\<`string`, `string`[] \| `undefined`\>; `factors`: \{ `allowedToSetup`: `string`[]; `alreadySetup`: `string`[]; `next`: `string`[]; \}; `phoneNumbers`: `Record`\<`string`, `string`[] \| `undefined`\>; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/multifactorauth/types.ts:119](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multifactorauth/types.ts#L119) | *** @@ -64,7 +57,7 @@ Defined in: [recipe/multifactorauth/types.ts:138](https://github.com/supertokens | Parameter | Type | | ------ | ------ | -| `tenantConfig` | [`TenantConfig`](recipe-multitenancy-types.mdx#tenantconfig) | +| `tenantConfig` | [`TenantConfig`](recipe-multitenancy-types#tenantconfig) | #### Returns @@ -91,8 +84,8 @@ Defined in: [recipe/multifactorauth/types.ts:140](https://github.com/supertokens | Parameter | Type | | ------ | ------ | -| `user` | [`User`](index.mdx#user-1) | -| `sessionRecipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `user` | [`User`](index#user-1) | +| `sessionRecipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | #### Returns @@ -118,8 +111,8 @@ Defined in: [recipe/multifactorauth/types.ts:136](https://github.com/supertokens | Parameter | Type | | ------ | ------ | -| `user` | [`User`](index.mdx#user-1) | -| `userContext` | [`UserContext`](types.mdx#usercontext) | +| `user` | [`User`](index#user-1) | +| `userContext` | [`UserContext`](types#usercontext) | #### Returns @@ -146,8 +139,8 @@ Defined in: [recipe/multifactorauth/types.ts:144](https://github.com/supertokens | Parameter | Type | | ------ | ------ | -| `user` | [`User`](index.mdx#user-1) | -| `sessionRecipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `user` | [`User`](index#user-1) | +| `sessionRecipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | #### Returns diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth.mdx index 53c41e3d03..3b11b5c7dd 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/multifactorauth -page_title: MFA -sidebar_position: 7 description: References documentation for the supertokens-node/recipe/multifactorauth package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 7 --- -# MFA - - ## Classes ### default @@ -43,7 +36,7 @@ new default(): default; | `FactorIds.THIRDPARTY` | `public` | `string` | `"thirdparty"` | [recipe/multifactorauth/types.ts:158](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multifactorauth/types.ts#L158) | | `FactorIds.TOTP` | `public` | `string` | `"totp"` | [recipe/multifactorauth/types.ts:159](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multifactorauth/types.ts#L159) | | `FactorIds.WEBAUTHN` | `public` | `string` | `"webauthn"` | [recipe/multifactorauth/types.ts:153](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multifactorauth/types.ts#L153) | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/multifactorauth/index.ts:26](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multifactorauth/index.ts#L26) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/multifactorauth/index.ts:26](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multifactorauth/index.ts#L26) | | `MultiFactorAuthClaim` | `static` | `MultiFactorAuthClaimClass` | `MultiFactorAuthClaim` | [recipe/multifactorauth/index.ts:28](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multifactorauth/index.ts#L28) | #### Methods @@ -130,7 +123,7 @@ Defined in: [recipe/multifactorauth/index.ts:58](https://github.com/supertokens/ ###### Returns -`Promise`\<[`MFARequirementList`](recipe-multifactorauth-types.mdx#mfarequirementlist)\> +`Promise`\<[`MFARequirementList`](recipe-multifactorauth-types#mfarequirementlist)\> ##### getRequiredSecondaryFactorsForUser() @@ -281,7 +274,7 @@ Defined in: [recipe/multifactorauth/index.ts:133](https://github.com/supertokens #### Returns -`Promise`\<[`MFARequirementList`](recipe-multifactorauth-types.mdx#mfarequirementlist)\> +`Promise`\<[`MFARequirementList`](recipe-multifactorauth-types#mfarequirementlist)\> *** @@ -318,11 +311,11 @@ Defined in: [recipe/multifactorauth/index.ts:126](https://github.com/supertokens | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-multifactorauth-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-multifactorauth-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -382,22 +375,22 @@ Defined in: [recipe/multifactorauth/index.ts:135](https://github.com/supertokens ### APIInterface -Re-exports [APIInterface](recipe-multifactorauth-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-multifactorauth-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-multifactorauth-types.mdx#apioptions) +Re-exports [APIOptions](recipe-multifactorauth-types#apioptions) *** ### FactorIds -Re-exports [FactorIds](recipe-multifactorauth-types.mdx#factorids) +Re-exports [FactorIds](recipe-multifactorauth-types#factorids) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-multifactorauth-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-multifactorauth-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy-types.mdx index bbe58dd925..4752c514ba 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/multitenancy/types -page_title: MultiTenancy Types -sidebar_position: 10 description: References documentation for the supertokens-node/recipe/multitenancy/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 10 --- -# MultiTenancy Types - - ## Type Aliases ### APIInterface @@ -26,7 +19,7 @@ Defined in: [recipe/multitenancy/types.ts:145](https://github.com/supertokens/su | Property | Type | Defined in | | ------ | ------ | ------ | -| `loginMethodsGET` | (`input`) => `Promise`\< \| \{ `emailPassword`: \{ `enabled`: `boolean`; \}; `firstFactors`: `string`[]; `passwordless`: \{ `enabled`: `boolean`; \}; `status`: `"OK"`; `thirdParty`: \{ `enabled`: `boolean`; `providers`: `object`[]; \}; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/multitenancy/types.ts:146](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L146) | +| `loginMethodsGET` | (`input`) => `Promise`\< \| \{ `emailPassword`: \{ `enabled`: `boolean`; \}; `firstFactors`: `string`[]; `passwordless`: \{ `enabled`: `boolean`; \}; `status`: `"OK"`; `thirdParty`: \{ `enabled`: `boolean`; `providers`: `object`[]; \}; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/multitenancy/types.ts:146](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L146) | *** @@ -50,7 +43,7 @@ Defined in: [recipe/multitenancy/types.ts:133](https://github.com/supertokens/su | `req` | `BaseRequest` | [recipe/multitenancy/types.ts:138](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L138) | | `res` | `BaseResponse` | [recipe/multitenancy/types.ts:139](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L139) | | `staticFirstFactors` | `string`[] \| `undefined` | [recipe/multitenancy/types.ts:142](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L142) | -| `staticThirdPartyProviders` | [`ProviderInput`](recipe-thirdparty-types.mdx#providerinput)[] | [recipe/multitenancy/types.ts:140](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L140) | +| `staticThirdPartyProviders` | [`ProviderInput`](recipe-thirdparty-types#providerinput)[] | [recipe/multitenancy/types.ts:140](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L140) | *** @@ -94,7 +87,7 @@ Defined in: [recipe/multitenancy/types.ts:46](https://github.com/supertokens/sup | `firstFactors?` | `string`[] | [recipe/multitenancy/types.ts:50](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L50) | | `requiredSecondaryFactors?` | `string`[] | [recipe/multitenancy/types.ts:51](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L51) | | `thirdParty` | `object` | [recipe/multitenancy/types.ts:47](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L47) | -| `thirdParty.providers` | [`ProviderConfig`](recipe-thirdparty-types.mdx#providerconfig)[] | [recipe/multitenancy/types.ts:48](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L48) | +| `thirdParty.providers` | [`ProviderConfig`](recipe-thirdparty-types#providerconfig)[] | [recipe/multitenancy/types.ts:48](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/types.ts#L48) | *** diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy.mdx index 248cb049f8..9ca77307e7 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/multitenancy -page_title: MultiTenancy -sidebar_position: 10 description: References documentation for the supertokens-node/recipe/multitenancy package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 10 --- -# MultiTenancy - - ## Classes ### default @@ -34,7 +27,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/multitenancy/index.ts:24](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/index.ts#L24) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/multitenancy/index.ts:24](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/multitenancy/index.ts#L24) | #### Methods @@ -68,7 +61,7 @@ Defined in: [recipe/multitenancy/index.ts:124](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns @@ -141,7 +134,7 @@ Defined in: [recipe/multitenancy/index.ts:90](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `config` | [`ProviderConfig`](recipe-thirdparty-types.mdx#providerconfig) | +| `config` | [`ProviderConfig`](recipe-thirdparty-types#providerconfig) | | `skipValidation?` | `boolean` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -225,7 +218,7 @@ Defined in: [recipe/multitenancy/index.ts:153](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns @@ -252,7 +245,7 @@ Defined in: [recipe/multitenancy/index.ts:60](https://github.com/supertokens/sup ###### Returns -`Promise`\<`object` & [`TenantConfig`](recipe-multitenancy-types.mdx#tenantconfig)\> +`Promise`\<`object` & [`TenantConfig`](recipe-multitenancy-types#tenantconfig)\> ##### listAllTenants() @@ -275,7 +268,7 @@ Defined in: [recipe/multitenancy/index.ts:76](https://github.com/supertokens/sup `Promise`\<\{ `status`: `"OK"`; - `tenants`: `object` & [`TenantConfig`](recipe-multitenancy-types.mdx#tenantconfig)[]; + `tenants`: `object` & [`TenantConfig`](recipe-multitenancy-types#tenantconfig)[]; \}\> ## Variables @@ -317,7 +310,7 @@ Defined in: [recipe/multitenancy/index.ts:180](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns @@ -387,7 +380,7 @@ Defined in: [recipe/multitenancy/index.ts:177](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `config` | [`ProviderConfig`](recipe-thirdparty-types.mdx#providerconfig) | +| `config` | [`ProviderConfig`](recipe-thirdparty-types#providerconfig) | | `skipValidation?` | `boolean` | | `userContext?` | `Record`\<`string`, `any`\> | @@ -471,7 +464,7 @@ Defined in: [recipe/multitenancy/index.ts:181](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | | `tenantId` | `string` | -| `recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns @@ -500,7 +493,7 @@ Defined in: [recipe/multitenancy/index.ts:174](https://github.com/supertokens/su #### Returns -`Promise`\<`object` & [`TenantConfig`](recipe-multitenancy-types.mdx#tenantconfig)\> +`Promise`\<`object` & [`TenantConfig`](recipe-multitenancy-types#tenantconfig)\> *** @@ -516,11 +509,11 @@ Defined in: [recipe/multitenancy/index.ts:170](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-multitenancy-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-multitenancy-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -545,23 +538,23 @@ Defined in: [recipe/multitenancy/index.ts:175](https://github.com/supertokens/su `Promise`\<\{ `status`: `"OK"`; - `tenants`: `object` & [`TenantConfig`](recipe-multitenancy-types.mdx#tenantconfig)[]; + `tenants`: `object` & [`TenantConfig`](recipe-multitenancy-types#tenantconfig)[]; \}\> ## References ### APIInterface -Re-exports [APIInterface](recipe-multitenancy-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-multitenancy-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-multitenancy-types.mdx#apioptions) +Re-exports [APIOptions](recipe-multitenancy-types#apioptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-multitenancy-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-multitenancy-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider-types.mdx index 81cfd3d7d6..17a3926f4a 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/oauth2provider/types -page_title: OAuth Provider Types -sidebar_position: 12 description: References documentation for the supertokens-node/recipe/oauth2provider/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 12 --- -# OAuth Provider Types - - ## Type Aliases ### APIInterface @@ -26,16 +19,16 @@ Defined in: [recipe/oauth2provider/types.ts:419](https://github.com/supertokens/ | Property | Type | Defined in | | ------ | ------ | ------ | -| `authGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `cookies?`: `string`[]; `redirectTo`: `string`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:430](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L430) | -| `endSessionGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `redirectTo`: `string`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:482](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L482) | -| `endSessionPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `redirectTo`: `string`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:491](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L491) | -| `introspectTokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| [`InstrospectTokenResponse`](#instrospecttokenresponse) \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| [`ErrorOAuth2`](#erroroauth2)\> | [recipe/oauth2provider/types.ts:474](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L474) | -| `loginGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `cookies?`: `string`[]; `frontendRedirectTo`: `string`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:420](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L420) | -| `loginInfoGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `info`: [`LoginInfo`](#logininfo); `status`: `"OK"`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:448](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L448) | -| `logoutPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `frontendRedirectTo`: `string`; `status`: `"OK"`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:500](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L500) | +| `authGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `cookies?`: `string`[]; `redirectTo`: `string`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:430](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L430) | +| `endSessionGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `redirectTo`: `string`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:482](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L482) | +| `endSessionPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `redirectTo`: `string`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:491](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L491) | +| `introspectTokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| [`InstrospectTokenResponse`](#instrospecttokenresponse) \| [`GeneralErrorResponse`](types#generalerrorresponse) \| [`ErrorOAuth2`](#erroroauth2)\> | [recipe/oauth2provider/types.ts:474](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L474) | +| `loginGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `cookies?`: `string`[]; `frontendRedirectTo`: `string`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:420](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L420) | +| `loginInfoGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `info`: [`LoginInfo`](#logininfo); `status`: `"OK"`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:448](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L448) | +| `logoutPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `frontendRedirectTo`: `string`; `status`: `"OK"`; \} \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:500](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L500) | | `revokeTokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| [`ErrorOAuth2`](#erroroauth2)\> | [recipe/oauth2provider/types.ts:465](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L465) | -| `tokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| [`TokenInfo`](#tokeninfo) \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:440](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L440) | -| `userInfoGET` | \| `undefined` \| (`input`) => `Promise`\< \| [`JSONObject`](types.mdx#jsonobject) \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:455](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L455) | +| `tokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| [`TokenInfo`](#tokeninfo) \| [`ErrorOAuth2`](#erroroauth2) \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:440](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L440) | +| `userInfoGET` | \| `undefined` \| (`input`) => `Promise`\< \| [`JSONObject`](types#jsonobject) \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/oauth2provider/types.ts:455](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L455) | *** @@ -76,7 +69,7 @@ Defined in: [recipe/oauth2provider/types.ts:68](https://github.com/supertokens/s | `amr?` | `string`[] | [recipe/oauth2provider/types.ts:73](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L73) | | `challenge` | `string` | [recipe/oauth2provider/types.ts:76](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L76) | | `client?` | `OAuth2Client` | [recipe/oauth2provider/types.ts:79](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L79) | -| `context?` | [`JSONObject`](types.mdx#jsonobject) | [recipe/oauth2provider/types.ts:82](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L82) | +| `context?` | [`JSONObject`](types#jsonobject) | [recipe/oauth2provider/types.ts:82](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L82) | | `loginChallenge?` | `string` | [recipe/oauth2provider/types.ts:85](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L85) | | `loginSessionId?` | `string` | [recipe/oauth2provider/types.ts:88](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L88) | | `oidcContext?` | `any` | [recipe/oauth2provider/types.ts:91](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/types.ts#L91) | @@ -264,14 +257,14 @@ Defined in: [recipe/oauth2provider/types.ts:579](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `user` | [`User`](index.mdx#user-1) | +| `user` | [`User`](index#user-1) | | `scopes` | `string`[] | | `sessionHandle` | `string` | -| `userContext` | [`UserContext`](types.mdx#usercontext) | +| `userContext` | [`UserContext`](types#usercontext) | #### Returns -`Promise`\<[`JSONObject`](types.mdx#jsonobject)\> +`Promise`\<[`JSONObject`](types#jsonobject)\> *** @@ -302,18 +295,18 @@ Defined in: [recipe/oauth2provider/types.ts:191](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `challenge`: `string`; `context?`: `any`; `grantAccessTokenAudience?`: `string`[]; `grantScope?`: `string`[]; `handledAt?`: `string`; `initialAccessTokenPayload`: [`JSONObject`](types.mdx#jsonobject) \| `undefined`; `initialIdTokenPayload`: [`JSONObject`](types.mdx#jsonobject) \| `undefined`; `rsub`: `string`; `sessionHandle`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `challenge`: `string`; `context?`: `any`; `grantAccessTokenAudience?`: `string`[]; `grantScope?`: `string`[]; `handledAt?`: `string`; `initialAccessTokenPayload`: [`JSONObject`](types#jsonobject) \| `undefined`; `initialIdTokenPayload`: [`JSONObject`](types#jsonobject) \| `undefined`; `rsub`: `string`; `sessionHandle`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.challenge` | `string` | | `input.context?` | `any` | | `input.grantAccessTokenAudience?` | `string`[] | | `input.grantScope?` | `string`[] | | `input.handledAt?` | `string` | -| `input.initialAccessTokenPayload` | [`JSONObject`](types.mdx#jsonobject) \| `undefined` | -| `input.initialIdTokenPayload` | [`JSONObject`](types.mdx#jsonobject) \| `undefined` | +| `input.initialAccessTokenPayload` | [`JSONObject`](types#jsonobject) \| `undefined` | +| `input.initialIdTokenPayload` | [`JSONObject`](types#jsonobject) \| `undefined` | | `input.rsub` | `string` | | `input.sessionHandle` | `string` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -341,7 +334,7 @@ Defined in: [recipe/oauth2provider/types.ts:222](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `acr?`: `string`; `amr?`: `string`[]; `challenge`: `string`; `context?`: `any`; `extendSessionLifespan?`: `boolean`; `identityProviderSessionId?`: `string`; `subject`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `acr?`: `string`; `amr?`: `string`[]; `challenge`: `string`; `context?`: `any`; `extendSessionLifespan?`: `boolean`; `identityProviderSessionId?`: `string`; `subject`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.acr?` | `string` | | `input.amr?` | `string`[] | | `input.challenge` | `string` | @@ -349,7 +342,7 @@ Defined in: [recipe/oauth2provider/types.ts:222](https://github.com/supertokens/ | `input.extendSessionLifespan?` | `boolean` | | `input.identityProviderSessionId?` | `string` | | `input.subject` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -376,9 +369,9 @@ Defined in: [recipe/oauth2provider/types.ts:412](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `challenge`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `challenge`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.challenge` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -405,11 +398,11 @@ Defined in: [recipe/oauth2provider/types.ts:179](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `cookies`: `string` \| `undefined`; `params`: `Record`\<`string`, `string`\>; `session`: `SessionContainerInterface` \| `undefined`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `cookies`: `string` \| `undefined`; `params`: `Record`\<`string`, `string`\>; `session`: `SessionContainerInterface` \| `undefined`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.cookies` | `string` \| `undefined` | | `input.params` | `Record`\<`string`, `string`\> | | `input.session` | `SessionContainerInterface` \| `undefined` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -432,16 +425,16 @@ Defined in: [recipe/oauth2provider/types.ts:342](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `client`: `OAuth2Client`; `scopes`: `string`[]; `sessionHandle`: `string` \| `undefined`; `user`: [`User`](index.mdx#user-1) \| `undefined`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `client`: `OAuth2Client`; `scopes`: `string`[]; `sessionHandle`: `string` \| `undefined`; `user`: [`User`](index#user-1) \| `undefined`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.client` | `OAuth2Client` | | `input.scopes` | `string`[] | | `input.sessionHandle` | `string` \| `undefined` | -| `input.user` | [`User`](index.mdx#user-1) \| `undefined` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.user` | [`User`](index#user-1) \| `undefined` | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns -`Promise`\<[`JSONObject`](types.mdx#jsonobject)\> +`Promise`\<[`JSONObject`](types#jsonobject)\> ##### buildIdTokenPayload() @@ -455,16 +448,16 @@ Defined in: [recipe/oauth2provider/types.ts:349](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `client`: `OAuth2Client`; `scopes`: `string`[]; `sessionHandle`: `string` \| `undefined`; `user`: [`User`](index.mdx#user-1) \| `undefined`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `client`: `OAuth2Client`; `scopes`: `string`[]; `sessionHandle`: `string` \| `undefined`; `user`: [`User`](index#user-1) \| `undefined`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.client` | `OAuth2Client` | | `input.scopes` | `string`[] | | `input.sessionHandle` | `string` \| `undefined` | -| `input.user` | [`User`](index.mdx#user-1) \| `undefined` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.user` | [`User`](index#user-1) \| `undefined` | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns -`Promise`\<[`JSONObject`](types.mdx#jsonobject)\> +`Promise`\<[`JSONObject`](types#jsonobject)\> ##### buildUserInfo() @@ -478,16 +471,16 @@ Defined in: [recipe/oauth2provider/types.ts:356](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `accessTokenPayload`: [`JSONObject`](types.mdx#jsonobject); `scopes`: `string`[]; `tenantId`: `string`; `user`: [`User`](index.mdx#user-1); `userContext`: [`UserContext`](types.mdx#usercontext); \} | -| `input.accessTokenPayload` | [`JSONObject`](types.mdx#jsonobject) | +| `input` | \{ `accessTokenPayload`: [`JSONObject`](types#jsonobject); `scopes`: `string`[]; `tenantId`: `string`; `user`: [`User`](index#user-1); `userContext`: [`UserContext`](types#usercontext); \} | +| `input.accessTokenPayload` | [`JSONObject`](types#jsonobject) | | `input.scopes` | `string`[] | | `input.tenantId` | `string` | -| `input.user` | [`User`](index.mdx#user-1) | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.user` | [`User`](index#user-1) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns -`Promise`\<[`JSONObject`](types.mdx#jsonobject)\> +`Promise`\<[`JSONObject`](types#jsonobject)\> ##### createOAuth2Client() @@ -575,11 +568,11 @@ Defined in: [recipe/oauth2provider/types.ts:406](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `params`: `Record`\<`string`, `string`\>; `session?`: `SessionContainerInterface`; `shouldTryRefresh`: `boolean`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `params`: `Record`\<`string`, `string`\>; `session?`: `SessionContainerInterface`; `shouldTryRefresh`: `boolean`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.params` | `Record`\<`string`, `string`\> | | `input.session?` | `SessionContainerInterface` | | `input.shouldTryRefresh` | `boolean` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -601,9 +594,9 @@ Defined in: [recipe/oauth2provider/types.ts:190](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `challenge`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `challenge`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.challenge` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -621,7 +614,7 @@ Defined in: [recipe/oauth2provider/types.ts:363](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \| \{ `forceFreshAuth`: `boolean`; `hint`: `string` \| `undefined`; `loginChallenge`: `string`; `tenantId`: `string`; `type`: `"login"`; `userContext`: [`UserContext`](types.mdx#usercontext); \} \| \{ `loginChallenge`: `string`; `type`: `"try-refresh"`; `userContext`: [`UserContext`](types.mdx#usercontext); \} \| \{ `logoutChallenge`: `string`; `type`: `"logout-confirmation"`; `userContext`: [`UserContext`](types.mdx#usercontext); \} \| \{ `type`: `"post-logout-fallback"`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \| \{ `forceFreshAuth`: `boolean`; `hint`: `string` \| `undefined`; `loginChallenge`: `string`; `tenantId`: `string`; `type`: `"login"`; `userContext`: [`UserContext`](types#usercontext); \} \| \{ `loginChallenge`: `string`; `type`: `"try-refresh"`; `userContext`: [`UserContext`](types#usercontext); \} \| \{ `logoutChallenge`: `string`; `type`: `"logout-confirmation"`; `userContext`: [`UserContext`](types#usercontext); \} \| \{ `type`: `"post-logout-fallback"`; `userContext`: [`UserContext`](types#usercontext); \} | ###### Returns @@ -641,9 +634,9 @@ Defined in: [recipe/oauth2provider/types.ts:218](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `challenge`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `challenge`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.challenge` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -672,9 +665,9 @@ Defined in: [recipe/oauth2provider/types.ts:252](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `clientId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `clientId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.clientId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -739,12 +732,12 @@ Defined in: [recipe/oauth2provider/types.ts:335](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `clientId`: `string`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1) \| `undefined`; `scopeParam`: `string`[]; `sessionHandle`: `string` \| `undefined`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `clientId`: `string`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1) \| `undefined`; `scopeParam`: `string`[]; `sessionHandle`: `string` \| `undefined`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.clientId` | `string` | -| `input.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) \| `undefined` | +| `input.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) \| `undefined` | | `input.scopeParam` | `string`[] | | `input.sessionHandle` | `string` \| `undefined` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -764,10 +757,10 @@ Defined in: [recipe/oauth2provider/types.ts:401](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `scopes?`: `string`[]; `token`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `scopes?`: `string`[]; `token`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.scopes?` | `string`[] | | `input.token` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -792,10 +785,10 @@ Defined in: [recipe/oauth2provider/types.ts:212](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `challenge`: `string`; `error`: [`ErrorOAuth2`](#erroroauth2); `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `challenge`: `string`; `error`: [`ErrorOAuth2`](#erroroauth2); `userContext`: [`UserContext`](types#usercontext); \} | | `input.challenge` | `string` | | `input.error` | [`ErrorOAuth2`](#erroroauth2) | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -823,10 +816,10 @@ Defined in: [recipe/oauth2provider/types.ts:246](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `challenge`: `string`; `error`: [`ErrorOAuth2`](#erroroauth2); `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `challenge`: `string`; `error`: [`ErrorOAuth2`](#erroroauth2); `userContext`: [`UserContext`](types#usercontext); \} | | `input.challenge` | `string` | | `input.error` | [`ErrorOAuth2`](#erroroauth2) | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -851,9 +844,9 @@ Defined in: [recipe/oauth2provider/types.ts:416](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `challenge`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `challenge`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.challenge` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -901,9 +894,9 @@ Defined in: [recipe/oauth2provider/types.ts:399](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `clientId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `clientId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.clientId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -925,9 +918,9 @@ Defined in: [recipe/oauth2provider/types.ts:400](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `sessionHandle`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `sessionHandle`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.sessionHandle` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -947,10 +940,10 @@ Defined in: [recipe/oauth2provider/types.ts:185](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `authorizationHeader?`: `string`; `body`: `Record`\<`string`, `string` \| `undefined`\>; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `authorizationHeader?`: `string`; `body`: `Record`\<`string`, `string` \| `undefined`\>; `userContext`: [`UserContext`](types#usercontext); \} | | `input.authorizationHeader?` | `string` | | `input.body` | `Record`\<`string`, `string` \| `undefined`\> | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -977,7 +970,7 @@ Defined in: [recipe/oauth2provider/types.ts:294](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | [`NonNullableProperties`](types.mdx#nonnullableproperties)\<`Omit`\<`Partial`\<`Omit`\<[`OAuth2ClientOptions`](#oauth2clientoptions), `"createdAt"` \| `"updatedAt"`\>\>, `"redirectUris"` \| `"grantTypes"` \| `"responseTypes"` \| `"metadata"`\>\> & `object` & `object` | +| `input` | [`NonNullableProperties`](types#nonnullableproperties)\<`Omit`\<`Partial`\<`Omit`\<[`OAuth2ClientOptions`](#oauth2clientoptions), `"createdAt"` \| `"updatedAt"`\>\>, `"redirectUris"` \| `"grantTypes"` \| `"responseTypes"` \| `"metadata"`\>\> & `object` & `object` | ###### Returns @@ -1007,19 +1000,19 @@ Defined in: [recipe/oauth2provider/types.ts:324](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `checkDatabase?`: `boolean`; `requirements?`: \{ `audience?`: `string`; `clientId?`: `string`; `scopes?`: `string`[]; \}; `token`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `checkDatabase?`: `boolean`; `requirements?`: \{ `audience?`: `string`; `clientId?`: `string`; `scopes?`: `string`[]; \}; `token`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.checkDatabase?` | `boolean` | | `input.requirements?` | \{ `audience?`: `string`; `clientId?`: `string`; `scopes?`: `string`[]; \} | | `input.requirements.audience?` | `string` | | `input.requirements.clientId?` | `string` | | `input.requirements.scopes?` | `string`[] | | `input.token` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns `Promise`\<\{ - `payload`: [`JSONObject`](types.mdx#jsonobject); + `payload`: [`JSONObject`](types#jsonobject); `status`: `"OK"`; \}\> @@ -1140,12 +1133,12 @@ Defined in: [recipe/oauth2provider/types.ts:585](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `user` | [`User`](index.mdx#user-1) | -| `accessTokenPayload` | [`JSONObject`](types.mdx#jsonobject) | +| `user` | [`User`](index#user-1) | +| `accessTokenPayload` | [`JSONObject`](types#jsonobject) | | `scopes` | `string`[] | | `tenantId` | `string` | -| `userContext` | [`UserContext`](types.mdx#usercontext) | +| `userContext` | [`UserContext`](types#usercontext) | #### Returns -`Promise`\<[`JSONObject`](types.mdx#jsonobject)\> +`Promise`\<[`JSONObject`](types#jsonobject)\> diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider.mdx index a10e4269f0..e03c1fbff7 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/oauth2provider -page_title: OAuth Provider -sidebar_position: 12 description: References documentation for the supertokens-node/recipe/oauth2provider package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 12 --- -# OAuth Provider - - ## Classes ### default @@ -34,7 +27,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/oauth2provider/index.ts:29](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/index.ts#L29) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/oauth2provider/index.ts:29](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/oauth2provider/index.ts#L29) | #### Methods @@ -59,7 +52,7 @@ Defined in: [recipe/oauth2provider/index.ts:43](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | [`CreateOAuth2ClientInput`](recipe-oauth2provider-types.mdx#createoauth2clientinput) | +| `input` | [`CreateOAuth2ClientInput`](recipe-oauth2provider-types#createoauth2clientinput) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns @@ -103,8 +96,8 @@ Defined in: [recipe/oauth2provider/index.ts:80](https://github.com/supertokens/s ###### Returns `Promise`\< - \| [`ErrorOAuth2`](recipe-oauth2provider-types.mdx#erroroauth2) - \| [`TokenInfo`](recipe-oauth2provider-types.mdx#tokeninfo)\> + \| [`ErrorOAuth2`](recipe-oauth2provider-types#erroroauth2) + \| [`TokenInfo`](recipe-oauth2provider-types#tokeninfo)\> ##### deleteOAuth2Client() @@ -126,7 +119,7 @@ Defined in: [recipe/oauth2provider/index.ts:55](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | [`DeleteOAuth2ClientInput`](recipe-oauth2provider-types.mdx#deleteoauth2clientinput) | +| `input` | [`DeleteOAuth2ClientInput`](recipe-oauth2provider-types#deleteoauth2clientinput) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns @@ -200,7 +193,7 @@ Defined in: [recipe/oauth2provider/index.ts:37](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | [`GetOAuth2ClientsInput`](recipe-oauth2provider-types.mdx#getoauth2clientsinput) | +| `input` | [`GetOAuth2ClientsInput`](recipe-oauth2provider-types#getoauth2clientsinput) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns @@ -245,7 +238,7 @@ Defined in: [recipe/oauth2provider/index.ts:99](https://github.com/supertokens/s ###### Returns `Promise`\< - \| [`ErrorOAuth2`](recipe-oauth2provider-types.mdx#erroroauth2) + \| [`ErrorOAuth2`](recipe-oauth2provider-types#erroroauth2) \| \{ `status`: `"OK"`; \}\> @@ -317,7 +310,7 @@ Defined in: [recipe/oauth2provider/index.ts:49](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | [`UpdateOAuth2ClientInput`](recipe-oauth2provider-types.mdx#updateoauth2clientinput) | +| `input` | [`UpdateOAuth2ClientInput`](recipe-oauth2provider-types#updateoauth2clientinput) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns @@ -363,7 +356,7 @@ Defined in: [recipe/oauth2provider/index.ts:62](https://github.com/supertokens/s ###### Returns `Promise`\<\{ - `payload`: [`JSONObject`](types.mdx#jsonobject); + `payload`: [`JSONObject`](types#jsonobject); `status`: `"OK"`; \}\> @@ -392,7 +385,7 @@ Defined in: [recipe/oauth2provider/index.ts:154](https://github.com/supertokens/ `Promise`\< \| InstrospectTokenResponse & \{ status: "OK"; \} - \| [`ErrorOAuth2`](recipe-oauth2provider-types.mdx#erroroauth2)\> + \| [`ErrorOAuth2`](recipe-oauth2provider-types#erroroauth2)\> ## Variables @@ -417,7 +410,7 @@ Defined in: [recipe/oauth2provider/index.ts:168](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | [`CreateOAuth2ClientInput`](recipe-oauth2provider-types.mdx#createoauth2clientinput) | +| `input` | [`CreateOAuth2ClientInput`](recipe-oauth2provider-types#createoauth2clientinput) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns @@ -458,8 +451,8 @@ Defined in: [recipe/oauth2provider/index.ts:177](https://github.com/supertokens/ #### Returns `Promise`\< - \| [`ErrorOAuth2`](recipe-oauth2provider-types.mdx#erroroauth2) - \| [`TokenInfo`](recipe-oauth2provider-types.mdx#tokeninfo)\> + \| [`ErrorOAuth2`](recipe-oauth2provider-types#erroroauth2) + \| [`TokenInfo`](recipe-oauth2provider-types#tokeninfo)\> *** @@ -483,7 +476,7 @@ Defined in: [recipe/oauth2provider/index.ts:172](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | [`DeleteOAuth2ClientInput`](recipe-oauth2provider-types.mdx#deleteoauth2clientinput) | +| `input` | [`DeleteOAuth2ClientInput`](recipe-oauth2provider-types#deleteoauth2clientinput) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns @@ -561,7 +554,7 @@ Defined in: [recipe/oauth2provider/index.ts:166](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | [`GetOAuth2ClientsInput`](recipe-oauth2provider-types.mdx#getoauth2clientsinput) | +| `input` | [`GetOAuth2ClientsInput`](recipe-oauth2provider-types#getoauth2clientsinput) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns @@ -592,11 +585,11 @@ Defined in: [recipe/oauth2provider/index.ts:163](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-oauth2provider-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-oauth2provider-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -624,7 +617,7 @@ Defined in: [recipe/oauth2provider/index.ts:179](https://github.com/supertokens/ #### Returns `Promise`\< - \| [`ErrorOAuth2`](recipe-oauth2provider-types.mdx#erroroauth2) + \| [`ErrorOAuth2`](recipe-oauth2provider-types#erroroauth2) \| \{ `status`: `"OK"`; \}\> @@ -702,7 +695,7 @@ Defined in: [recipe/oauth2provider/index.ts:170](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | [`UpdateOAuth2ClientInput`](recipe-oauth2provider-types.mdx#updateoauth2clientinput) | +| `input` | [`UpdateOAuth2ClientInput`](recipe-oauth2provider-types#updateoauth2clientinput) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns @@ -746,7 +739,7 @@ Defined in: [recipe/oauth2provider/index.ts:174](https://github.com/supertokens/ #### Returns `Promise`\<\{ - `payload`: [`JSONObject`](types.mdx#jsonobject); + `payload`: [`JSONObject`](types#jsonobject); `status`: `"OK"`; \}\> @@ -774,22 +767,22 @@ Defined in: [recipe/oauth2provider/index.ts:175](https://github.com/supertokens/ `Promise`\< \| InstrospectTokenResponse & \{ status: "OK"; \} - \| [`ErrorOAuth2`](recipe-oauth2provider-types.mdx#erroroauth2)\> + \| [`ErrorOAuth2`](recipe-oauth2provider-types#erroroauth2)\> ## References ### APIInterface -Re-exports [APIInterface](recipe-oauth2provider-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-oauth2provider-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-oauth2provider-types.mdx#apioptions) +Re-exports [APIOptions](recipe-oauth2provider-types#apioptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-oauth2provider-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-oauth2provider-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-openid-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-openid-types.mdx index ab616c386e..cc84b014a4 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-openid-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-openid-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/openid/types -page_title: OpenID Types -sidebar_position: 13 description: References documentation for the supertokens-node/recipe/openid/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 13 --- -# OpenID Types - - ## Type Aliases ### APIInterface @@ -26,7 +19,7 @@ Defined in: [recipe/openid/types.ts:47](https://github.com/supertokens/supertoke | Property | Type | Defined in | | ------ | ------ | ------ | -| `getOpenIdDiscoveryConfigurationGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `authorization_endpoint`: `string`; `end_session_endpoint`: `string`; `id_token_signing_alg_values_supported`: `string`[]; `issuer`: `string`; `jwks_uri`: `string`; `response_types_supported`: `string`[]; `revocation_endpoint`: `string`; `status`: `"OK"`; `subject_types_supported`: `string`[]; `token_endpoint`: `string`; `token_introspection_endpoint`: `string`; `userinfo_endpoint`: `string`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/openid/types.ts:48](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/openid/types.ts#L48) | +| `getOpenIdDiscoveryConfigurationGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `authorization_endpoint`: `string`; `end_session_endpoint`: `string`; `id_token_signing_alg_values_supported`: `string`[]; `issuer`: `string`; `jwks_uri`: `string`; `response_types_supported`: `string`[]; `revocation_endpoint`: `string`; `status`: `"OK"`; `subject_types_supported`: `string`[]; `token_endpoint`: `string`; `token_introspection_endpoint`: `string`; `userinfo_endpoint`: `string`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/openid/types.ts:48](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/openid/types.ts#L48) | *** @@ -79,9 +72,9 @@ Defined in: [recipe/openid/types.ts:84](https://github.com/supertokens/supertoke | Parameter | Type | | ------ | ------ | -| `input` | \{ `payload?`: `any`; `userContext`: [`UserContext`](types.mdx#usercontext); `useStaticSigningKey?`: `boolean`; `validitySeconds?`: `number`; \} | +| `input` | \{ `payload?`: `any`; `userContext`: [`UserContext`](types#usercontext); `useStaticSigningKey?`: `boolean`; `validitySeconds?`: `number`; \} | | `input.payload?` | `any` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.useStaticSigningKey?` | `boolean` | | `input.validitySeconds?` | `number` | @@ -121,8 +114,8 @@ Defined in: [recipe/openid/types.ts:70](https://github.com/supertokens/supertoke | Parameter | Type | | ------ | ------ | -| `input` | \{ `userContext`: [`UserContext`](types.mdx#usercontext); \} | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input` | \{ `userContext`: [`UserContext`](types#usercontext); \} | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-openid.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-openid.mdx index 751c03a2fd..0f7c6a5777 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-openid.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-openid.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/openid -page_title: OpenID -sidebar_position: 13 description: References documentation for the supertokens-node/recipe/openid package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 13 --- -# OpenID - - ## Classes ### default @@ -34,7 +27,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `OpenIdRecipe.init` | [recipe/openid/index.ts:5](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/openid/index.ts#L5) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `OpenIdRecipe.init` | [recipe/openid/index.ts:5](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/openid/index.ts#L5) | #### Methods @@ -142,8 +135,8 @@ Defined in: [recipe/openid/index.ts:14](https://github.com/supertokens/supertoke | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-openid-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-openid-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless-types.mdx index 6aa78ff26d..bd2a53ac48 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/passwordless/types -page_title: Passwordless Types -sidebar_position: 3 description: References documentation for the supertokens-node/recipe/passwordless/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 3 --- -# Passwordless Types - - ## Type Aliases ### APIInterface @@ -26,11 +19,11 @@ Defined in: [recipe/passwordless/types.ts:335](https://github.com/supertokens/su | Property | Type | Defined in | | ------ | ------ | ------ | -| `consumeCodePOST?` | (`input`) => `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; `maximumCodeInputAttempts`: `number`; `status`: `"INCORRECT_USER_INPUT_CODE_ERROR"` \| `"EXPIRED_USER_INPUT_CODE_ERROR"`; \} \| \{ `status`: `"RESTART_FLOW_ERROR"`; \} \| \{ `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/passwordless/types.ts:368](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L368) | -| `createCodePOST?` | (`input`) => `Promise`\< \| \{ `deviceId`: `string`; `flowType`: `"USER_INPUT_CODE"` \| `"MAGIC_LINK"` \| `"USER_INPUT_CODE_AND_MAGIC_LINK"`; `preAuthSessionId`: `string`; `status`: `"OK"`; \} \| \{ `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/passwordless/types.ts:336](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L336) | -| `emailExistsGET?` | (`input`) => `Promise`\< \| \{ `exists`: `boolean`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/passwordless/types.ts:406](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L406) | -| `phoneNumberExistsGET?` | (`input`) => `Promise`\< \| \{ `exists`: `boolean`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/passwordless/types.ts:419](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L419) | -| `resendCodePOST?` | (`input`) => `Promise`\< \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| \{ `status`: `"RESTART_FLOW_ERROR"` \| `"OK"`; \}\> | [recipe/passwordless/types.ts:358](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L358) | +| `consumeCodePOST?` | (`input`) => `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; `maximumCodeInputAttempts`: `number`; `status`: `"INCORRECT_USER_INPUT_CODE_ERROR"` \| `"EXPIRED_USER_INPUT_CODE_ERROR"`; \} \| \{ `status`: `"RESTART_FLOW_ERROR"`; \} \| \{ `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/passwordless/types.ts:368](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L368) | +| `createCodePOST?` | (`input`) => `Promise`\< \| \{ `deviceId`: `string`; `flowType`: `"USER_INPUT_CODE"` \| `"MAGIC_LINK"` \| `"USER_INPUT_CODE_AND_MAGIC_LINK"`; `preAuthSessionId`: `string`; `status`: `"OK"`; \} \| \{ `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/passwordless/types.ts:336](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L336) | +| `emailExistsGET?` | (`input`) => `Promise`\< \| \{ `exists`: `boolean`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/passwordless/types.ts:406](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L406) | +| `phoneNumberExistsGET?` | (`input`) => `Promise`\< \| \{ `exists`: `boolean`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/passwordless/types.ts:419](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L419) | +| `resendCodePOST?` | (`input`) => `Promise`\< \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `status`: `"RESTART_FLOW_ERROR"` \| `"OK"`; \}\> | [recipe/passwordless/types.ts:358](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L358) | *** @@ -46,7 +39,7 @@ Defined in: [recipe/passwordless/types.ts:323](https://github.com/supertokens/su | Property | Type | Defined in | | ------ | ------ | ------ | -| `appInfo` | [`NormalisedAppinfo`](types.mdx#normalisedappinfo) | [recipe/passwordless/types.ts:325](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L325) | +| `appInfo` | [`NormalisedAppinfo`](types#normalisedappinfo) | [recipe/passwordless/types.ts:325](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L325) | | `config` | [`TypeNormalisedInput`](#typenormalisedinput) | [recipe/passwordless/types.ts:326](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L326) | | `emailDelivery` | `EmailDeliveryIngredient`\<[`TypePasswordlessEmailDeliveryInput`](#typepasswordlessemaildeliveryinput)\> | [recipe/passwordless/types.ts:331](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L331) | | `isInServerlessEnv` | `boolean` | [recipe/passwordless/types.ts:328](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L328) | @@ -91,7 +84,7 @@ Defined in: [recipe/passwordless/types.ts:110](https://github.com/supertokens/su | Property | Type | Defined in | | ------ | ------ | ------ | | `checkCode` | (`input`) => `Promise`\< \| \{ `consumedDevice`: \{ `email?`: `string`; `failedCodeInputAttemptCount`: `number`; `phoneNumber?`: `string`; `preAuthSessionId`: `string`; \}; `status`: `"OK"`; \} \| \{ `failedCodeInputAttemptCount`: `number`; `maximumCodeInputAttempts`: `number`; `status`: `"INCORRECT_USER_INPUT_CODE_ERROR"` \| `"EXPIRED_USER_INPUT_CODE_ERROR"`; \} \| \{ `status`: `"RESTART_FLOW_ERROR"`; \}\> | [recipe/passwordless/types.ts:203](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L203) | -| `consumeCode` | (`input`) => `Promise`\< \| \{ `consumedDevice`: \{ `email?`: `string`; `failedCodeInputAttemptCount`: `number`; `phoneNumber?`: `string`; `preAuthSessionId`: `string`; \}; `createdNewRecipeUser`: `boolean`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; `maximumCodeInputAttempts`: `number`; `status`: `"INCORRECT_USER_INPUT_CODE_ERROR"` \| `"EXPIRED_USER_INPUT_CODE_ERROR"`; \} \| \{ `status`: `"RESTART_FLOW_ERROR"`; \} \| \{ `reason`: \| `"EMAIL_VERIFICATION_REQUIRED"` \| `"RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"` \| `"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"` \| `"SESSION_USER_ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; `status`: `"LINKING_TO_SESSION_USER_FAILED"`; \}\> | [recipe/passwordless/types.ts:155](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L155) | +| `consumeCode` | (`input`) => `Promise`\< \| \{ `consumedDevice`: \{ `email?`: `string`; `failedCodeInputAttemptCount`: `number`; `phoneNumber?`: `string`; `preAuthSessionId`: `string`; \}; `createdNewRecipeUser`: `boolean`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; `maximumCodeInputAttempts`: `number`; `status`: `"INCORRECT_USER_INPUT_CODE_ERROR"` \| `"EXPIRED_USER_INPUT_CODE_ERROR"`; \} \| \{ `status`: `"RESTART_FLOW_ERROR"`; \} \| \{ `reason`: \| `"EMAIL_VERIFICATION_REQUIRED"` \| `"RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"` \| `"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"` \| `"SESSION_USER_ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"`; `status`: `"LINKING_TO_SESSION_USER_FAILED"`; \}\> | [recipe/passwordless/types.ts:155](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L155) | | `createCode` | (`input`) => `Promise`\<\{ `codeId`: `string`; `codeLifetime`: `number`; `deviceId`: `string`; `linkCode`: `string`; `preAuthSessionId`: `string`; `status`: `"OK"`; `timeCreated`: `number`; `userInputCode`: `string`; \}\> | [recipe/passwordless/types.ts:111](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L111) | | `createNewCodeForDevice` | (`input`) => `Promise`\< \| \{ `codeId`: `string`; `codeLifetime`: `number`; `deviceId`: `string`; `linkCode`: `string`; `preAuthSessionId`: `string`; `status`: `"OK"`; `timeCreated`: `number`; `userInputCode`: `string`; \} \| \{ `status`: `"RESTART_FLOW_ERROR"` \| `"USER_INPUT_CODE_ALREADY_USED_ERROR"`; \}\> | [recipe/passwordless/types.ts:137](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L137) | | `listCodesByDeviceId` | (`input`) => `Promise`\<[`DeviceType`](#devicetype) \| `undefined`\> | [recipe/passwordless/types.ts:295](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/types.ts#L295) | diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless.mdx index e6fb85532e..66e3f29cb7 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/passwordless -page_title: Passwordless -sidebar_position: 3 description: References documentation for the supertokens-node/recipe/passwordless package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 3 --- -# Passwordless - - ## Classes ### default @@ -35,7 +28,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | | `Error` | `static` | *typeof* `default` | `SuperTokensError` | [recipe/passwordless/index.ts:34](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/index.ts#L34) | -| `init` | `static` | (`config`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/passwordless/index.ts:32](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/index.ts#L32) | +| `init` | `static` | (`config`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/passwordless/index.ts:32](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/passwordless/index.ts#L32) | #### Methods @@ -149,9 +142,9 @@ Defined in: [recipe/passwordless/index.ts:77](https://github.com/supertokens/sup `preAuthSessionId`: `string`; \}; `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; @@ -219,9 +212,9 @@ Defined in: [recipe/passwordless/index.ts:114](https://github.com/supertokens/su `preAuthSessionId`: `string`; \}; `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; @@ -360,7 +353,7 @@ Defined in: [recipe/passwordless/index.ts:313](https://github.com/supertokens/su ###### Returns -`Promise`\<[`DeviceType`](recipe-passwordless-types.mdx#devicetype)\> +`Promise`\<[`DeviceType`](recipe-passwordless-types#devicetype)\> ##### listCodesByEmail() @@ -381,7 +374,7 @@ Defined in: [recipe/passwordless/index.ts:299](https://github.com/supertokens/su ###### Returns -`Promise`\<[`DeviceType`](recipe-passwordless-types.mdx#devicetype)[]\> +`Promise`\<[`DeviceType`](recipe-passwordless-types#devicetype)[]\> ##### listCodesByPhoneNumber() @@ -402,7 +395,7 @@ Defined in: [recipe/passwordless/index.ts:306](https://github.com/supertokens/su ###### Returns -`Promise`\<[`DeviceType`](recipe-passwordless-types.mdx#devicetype)[]\> +`Promise`\<[`DeviceType`](recipe-passwordless-types#devicetype)[]\> ##### listCodesByPreAuthSessionId() @@ -423,7 +416,7 @@ Defined in: [recipe/passwordless/index.ts:320](https://github.com/supertokens/su ###### Returns -`Promise`\<[`DeviceType`](recipe-passwordless-types.mdx#devicetype)\> +`Promise`\<[`DeviceType`](recipe-passwordless-types#devicetype)\> ##### revokeAllCodes() @@ -481,7 +474,7 @@ Defined in: [recipe/passwordless/index.ts:373](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | [`TypePasswordlessEmailDeliveryInput`](recipe-passwordless-types.mdx#typepasswordlessemaildeliveryinput) & `object` | +| `input` | [`TypePasswordlessEmailDeliveryInput`](recipe-passwordless-types#typepasswordlessemaildeliveryinput) & `object` | ###### Returns @@ -499,7 +492,7 @@ Defined in: [recipe/passwordless/index.ts:380](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | [`TypePasswordlessSmsDeliveryInput`](recipe-passwordless-types.mdx#typepasswordlesssmsdeliveryinput) & `object` | +| `input` | [`TypePasswordlessSmsDeliveryInput`](recipe-passwordless-types#typepasswordlesssmsdeliveryinput) & `object` | ###### Returns @@ -528,9 +521,9 @@ Defined in: [recipe/passwordless/index.ts:352](https://github.com/supertokens/su `Promise`\<\{ `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `string`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \}\> ##### updateUser() @@ -556,10 +549,10 @@ Defined in: [recipe/passwordless/index.ts:257](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `email?`: `string`; `phoneNumber?`: `string`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); `userContext?`: `Record`\<`string`, `any`\>; \} | +| `input` | \{ `email?`: `string`; `phoneNumber?`: `string`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `userContext?`: `Record`\<`string`, `any`\>; \} | | `input.email?` | `string` | | `input.phoneNumber?` | `string` | -| `input.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `input.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `input.userContext?` | `Record`\<`string`, `any`\> | ###### Returns @@ -745,9 +738,9 @@ Defined in: [recipe/passwordless/index.ts:394](https://github.com/supertokens/su `preAuthSessionId`: `string`; \}; `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; @@ -813,9 +806,9 @@ Defined in: [recipe/passwordless/index.ts:394](https://github.com/supertokens/su `preAuthSessionId`: `string`; \}; `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; @@ -965,11 +958,11 @@ Defined in: [recipe/passwordless/index.ts:388](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `config` | [`TypeInput`](recipe-passwordless-types.mdx#typeinput) | +| `config` | [`TypeInput`](recipe-passwordless-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -992,7 +985,7 @@ Defined in: [recipe/passwordless/index.ts:396](https://github.com/supertokens/su #### Returns -`Promise`\<[`DeviceType`](recipe-passwordless-types.mdx#devicetype)\> +`Promise`\<[`DeviceType`](recipe-passwordless-types#devicetype)\> *** @@ -1015,7 +1008,7 @@ Defined in: [recipe/passwordless/index.ts:398](https://github.com/supertokens/su #### Returns -`Promise`\<[`DeviceType`](recipe-passwordless-types.mdx#devicetype)[]\> +`Promise`\<[`DeviceType`](recipe-passwordless-types#devicetype)[]\> *** @@ -1038,7 +1031,7 @@ Defined in: [recipe/passwordless/index.ts:400](https://github.com/supertokens/su #### Returns -`Promise`\<[`DeviceType`](recipe-passwordless-types.mdx#devicetype)[]\> +`Promise`\<[`DeviceType`](recipe-passwordless-types#devicetype)[]\> *** @@ -1061,7 +1054,7 @@ Defined in: [recipe/passwordless/index.ts:402](https://github.com/supertokens/su #### Returns -`Promise`\<[`DeviceType`](recipe-passwordless-types.mdx#devicetype)\> +`Promise`\<[`DeviceType`](recipe-passwordless-types#devicetype)\> *** @@ -1125,7 +1118,7 @@ Defined in: [recipe/passwordless/index.ts:420](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | [`TypePasswordlessEmailDeliveryInput`](recipe-passwordless-types.mdx#typepasswordlessemaildeliveryinput) & `object` | +| `input` | [`TypePasswordlessEmailDeliveryInput`](recipe-passwordless-types#typepasswordlessemaildeliveryinput) & `object` | #### Returns @@ -1145,7 +1138,7 @@ Defined in: [recipe/passwordless/index.ts:422](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | [`TypePasswordlessSmsDeliveryInput`](recipe-passwordless-types.mdx#typepasswordlesssmsdeliveryinput) & `object` | +| `input` | [`TypePasswordlessSmsDeliveryInput`](recipe-passwordless-types#typepasswordlesssmsdeliveryinput) & `object` | #### Returns @@ -1176,9 +1169,9 @@ Defined in: [recipe/passwordless/index.ts:414](https://github.com/supertokens/su `Promise`\<\{ `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `string`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \}\> *** @@ -1206,10 +1199,10 @@ Defined in: [recipe/passwordless/index.ts:406](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `email?`: `string`; `phoneNumber?`: `string`; `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); `userContext?`: `Record`\<`string`, `any`\>; \} | +| `input` | \{ `email?`: `string`; `phoneNumber?`: `string`; `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `userContext?`: `Record`\<`string`, `any`\>; \} | | `input.email?` | `string` | | `input.phoneNumber?` | `string` | -| `input.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) | +| `input.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) | | `input.userContext?` | `Record`\<`string`, `any`\> | #### Returns @@ -1231,16 +1224,16 @@ Defined in: [recipe/passwordless/index.ts:406](https://github.com/supertokens/su ### APIInterface -Re-exports [APIInterface](recipe-passwordless-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-passwordless-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-passwordless-types.mdx#apioptions) +Re-exports [APIOptions](recipe-passwordless-types#apioptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-passwordless-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-passwordless-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty-types.mdx index 59d9a218db..4476fab6f7 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/thirdparty/types -page_title: ThirdParty Types -sidebar_position: 4 description: References documentation for the supertokens-node/recipe/thirdparty/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 4 --- -# ThirdParty Types - - ## Type Aliases ### APIInterface @@ -27,8 +20,8 @@ Defined in: [recipe/thirdparty/types.ts:253](https://github.com/supertokens/supe | Property | Type | Defined in | | ------ | ------ | ------ | | `appleRedirectHandlerPOST` | `undefined` \| (`input`) => `Promise`\<`void`\> | [recipe/thirdparty/types.ts:313](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/types.ts#L313) | -| `authorisationUrlGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `pkceCodeVerifier?`: `string`; `status`: `"OK"`; `urlWithQueryParams`: `string`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/thirdparty/types.ts:254](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/types.ts#L254) | -| `signInUpPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; `oAuthTokens`: \{ \[`key`: `string`\]: `any`; \}; `rawUserInfoFromProvider`: \{ `fromIdTokenPayload?`: \{ \[`key`: `string`\]: `any`; \}; `fromUserInfoAPI?`: \{ \[`key`: `string`\]: `any`; \}; \}; `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `status`: `"NO_EMAIL_GIVEN_BY_PROVIDER"`; \} \| \{ `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/thirdparty/types.ts:271](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/types.ts#L271) | +| `authorisationUrlGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `pkceCodeVerifier?`: `string`; `status`: `"OK"`; `urlWithQueryParams`: `string`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/thirdparty/types.ts:254](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/types.ts#L254) | +| `signInUpPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; `oAuthTokens`: \{ \[`key`: `string`\]: `any`; \}; `rawUserInfoFromProvider`: \{ `fromIdTokenPayload?`: \{ \[`key`: `string`\]: `any`; \}; `fromUserInfoAPI?`: \{ \[`key`: `string`\]: `any`; \}; \}; `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `status`: `"NO_EMAIL_GIVEN_BY_PROVIDER"`; \} \| \{ `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/thirdparty/types.ts:271](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/types.ts#L271) | *** @@ -44,7 +37,7 @@ Defined in: [recipe/thirdparty/types.ts:242](https://github.com/supertokens/supe | Property | Type | Defined in | | ------ | ------ | ------ | -| `appInfo` | [`NormalisedAppinfo`](types.mdx#normalisedappinfo) | [recipe/thirdparty/types.ts:250](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/types.ts#L250) | +| `appInfo` | [`NormalisedAppinfo`](types#normalisedappinfo) | [recipe/thirdparty/types.ts:250](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/types.ts#L250) | | `config` | [`TypeNormalisedInput`](#typenormalisedinput) | [recipe/thirdparty/types.ts:244](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/types.ts#L244) | | `isInServerlessEnv` | `boolean` | [recipe/thirdparty/types.ts:246](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/types.ts#L246) | | `providers` | [`ProviderInput`](#providerinput)[] | [recipe/thirdparty/types.ts:247](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/types.ts#L247) | @@ -142,11 +135,11 @@ Defined in: [recipe/thirdparty/types.ts:160](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `input` | \{ `clientType?`: `string`; `tenantId`: `string`; `thirdPartyId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `clientType?`: `string`; `tenantId`: `string`; `thirdPartyId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.clientType?` | `string` | | `input.tenantId` | `string` | | `input.thirdPartyId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -185,7 +178,7 @@ Defined in: [recipe/thirdparty/types.ts:207](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `isVerified`: `boolean`; `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `thirdPartyId`: `string`; `thirdPartyUserId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `isVerified`: `boolean`; `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `thirdPartyId`: `string`; `thirdPartyUserId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | | `input.isVerified` | `boolean` | | `input.session` | `SessionContainerInterface` \| `undefined` | @@ -193,16 +186,16 @@ Defined in: [recipe/thirdparty/types.ts:207](https://github.com/supertokens/supe | `input.tenantId` | `string` | | `input.thirdPartyId` | `string` | | `input.thirdPartyUserId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `reason`: `string`; @@ -260,7 +253,7 @@ Defined in: [recipe/thirdparty/types.ts:167](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `isVerified`: `boolean`; `oAuthTokens`: \{ \[`key`: `string`\]: `any`; \}; `rawUserInfoFromProvider`: \{ `fromIdTokenPayload?`: \{ \[`key`: `string`\]: `any`; \}; `fromUserInfoAPI?`: \{ \[`key`: `string`\]: `any`; \}; \}; `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `thirdPartyId`: `string`; `thirdPartyUserId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `isVerified`: `boolean`; `oAuthTokens`: \{ \[`key`: `string`\]: `any`; \}; `rawUserInfoFromProvider`: \{ `fromIdTokenPayload?`: \{ \[`key`: `string`\]: `any`; \}; `fromUserInfoAPI?`: \{ \[`key`: `string`\]: `any`; \}; \}; `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `thirdPartyId`: `string`; `thirdPartyUserId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | | `input.isVerified` | `boolean` | | `input.oAuthTokens` | \{ \[`key`: `string`\]: `any`; \} | @@ -272,7 +265,7 @@ Defined in: [recipe/thirdparty/types.ts:167](https://github.com/supertokens/supe | `input.tenantId` | `string` | | `input.thirdPartyId` | `string` | | `input.thirdPartyUserId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -290,9 +283,9 @@ Defined in: [recipe/thirdparty/types.ts:167](https://github.com/supertokens/supe \[`key`: `string`\]: `any`; \}; \}; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `reason`: `string`; diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty.mdx index 3658f31a3e..5337a1707e 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/thirdparty -page_title: ThirdParty -sidebar_position: 4 description: References documentation for the supertokens-node/recipe/thirdparty package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 4 --- -# ThirdParty - - ## Classes ### default @@ -35,7 +28,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | | `Error` | `static` | *typeof* `default` | `SuperTokensError` | [recipe/thirdparty/index.ts:28](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/index.ts#L28) | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/thirdparty/index.ts:26](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/index.ts#L26) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/thirdparty/index.ts:26](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/thirdparty/index.ts#L26) | #### Methods @@ -62,7 +55,7 @@ Defined in: [recipe/thirdparty/index.ts:30](https://github.com/supertokens/super ###### Returns -`Promise`\<[`TypeProvider`](recipe-thirdparty-types.mdx#typeprovider)\> +`Promise`\<[`TypeProvider`](recipe-thirdparty-types#typeprovider)\> ##### manuallyCreateOrUpdateUser() @@ -112,9 +105,9 @@ Defined in: [recipe/thirdparty/index.ts:44](https://github.com/supertokens/super `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `reason`: `string`; @@ -178,9 +171,9 @@ Defined in: [recipe/thirdparty/index.ts:68](https://github.com/supertokens/super `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `reason`: `string`; @@ -229,7 +222,7 @@ Defined in: [recipe/thirdparty/index.ts:149](https://github.com/supertokens/supe #### Returns -`Promise`\<[`TypeProvider`](recipe-thirdparty-types.mdx#typeprovider)\> +`Promise`\<[`TypeProvider`](recipe-thirdparty-types#typeprovider)\> *** @@ -245,11 +238,11 @@ Defined in: [recipe/thirdparty/index.ts:145](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-thirdparty-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-thirdparty-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -343,9 +336,9 @@ Defined in: [recipe/thirdparty/index.ts:151](https://github.com/supertokens/supe `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `reason`: `string`; @@ -407,9 +400,9 @@ Defined in: [recipe/thirdparty/index.ts:151](https://github.com/supertokens/supe `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `reason`: `string`; @@ -431,22 +424,22 @@ Defined in: [recipe/thirdparty/index.ts:151](https://github.com/supertokens/supe ### APIInterface -Re-exports [APIInterface](recipe-thirdparty-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-thirdparty-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-thirdparty-types.mdx#apioptions) +Re-exports [APIOptions](recipe-thirdparty-types#apioptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-thirdparty-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-thirdparty-types#recipeinterface) *** ### TypeProvider -Re-exports [TypeProvider](recipe-thirdparty-types.mdx#typeprovider) +Re-exports [TypeProvider](recipe-thirdparty-types#typeprovider) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-totp-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-totp-types.mdx index 9f8b733cc6..602a36ddbe 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-totp-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-totp-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/totp/types -page_title: TOTP Types -sidebar_position: 16 description: References documentation for the supertokens-node/recipe/totp/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 16 --- -# TOTP Types - - ## Type Aliases ### APIInterface @@ -26,11 +19,11 @@ Defined in: [recipe/totp/types.ts:149](https://github.com/supertokens/supertoken | Property | Type | Defined in | | ------ | ------ | ------ | -| `createDevicePOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `deviceName`: `string`; `qrCodeString`: `string`; `secret`: `string`; `status`: `"OK"`; \} \| \{ `status`: `"DEVICE_ALREADY_EXISTS_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/totp/types.ts:150](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/types.ts#L150) | -| `listDevicesGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `devices`: `object`[]; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/totp/types.ts:170](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/types.ts#L170) | -| `removeDevicePOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `didDeviceExist`: `boolean`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/totp/types.ts:185](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/types.ts#L185) | -| `verifyDevicePOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; `wasAlreadyVerified`: `boolean`; \} \| \{ `status`: `"UNKNOWN_DEVICE_ERROR"`; \} \| \{ `currentNumberOfFailedAttempts`: `number`; `maxNumberOfFailedAttempts`: `number`; `status`: `"INVALID_TOTP_ERROR"`; \} \| \{ `retryAfterMs`: `number`; `status`: `"LIMIT_REACHED_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/totp/types.ts:200](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/types.ts#L200) | -| `verifyTOTPPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"` \| `"UNKNOWN_USER_ID_ERROR"`; \} \| \{ `currentNumberOfFailedAttempts`: `number`; `maxNumberOfFailedAttempts`: `number`; `status`: `"INVALID_TOTP_ERROR"`; \} \| \{ `retryAfterMs`: `number`; `status`: `"LIMIT_REACHED_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/totp/types.ts:228](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/types.ts#L228) | +| `createDevicePOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `deviceName`: `string`; `qrCodeString`: `string`; `secret`: `string`; `status`: `"OK"`; \} \| \{ `status`: `"DEVICE_ALREADY_EXISTS_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/totp/types.ts:150](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/types.ts#L150) | +| `listDevicesGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `devices`: `object`[]; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/totp/types.ts:170](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/types.ts#L170) | +| `removeDevicePOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `didDeviceExist`: `boolean`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/totp/types.ts:185](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/types.ts#L185) | +| `verifyDevicePOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; `wasAlreadyVerified`: `boolean`; \} \| \{ `status`: `"UNKNOWN_DEVICE_ERROR"`; \} \| \{ `currentNumberOfFailedAttempts`: `number`; `maxNumberOfFailedAttempts`: `number`; `status`: `"INVALID_TOTP_ERROR"`; \} \| \{ `retryAfterMs`: `number`; `status`: `"LIMIT_REACHED_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/totp/types.ts:200](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/types.ts#L200) | +| `verifyTOTPPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"` \| `"UNKNOWN_USER_ID_ERROR"`; \} \| \{ `currentNumberOfFailedAttempts`: `number`; `maxNumberOfFailedAttempts`: `number`; `status`: `"INVALID_TOTP_ERROR"`; \} \| \{ `retryAfterMs`: `number`; `status`: `"LIMIT_REACHED_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/totp/types.ts:228](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/types.ts#L228) | *** diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-totp.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-totp.mdx index faea961bc5..7949ad44d5 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-totp.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-totp.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/totp -page_title: TOTP -sidebar_position: 16 description: References documentation for the supertokens-node/recipe/totp package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 16 --- -# TOTP - - ## Classes ### default @@ -34,7 +27,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/totp/index.ts:21](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/index.ts#L21) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/totp/index.ts:21](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/totp/index.ts#L21) | #### Methods @@ -345,11 +338,11 @@ Defined in: [recipe/totp/index.ts:164](https://github.com/supertokens/supertoken | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-totp-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-totp-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -540,16 +533,16 @@ Defined in: [recipe/totp/index.ts:171](https://github.com/supertokens/supertoken ### APIInterface -Re-exports [APIInterface](recipe-totp-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-totp-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-totp-types.mdx#apioptions) +Re-exports [APIOptions](recipe-totp-types#apioptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-totp-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-totp-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata-types.mdx index 845f814a2f..fd385c11b2 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/usermetadata/types -page_title: UserMetadata Types -sidebar_position: 15 description: References documentation for the supertokens-node/recipe/usermetadata/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 15 --- -# UserMetadata Types - - ## Type Aliases ### APIInterface @@ -38,7 +31,7 @@ Defined in: [recipe/usermetadata/types.ts:41](https://github.com/supertokens/sup | ------ | ------ | ------ | ------ | | `clearUserMetadata` | (`input`) => `Promise`\<\{ `status`: `"OK"`; \}\> | - | [recipe/usermetadata/types.ts:60](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/usermetadata/types.ts#L60) | | `getUserMetadata` | (`input`) => `Promise`\<\{ `metadata`: `any`; `status`: `"OK"`; \}\> | - | [recipe/usermetadata/types.ts:42](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/usermetadata/types.ts#L42) | -| `updateUserMetadata` | (`input`) => `Promise`\<\{ `metadata`: [`JSONObject`](types.mdx#jsonobject); `status`: `"OK"`; \}\> | Updates the metadata object of the user by doing a shallow merge of the stored and the update JSONs and removing properties set to null on the root level of the update object. e.g.: - stored: `{ "preferences": { "theme":"dark" }, "notifications": { "email": true }, "todos": ["example"] }` - update: `{ "notifications": { "sms": true }, "todos": null }` - result: `{ "preferences": { "theme":"dark" }, "notifications": { "sms": true } }` | [recipe/usermetadata/types.ts:55](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/usermetadata/types.ts#L55) | +| `updateUserMetadata` | (`input`) => `Promise`\<\{ `metadata`: [`JSONObject`](types#jsonobject); `status`: `"OK"`; \}\> | Updates the metadata object of the user by doing a shallow merge of the stored and the update JSONs and removing properties set to null on the root level of the update object. e.g.: - stored: `{ "preferences": { "theme":"dark" }, "notifications": { "email": true }, "todos": ["example"] }` - update: `{ "notifications": { "sms": true }, "todos": null }` - result: `{ "preferences": { "theme":"dark" }, "notifications": { "sms": true } }` | [recipe/usermetadata/types.ts:55](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/usermetadata/types.ts#L55) | *** diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata.mdx index bbb4781574..04db3c5976 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/usermetadata -page_title: UserMetadata -sidebar_position: 15 description: References documentation for the supertokens-node/recipe/usermetadata package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 15 --- -# UserMetadata - - ## Classes ### default @@ -34,7 +27,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/usermetadata/index.ts:22](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/usermetadata/index.ts#L22) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/usermetadata/index.ts:22](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/usermetadata/index.ts#L22) | #### Methods @@ -105,13 +98,13 @@ Defined in: [recipe/usermetadata/index.ts:31](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | | `userId` | `string` | -| `metadataUpdate` | [`JSONObject`](types.mdx#jsonobject) | +| `metadataUpdate` | [`JSONObject`](types#jsonobject) | | `userContext?` | `Record`\<`string`, `any`\> | ###### Returns `Promise`\<\{ - `metadata`: [`JSONObject`](types.mdx#jsonobject); + `metadata`: [`JSONObject`](types#jsonobject); `status`: `"OK"`; \}\> @@ -181,11 +174,11 @@ Defined in: [recipe/usermetadata/index.ts:47](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-usermetadata-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-usermetadata-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -205,13 +198,13 @@ Defined in: [recipe/usermetadata/index.ts:49](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | | `userId` | `string` | -| `metadataUpdate` | [`JSONObject`](types.mdx#jsonobject) | +| `metadataUpdate` | [`JSONObject`](types#jsonobject) | | `userContext?` | `Record`\<`string`, `any`\> | #### Returns `Promise`\<\{ - `metadata`: [`JSONObject`](types.mdx#jsonobject); + `metadata`: [`JSONObject`](types#jsonobject); `status`: `"OK"`; \}\> @@ -219,10 +212,10 @@ Defined in: [recipe/usermetadata/index.ts:49](https://github.com/supertokens/sup ### JSONObject -Re-exports [JSONObject](types.mdx#jsonobject) +Re-exports [JSONObject](types#jsonobject) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-usermetadata-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-usermetadata-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-userroles-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-userroles-types.mdx index 05f20a40b3..d5667c35f7 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-userroles-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-userroles-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/userroles/types -page_title: UserRoles Types -sidebar_position: 14 description: References documentation for the supertokens-node/recipe/userroles/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 14 --- -# UserRoles Types - - ## Type Aliases ### APIInterface diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-userroles.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-userroles.mdx index 7485a282c8..7227b051b0 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-userroles.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-userroles.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/userroles -page_title: UserRoles -sidebar_position: 14 description: References documentation for the supertokens-node/recipe/userroles package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 14 --- -# UserRoles - - ## Classes ### default @@ -34,7 +27,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/userroles/index.ts:23](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/userroles/index.ts#L23) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/userroles/index.ts:23](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/userroles/index.ts#L23) | | `PermissionClaim` | `static` | `PermissionClaimClass` | `PermissionClaim` | [recipe/userroles/index.ts:24](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/userroles/index.ts#L24) | | `UserRoleClaim` | `static` | `UserRoleClaimClass` | `UserRoleClaim` | [recipe/userroles/index.ts:25](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/userroles/index.ts#L25) | @@ -605,11 +598,11 @@ Defined in: [recipe/userroles/index.ts:105](https://github.com/supertokens/super | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-userroles-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-userroles-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -698,4 +691,4 @@ Defined in: [recipe/userroles/userRoleClaim.ts:24](https://github.com/supertoken ### RecipeInterface -Re-exports [RecipeInterface](recipe-userroles-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-userroles-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn-types.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn-types.mdx index a98166f022..3148f40cbd 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn-types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/webauthn/types -page_title: WebAuthn Types -sidebar_position: 5 description: References documentation for the supertokens-node/recipe/webauthn/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 5 --- -# WebAuthn Types - - ## Type Aliases ### APIInterface @@ -26,16 +19,16 @@ Defined in: [recipe/webauthn/types.ts:477](https://github.com/supertokens/supert | Property | Type | Defined in | | ------ | ------ | ------ | -| `emailExistsGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `exists`: `boolean`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/webauthn/types.ts:655](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L655) | -| `generateRecoverAccountTokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| `GenerateRecoverAccountTokenPOSTErrorResponse`\> | [recipe/webauthn/types.ts:580](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L580) | -| `listCredentialsGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `credentials`: `object`[]; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [recipe/webauthn/types.ts:609](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L609) | -| `recoverAccountPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `email`: `string`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| `RecoverAccountPOSTErrorResponse`\> | [recipe/webauthn/types.ts:590](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L590) | -| `registerCredentialPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| `RegisterCredentialPOSTErrorResponse`\> | [recipe/webauthn/types.ts:623](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L623) | -| `registerOptionsPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `attestation`: `"none"` \| `"indirect"` \| `"direct"` \| `"enterprise"`; `authenticatorSelection`: \{ `requireResidentKey`: `boolean`; `residentKey`: [`ResidentKey`](#residentkey); `userVerification`: [`UserVerification`](#userverification); \}; `challenge`: `string`; `createdAt`: `number`; `excludeCredentials`: `object`[]; `expiresAt`: `number`; `pubKeyCredParams`: `object`[]; `rp`: \{ `id`: `string`; `name`: `string`; \}; `status`: `"OK"`; `timeout`: `number`; `user`: \{ `displayName`: `string`; `id`: `string`; `name`: `string`; \}; `webauthnGeneratedOptionsId`: `string`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| `RegisterOptionsPOSTErrorResponse`\> | [recipe/webauthn/types.ts:478](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L478) | -| `removeCredentialPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| `RemoveCredentialPOSTErrorResponse`\> | [recipe/webauthn/types.ts:640](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L640) | -| `signInOptionsPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `challenge`: `string`; `createdAt`: `number`; `expiresAt`: `number`; `rpId`: `string`; `status`: `"OK"`; `timeout`: `number`; `userVerification`: [`UserVerification`](#userverification); `webauthnGeneratedOptionsId`: `string`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| `SignInOptionsPOSTErrorResponse`\> | [recipe/webauthn/types.ts:523](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L523) | -| `signInPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| `SignInPOSTErrorResponse`\> | [recipe/webauthn/types.ts:560](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L560) | -| `signUpPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| `SignUpPOSTErrorResponse`\> | [recipe/webauthn/types.ts:540](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L540) | +| `emailExistsGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `exists`: `boolean`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/webauthn/types.ts:655](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L655) | +| `generateRecoverAccountTokenPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| `GenerateRecoverAccountTokenPOSTErrorResponse`\> | [recipe/webauthn/types.ts:580](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L580) | +| `listCredentialsGET` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `credentials`: `object`[]; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [recipe/webauthn/types.ts:609](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L609) | +| `recoverAccountPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `email`: `string`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| `RecoverAccountPOSTErrorResponse`\> | [recipe/webauthn/types.ts:590](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L590) | +| `registerCredentialPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| `RegisterCredentialPOSTErrorResponse`\> | [recipe/webauthn/types.ts:623](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L623) | +| `registerOptionsPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `attestation`: `"none"` \| `"indirect"` \| `"direct"` \| `"enterprise"`; `authenticatorSelection`: \{ `requireResidentKey`: `boolean`; `residentKey`: [`ResidentKey`](#residentkey); `userVerification`: [`UserVerification`](#userverification); \}; `challenge`: `string`; `createdAt`: `number`; `excludeCredentials`: `object`[]; `expiresAt`: `number`; `pubKeyCredParams`: `object`[]; `rp`: \{ `id`: `string`; `name`: `string`; \}; `status`: `"OK"`; `timeout`: `number`; `user`: \{ `displayName`: `string`; `id`: `string`; `name`: `string`; \}; `webauthnGeneratedOptionsId`: `string`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| `RegisterOptionsPOSTErrorResponse`\> | [recipe/webauthn/types.ts:478](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L478) | +| `removeCredentialPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| `RemoveCredentialPOSTErrorResponse`\> | [recipe/webauthn/types.ts:640](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L640) | +| `signInOptionsPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `challenge`: `string`; `createdAt`: `number`; `expiresAt`: `number`; `rpId`: `string`; `status`: `"OK"`; `timeout`: `number`; `userVerification`: [`UserVerification`](#userverification); `webauthnGeneratedOptionsId`: `string`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| `SignInOptionsPOSTErrorResponse`\> | [recipe/webauthn/types.ts:523](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L523) | +| `signInPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| `SignInPOSTErrorResponse`\> | [recipe/webauthn/types.ts:560](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L560) | +| `signUpPOST` | \| `undefined` \| (`input`) => `Promise`\< \| \{ `session`: `SessionContainerInterface`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| `SignUpPOSTErrorResponse`\> | [recipe/webauthn/types.ts:540](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L540) | *** @@ -51,7 +44,7 @@ Defined in: [recipe/webauthn/types.ts:420](https://github.com/supertokens/supert | Property | Type | Defined in | | ------ | ------ | ------ | -| `appInfo` | [`NormalisedAppinfo`](types.mdx#normalisedappinfo) | [recipe/webauthn/types.ts:422](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L422) | +| `appInfo` | [`NormalisedAppinfo`](types#normalisedappinfo) | [recipe/webauthn/types.ts:422](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L422) | | `config` | [`TypeNormalisedInput`](#typenormalisedinput) | [recipe/webauthn/types.ts:423](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L423) | | `emailDelivery` | `EmailDeliveryIngredient`\<[`TypeWebauthnEmailDeliveryInput`](#typewebauthnemaildeliveryinput)\> | [recipe/webauthn/types.ts:428](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L428) | | `isInServerlessEnv` | `boolean` | [recipe/webauthn/types.ts:425](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L425) | @@ -196,10 +189,10 @@ Defined in: [recipe/webauthn/types.ts:322](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `tenantId`: `string`; `token`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `tenantId`: `string`; `token`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.tenantId` | `string` | | `input.token` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -234,10 +227,10 @@ called during operations like creating a user during account recovery flow. | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`RegistrationPayload`](#registrationpayload); `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: [`RegistrationPayload`](#registrationpayload); `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | [`RegistrationPayload`](#registrationpayload) | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.webauthnGeneratedOptionsId` | `string` | ###### Returns @@ -245,9 +238,9 @@ called during operations like creating a user during account recovery flow. `Promise`\< \| `CreateNewRecipeUserErrorResponse` \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \}\> ##### generateRecoverAccountToken() @@ -271,10 +264,10 @@ need to know which email to use to create an webauthn account later on. | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `userId`: `string`; \} | +| `input` | \{ `email`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); `userId`: `string`; \} | | `input.email` | `string` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.userId` | `string` | ###### Returns @@ -306,9 +299,9 @@ Defined in: [recipe/webauthn/types.ts:358](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `recipeUserId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `webauthnCredentialId`: `string`; \} | +| `input` | \{ `recipeUserId`: `string`; `userContext`: [`UserContext`](types#usercontext); `webauthnCredentialId`: `string`; \} | | `input.recipeUserId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.webauthnCredentialId` | `string` | ###### Returns @@ -316,7 +309,7 @@ Defined in: [recipe/webauthn/types.ts:358](https://github.com/supertokens/supert `Promise`\< \| \{ `createdAt`: `number`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `relyingPartyId`: `string`; `status`: `"OK"`; `webauthnCredentialId`: `string`; @@ -350,9 +343,9 @@ Defined in: [recipe/webauthn/types.ts:385](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.webauthnGeneratedOptionsId` | `string` | ###### Returns @@ -392,18 +385,18 @@ Defined in: [recipe/webauthn/types.ts:343](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `tenantId`: `string`; `token`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `tenantId`: `string`; `token`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.tenantId` | `string` | | `input.token` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns `Promise`\< \| \{ - `recipeUserId?`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId?`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| `GetUserFromRecoverAccountTokenErrorResponse`\> @@ -422,9 +415,9 @@ Defined in: [recipe/webauthn/types.ts:369](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `recipeUserId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `recipeUserId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.recipeUserId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -449,10 +442,10 @@ Defined in: [recipe/webauthn/types.ts:331](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`RegistrationPayload`](#registrationpayload); `recipeUserId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: [`RegistrationPayload`](#registrationpayload); `recipeUserId`: `string`; `userContext`: [`UserContext`](types#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | [`RegistrationPayload`](#registrationpayload) | | `input.recipeUserId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.webauthnGeneratedOptionsId` | `string` | ###### Returns @@ -549,9 +542,9 @@ Defined in: [recipe/webauthn/types.ts:351](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `recipeUserId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `webauthnCredentialId`: `string`; \} | +| `input` | \{ `recipeUserId`: `string`; `userContext`: [`UserContext`](types#usercontext); `webauthnCredentialId`: `string`; \} | | `input.recipeUserId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.webauthnCredentialId` | `string` | ###### Returns @@ -578,9 +571,9 @@ Defined in: [recipe/webauthn/types.ts:379](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.webauthnGeneratedOptionsId` | `string` | ###### Returns @@ -609,21 +602,21 @@ Defined in: [recipe/webauthn/types.ts:274](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`AuthenticationPayload`](#authenticationpayload); `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: [`AuthenticationPayload`](#authenticationpayload); `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | [`AuthenticationPayload`](#authenticationpayload) | | `input.session` | `SessionContainerInterface` \| `undefined` | | `input.shouldTryLinkingWithSessionUser` | `boolean` \| `undefined` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.webauthnGeneratedOptionsId` | `string` | ###### Returns `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| `SignInErrorResponse`\> @@ -649,13 +642,13 @@ Defined in: [recipe/webauthn/types.ts:236](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `origin`: `string`; `relyingPartyId`: `string`; `relyingPartyName`: `string`; `tenantId`: `string`; `timeout`: `number` \| `undefined`; `userContext`: [`UserContext`](types.mdx#usercontext); `userPresence`: `boolean` \| `undefined`; `userVerification`: [`UserVerification`](#userverification) \| `undefined`; \} | +| `input` | \{ `origin`: `string`; `relyingPartyId`: `string`; `relyingPartyName`: `string`; `tenantId`: `string`; `timeout`: `number` \| `undefined`; `userContext`: [`UserContext`](types#usercontext); `userPresence`: `boolean` \| `undefined`; `userVerification`: [`UserVerification`](#userverification) \| `undefined`; \} | | `input.origin` | `string` | | `input.relyingPartyId` | `string` | | `input.relyingPartyName` | `string` | | `input.tenantId` | `string` | | `input.timeout` | `number` \| `undefined` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.userPresence` | `boolean` \| `undefined` | | `input.userVerification` | [`UserVerification`](#userverification) \| `undefined` | @@ -691,21 +684,21 @@ Defined in: [recipe/webauthn/types.ts:258](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`RegistrationPayload`](#registrationpayload); `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: [`RegistrationPayload`](#registrationpayload); `session`: `SessionContainerInterface` \| `undefined`; `shouldTryLinkingWithSessionUser`: `boolean` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | [`RegistrationPayload`](#registrationpayload) | | `input.session` | `SessionContainerInterface` \| `undefined` | | `input.shouldTryLinkingWithSessionUser` | `boolean` \| `undefined` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.webauthnGeneratedOptionsId` | `string` | ###### Returns `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| `SignUpErrorResponse`\> @@ -725,11 +718,11 @@ Defined in: [recipe/webauthn/types.ts:407](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `recipeUserId`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `email`: `string`; `recipeUserId`: `string`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.email` | `string` | | `input.recipeUserId` | `string` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | ###### Returns @@ -757,10 +750,10 @@ Defined in: [recipe/webauthn/types.ts:283](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`AuthenticationPayload`](#authenticationpayload); `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: [`AuthenticationPayload`](#authenticationpayload); `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | [`AuthenticationPayload`](#authenticationpayload) | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | | `input.webauthnGeneratedOptionsId` | `string` | ###### Returns @@ -768,9 +761,9 @@ Defined in: [recipe/webauthn/types.ts:283](https://github.com/supertokens/supert `Promise`\< \| `VerifyCredentialsErrorResponse` \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \}\> *** @@ -836,10 +829,10 @@ Defined in: [recipe/webauthn/types.ts:91](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input` | \{ `request`: `BaseRequest`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `request`: `BaseRequest`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.request` | `BaseRequest` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | #### Returns @@ -881,7 +874,7 @@ Defined in: [recipe/webauthn/types.ts:97](https://github.com/supertokens/superto | ------ | ------ | | `email` | `string` | | `tenantId` | `string` | -| `userContext` | [`UserContext`](types.mdx#usercontext) | +| `userContext` | [`UserContext`](types#usercontext) | #### Returns @@ -924,10 +917,10 @@ Defined in: [recipe/webauthn/types.ts:56](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input` | \{ `request`: `BaseRequest`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `request`: `BaseRequest`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.request` | `BaseRequest` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | #### Returns @@ -947,10 +940,10 @@ Defined in: [recipe/webauthn/types.ts:44](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input` | \{ `request`: `BaseRequest` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `request`: `BaseRequest` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.request` | `BaseRequest` \| `undefined` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | #### Returns @@ -970,10 +963,10 @@ Defined in: [recipe/webauthn/types.ts:50](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input` | \{ `request`: `BaseRequest` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types.mdx#usercontext); \} | +| `input` | \{ `request`: `BaseRequest` \| `undefined`; `tenantId`: `string`; `userContext`: [`UserContext`](types#usercontext); \} | | `input.request` | `BaseRequest` \| `undefined` | | `input.tenantId` | `string` | -| `input.userContext` | [`UserContext`](types.mdx#usercontext) | +| `input.userContext` | [`UserContext`](types#usercontext) | #### Returns @@ -995,7 +988,7 @@ Defined in: [recipe/webauthn/types.ts:62](https://github.com/supertokens/superto | ------ | ------ | | `email` | `string` | | `tenantId` | `string` | -| `userContext` | [`UserContext`](types.mdx#usercontext) | +| `userContext` | [`UserContext`](types#usercontext) | #### Returns @@ -1031,7 +1024,7 @@ Defined in: [recipe/webauthn/types.ts:666](https://github.com/supertokens/supert | `user` | `object` | [recipe/webauthn/types.ts:668](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L668) | | `user.email` | `string` | [recipe/webauthn/types.ts:671](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L671) | | `user.id` | `string` | [recipe/webauthn/types.ts:669](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L669) | -| `user.recipeUserId` | [`RecipeUserId`](index.mdx#recipeuserid-1) \| `undefined` | [recipe/webauthn/types.ts:670](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L670) | +| `user.recipeUserId` | [`RecipeUserId`](index#recipeuserid-1) \| `undefined` | [recipe/webauthn/types.ts:670](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/types.ts#L670) | *** diff --git a/docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn.mdx b/docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn.mdx index 211ddfc6ca..4072c5266b 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/recipe/webauthn -page_title: WebAuthn -sidebar_position: 5 description: References documentation for the supertokens-node/recipe/webauthn package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 5 --- -# WebAuthn - - ## Classes ### default @@ -35,7 +28,7 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | | `Error` | `static` | *typeof* `default` | `SuperTokensError` | [recipe/webauthn/index.ts:36](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/index.ts#L36) | -| `init` | `static` | (`config?`) => [`RecipeListFunction`](types.mdx#recipelistfunction) | `Recipe.init` | [recipe/webauthn/index.ts:34](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/index.ts#L34) | +| `init` | `static` | (`config?`) => [`RecipeListFunction`](types#recipelistfunction) | `Recipe.init` | [recipe/webauthn/index.ts:34](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/recipe/webauthn/index.ts#L34) | #### Methods @@ -176,7 +169,7 @@ Defined in: [recipe/webauthn/index.ts:322](https://github.com/supertokens/supert `Promise`\< \| \{ `createdAt`: `number`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `relyingPartyId`: `string`; `status`: `"OK"`; `webauthnCredentialId`: `string`; @@ -229,7 +222,7 @@ Defined in: [recipe/webauthn/index.ts:83](https://github.com/supertokens/superto `status`: `"OK"`; `timeout`: `number`; `userPresence`: `boolean`; - `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification); + `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification); `webauthnGeneratedOptionsId`: `string`; \} \| `GetGeneratedOptionsErrorResponse`\> @@ -261,9 +254,9 @@ Defined in: [recipe/webauthn/index.ts:289](https://github.com/supertokens/supert `Promise`\< \| \{ - `recipeUserId?`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId?`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| `GetUserFromRecoverAccountTokenErrorResponse`\> @@ -310,8 +303,8 @@ Defined in: [recipe/webauthn/index.ts:162](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `__namedParameters` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload); `tenantId?`: `string`; `token`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | -| `__namedParameters.credential` | [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload) | +| `__namedParameters` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types#registrationpayload); `tenantId?`: `string`; `token`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | +| `__namedParameters.credential` | [`RegistrationPayload`](recipe-webauthn-types#registrationpayload) | | `__namedParameters.tenantId?` | `string` | | `__namedParameters.token` | `string` | | `__namedParameters.userContext?` | `Record`\<`string`, `any`\> | @@ -342,8 +335,8 @@ Defined in: [recipe/webauthn/index.ts:198](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload); `recipeUserId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | -| `input.credential` | [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload) | +| `input` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types#registrationpayload); `recipeUserId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | +| `input.credential` | [`RegistrationPayload`](recipe-webauthn-types#registrationpayload) | | `input.recipeUserId` | `string` | | `input.userContext?` | `Record`\<`string`, `any`\> | | `input.webauthnGeneratedOptionsId` | `string` | @@ -400,11 +393,11 @@ Defined in: [recipe/webauthn/index.ts:38](https://github.com/supertokens/superto `Promise`\< \| \{ - `attestation`: [`Attestation`](recipe-webauthn-types.mdx#attestation); + `attestation`: [`Attestation`](recipe-webauthn-types#attestation); `authenticatorSelection`: \{ `requireResidentKey`: `boolean`; - `residentKey`: [`ResidentKey`](recipe-webauthn-types.mdx#residentkey); - `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification); + `residentKey`: [`ResidentKey`](recipe-webauthn-types#residentkey); + `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification); \}; `challenge`: `string`; `createdAt`: `number`; @@ -496,7 +489,7 @@ Defined in: [recipe/webauthn/index.ts:281](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | [`TypeWebauthnRecoverAccountEmailDeliveryInput`](recipe-webauthn-types.mdx#typewebauthnrecoveraccountemaildeliveryinput) & `object` | +| `input` | [`TypeWebauthnRecoverAccountEmailDeliveryInput`](recipe-webauthn-types#typewebauthnrecoveraccountemaildeliveryinput) & `object` | ###### Returns @@ -556,8 +549,8 @@ Defined in: [recipe/webauthn/index.ts:108](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`AuthenticationPayload`](recipe-webauthn-types.mdx#authenticationpayload); `session`: `SessionContainerInterface`; `shouldTryLinkingWithSessionUser`: `boolean`; `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | -| `input.credential` | [`AuthenticationPayload`](recipe-webauthn-types.mdx#authenticationpayload) | +| `input` | \{ `credential`: [`AuthenticationPayload`](recipe-webauthn-types#authenticationpayload); `session`: `SessionContainerInterface`; `shouldTryLinkingWithSessionUser`: `boolean`; `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | +| `input.credential` | [`AuthenticationPayload`](recipe-webauthn-types#authenticationpayload) | | `input.session` | `SessionContainerInterface` | | `input.shouldTryLinkingWithSessionUser` | `boolean` | | `input.tenantId` | `string` | @@ -568,9 +561,9 @@ Defined in: [recipe/webauthn/index.ts:108](https://github.com/supertokens/supert `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| `SignInErrorResponse`\> @@ -596,7 +589,7 @@ Defined in: [recipe/webauthn/index.ts:67](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input` | \{ `origin`: `string`; `relyingPartyId`: `string`; `relyingPartyName`: `string`; `tenantId`: `string`; `timeout`: `number`; `userContext?`: `Record`\<`string`, `any`\>; `userPresence`: `boolean`; `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification); \} | +| `input` | \{ `origin`: `string`; `relyingPartyId`: `string`; `relyingPartyName`: `string`; `tenantId`: `string`; `timeout`: `number`; `userContext?`: `Record`\<`string`, `any`\>; `userPresence`: `boolean`; `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification); \} | | `input.origin` | `string` | | `input.relyingPartyId` | `string` | | `input.relyingPartyName` | `string` | @@ -604,7 +597,7 @@ Defined in: [recipe/webauthn/index.ts:67](https://github.com/supertokens/superto | `input.timeout` | `number` | | `input.userContext?` | `Record`\<`string`, `any`\> | | `input.userPresence` | `boolean` | -| `input.userVerification` | [`UserVerification`](recipe-webauthn-types.mdx#userverification) | +| `input.userVerification` | [`UserVerification`](recipe-webauthn-types#userverification) | ###### Returns @@ -615,7 +608,7 @@ Defined in: [recipe/webauthn/index.ts:67](https://github.com/supertokens/superto `expiresAt`: `number`; `status`: `"OK"`; `timeout`: `number`; - `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification); + `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification); `webauthnGeneratedOptionsId`: `string`; \} \| `SignInOptionsErrorResponse`\> @@ -638,8 +631,8 @@ Defined in: [recipe/webauthn/index.ts:94](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload); `session`: `SessionContainerInterface`; `shouldTryLinkingWithSessionUser`: `boolean`; `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | -| `input.credential` | [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload) | +| `input` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types#registrationpayload); `session`: `SessionContainerInterface`; `shouldTryLinkingWithSessionUser`: `boolean`; `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | +| `input.credential` | [`RegistrationPayload`](recipe-webauthn-types#registrationpayload) | | `input.session` | `SessionContainerInterface` | | `input.shouldTryLinkingWithSessionUser` | `boolean` | | `input.tenantId` | `string` | @@ -650,9 +643,9 @@ Defined in: [recipe/webauthn/index.ts:94](https://github.com/supertokens/superto `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| `SignUpErrorResponse`\> @@ -706,8 +699,8 @@ Defined in: [recipe/webauthn/index.ts:122](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`AuthenticationPayload`](recipe-webauthn-types.mdx#authenticationpayload); `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | -| `input.credential` | [`AuthenticationPayload`](recipe-webauthn-types.mdx#authenticationpayload) | +| `input` | \{ `credential`: [`AuthenticationPayload`](recipe-webauthn-types#authenticationpayload); `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | +| `input.credential` | [`AuthenticationPayload`](recipe-webauthn-types#authenticationpayload) | | `input.tenantId` | `string` | | `input.userContext?` | `Record`\<`string`, `any`\> | | `input.webauthnGeneratedOptionsId` | `string` | @@ -879,7 +872,7 @@ Defined in: [recipe/webauthn/index.ts:389](https://github.com/supertokens/supert `Promise`\< \| \{ `createdAt`: `number`; - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `relyingPartyId`: `string`; `status`: `"OK"`; `webauthnCredentialId`: `string`; @@ -934,7 +927,7 @@ Defined in: [recipe/webauthn/index.ts:381](https://github.com/supertokens/supert `status`: `"OK"`; `timeout`: `number`; `userPresence`: `boolean`; - `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification); + `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification); `webauthnGeneratedOptionsId`: `string`; \} \| `GetGeneratedOptionsErrorResponse`\> @@ -968,9 +961,9 @@ Defined in: [recipe/webauthn/index.ts:383](https://github.com/supertokens/supert `Promise`\< \| \{ - `recipeUserId?`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId?`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| `GetUserFromRecoverAccountTokenErrorResponse`\> @@ -988,11 +981,11 @@ Defined in: [recipe/webauthn/index.ts:353](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `config?` | [`TypeInput`](recipe-webauthn-types.mdx#typeinput) | +| `config?` | [`TypeInput`](recipe-webauthn-types#typeinput) | #### Returns -[`RecipeListFunction`](types.mdx#recipelistfunction) +[`RecipeListFunction`](types#recipelistfunction) *** @@ -1041,8 +1034,8 @@ Defined in: [recipe/webauthn/index.ts:369](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `__namedParameters` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload); `tenantId?`: `string`; `token`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | -| `__namedParameters.credential` | [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload) | +| `__namedParameters` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types#registrationpayload); `tenantId?`: `string`; `token`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | +| `__namedParameters.credential` | [`RegistrationPayload`](recipe-webauthn-types#registrationpayload) | | `__namedParameters.tenantId?` | `string` | | `__namedParameters.token` | `string` | | `__namedParameters.userContext?` | `Record`\<`string`, `any`\> | @@ -1075,8 +1068,8 @@ Defined in: [recipe/webauthn/index.ts:373](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload); `recipeUserId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | -| `input.credential` | [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload) | +| `input` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types#registrationpayload); `recipeUserId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | +| `input.credential` | [`RegistrationPayload`](recipe-webauthn-types#registrationpayload) | | `input.recipeUserId` | `string` | | `input.userContext?` | `Record`\<`string`, `any`\> | | `input.webauthnGeneratedOptionsId` | `string` | @@ -1135,11 +1128,11 @@ Defined in: [recipe/webauthn/index.ts:357](https://github.com/supertokens/supert `Promise`\< \| \{ - `attestation`: [`Attestation`](recipe-webauthn-types.mdx#attestation); + `attestation`: [`Attestation`](recipe-webauthn-types#attestation); `authenticatorSelection`: \{ `requireResidentKey`: `boolean`; - `residentKey`: [`ResidentKey`](recipe-webauthn-types.mdx#residentkey); - `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification); + `residentKey`: [`ResidentKey`](recipe-webauthn-types#residentkey); + `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification); \}; `challenge`: `string`; `createdAt`: `number`; @@ -1237,7 +1230,7 @@ Defined in: [recipe/webauthn/index.ts:379](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | [`TypeWebauthnRecoverAccountEmailDeliveryInput`](recipe-webauthn-types.mdx#typewebauthnrecoveraccountemaildeliveryinput) & `object` | +| `input` | [`TypeWebauthnRecoverAccountEmailDeliveryInput`](recipe-webauthn-types#typewebauthnrecoveraccountemaildeliveryinput) & `object` | #### Returns @@ -1301,8 +1294,8 @@ Defined in: [recipe/webauthn/index.ts:361](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`AuthenticationPayload`](recipe-webauthn-types.mdx#authenticationpayload); `session`: `SessionContainerInterface`; `shouldTryLinkingWithSessionUser`: `boolean`; `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | -| `input.credential` | [`AuthenticationPayload`](recipe-webauthn-types.mdx#authenticationpayload) | +| `input` | \{ `credential`: [`AuthenticationPayload`](recipe-webauthn-types#authenticationpayload); `session`: `SessionContainerInterface`; `shouldTryLinkingWithSessionUser`: `boolean`; `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | +| `input.credential` | [`AuthenticationPayload`](recipe-webauthn-types#authenticationpayload) | | `input.session` | `SessionContainerInterface` | | `input.shouldTryLinkingWithSessionUser` | `boolean` | | `input.tenantId` | `string` | @@ -1313,9 +1306,9 @@ Defined in: [recipe/webauthn/index.ts:361](https://github.com/supertokens/supert `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| `SignInErrorResponse`\> @@ -1343,7 +1336,7 @@ Defined in: [recipe/webauthn/index.ts:359](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `origin`: `string`; `relyingPartyId`: `string`; `relyingPartyName`: `string`; `tenantId`: `string`; `timeout`: `number`; `userContext?`: `Record`\<`string`, `any`\>; `userPresence`: `boolean`; `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification); \} | +| `input` | \{ `origin`: `string`; `relyingPartyId`: `string`; `relyingPartyName`: `string`; `tenantId`: `string`; `timeout`: `number`; `userContext?`: `Record`\<`string`, `any`\>; `userPresence`: `boolean`; `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification); \} | | `input.origin` | `string` | | `input.relyingPartyId` | `string` | | `input.relyingPartyName` | `string` | @@ -1351,7 +1344,7 @@ Defined in: [recipe/webauthn/index.ts:359](https://github.com/supertokens/supert | `input.timeout` | `number` | | `input.userContext?` | `Record`\<`string`, `any`\> | | `input.userPresence` | `boolean` | -| `input.userVerification` | [`UserVerification`](recipe-webauthn-types.mdx#userverification) | +| `input.userVerification` | [`UserVerification`](recipe-webauthn-types#userverification) | #### Returns @@ -1362,7 +1355,7 @@ Defined in: [recipe/webauthn/index.ts:359](https://github.com/supertokens/supert `expiresAt`: `number`; `status`: `"OK"`; `timeout`: `number`; - `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification); + `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification); `webauthnGeneratedOptionsId`: `string`; \} \| `SignInOptionsErrorResponse`\> @@ -1387,8 +1380,8 @@ Defined in: [recipe/webauthn/index.ts:363](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload); `session`: `SessionContainerInterface`; `shouldTryLinkingWithSessionUser`: `boolean`; `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | -| `input.credential` | [`RegistrationPayload`](recipe-webauthn-types.mdx#registrationpayload) | +| `input` | \{ `credential`: [`RegistrationPayload`](recipe-webauthn-types#registrationpayload); `session`: `SessionContainerInterface`; `shouldTryLinkingWithSessionUser`: `boolean`; `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | +| `input.credential` | [`RegistrationPayload`](recipe-webauthn-types#registrationpayload) | | `input.session` | `SessionContainerInterface` | | `input.shouldTryLinkingWithSessionUser` | `boolean` | | `input.tenantId` | `string` | @@ -1399,9 +1392,9 @@ Defined in: [recipe/webauthn/index.ts:363](https://github.com/supertokens/supert `Promise`\< \| \{ - `recipeUserId`: [`RecipeUserId`](index.mdx#recipeuserid-1); + `recipeUserId`: [`RecipeUserId`](index#recipeuserid-1); `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| `SignUpErrorResponse`\> @@ -1459,8 +1452,8 @@ Defined in: [recipe/webauthn/index.ts:365](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: [`AuthenticationPayload`](recipe-webauthn-types.mdx#authenticationpayload); `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | -| `input.credential` | [`AuthenticationPayload`](recipe-webauthn-types.mdx#authenticationpayload) | +| `input` | \{ `credential`: [`AuthenticationPayload`](recipe-webauthn-types#authenticationpayload); `tenantId`: `string`; `userContext?`: `Record`\<`string`, `any`\>; `webauthnGeneratedOptionsId`: `string`; \} | +| `input.credential` | [`AuthenticationPayload`](recipe-webauthn-types#authenticationpayload) | | `input.tenantId` | `string` | | `input.userContext?` | `Record`\<`string`, `any`\> | | `input.webauthnGeneratedOptionsId` | `string` | @@ -1481,16 +1474,16 @@ Defined in: [recipe/webauthn/index.ts:365](https://github.com/supertokens/supert ### APIInterface -Re-exports [APIInterface](recipe-webauthn-types.mdx#apiinterface) +Re-exports [APIInterface](recipe-webauthn-types#apiinterface) *** ### APIOptions -Re-exports [APIOptions](recipe-webauthn-types.mdx#apioptions) +Re-exports [APIOptions](recipe-webauthn-types#apioptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-webauthn-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-webauthn-types#recipeinterface) diff --git a/docs/references/backend-sdks/supertokens-nodejs/types.mdx b/docs/references/backend-sdks/supertokens-nodejs/types.mdx index 1f551b26e2..a173d42f5a 100644 --- a/docs/references/backend-sdks/supertokens-nodejs/types.mdx +++ b/docs/references/backend-sdks/supertokens-nodejs/types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-node/types -page_title: SuperTokens Node Types -sidebar_position: 1 description: References documentation for the supertokens-node/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 1 --- -# SuperTokens Node Types - - ## Interfaces ### HttpRequest @@ -54,22 +47,22 @@ Defined in: [types.ts:90](https://github.com/supertokens/supertokens-node/blob/8 | Property | Type | Defined in | | ------ | ------ | ------ | -| `accountlinking` | [`TypeInput`](recipe-accountlinking-types.mdx#typeinput) & `object` | [types.ts:91](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L91) | -| `dashboard` | [`TypeInput`](recipe-dashboard-types.mdx#typeinput) | [types.ts:92](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L92) | -| `emailpassword` | [`TypeInput`](recipe-emailpassword-types.mdx#typeinput) | [types.ts:93](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L93) | -| `emailverification` | [`TypeInput`](recipe-emailverification-types.mdx#typeinput) | [types.ts:94](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L94) | -| `jwt` | [`TypeInput`](recipe-jwt-types.mdx#typeinput) | [types.ts:95](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L95) | -| `multifactorauth` | [`TypeInput`](recipe-multifactorauth-types.mdx#typeinput) | [types.ts:96](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L96) | -| `multitenancy` | [`TypeInput`](recipe-multitenancy-types.mdx#typeinput) | [types.ts:97](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L97) | -| `oauth2provider` | [`TypeInput`](recipe-oauth2provider-types.mdx#typeinput) | [types.ts:98](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L98) | -| `openid` | [`TypeInput`](recipe-openid-types.mdx#typeinput) | [types.ts:99](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L99) | -| `passwordless` | [`TypeInput`](recipe-passwordless-types.mdx#typeinput) | [types.ts:100](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L100) | +| `accountlinking` | [`TypeInput`](recipe-accountlinking-types#typeinput) & `object` | [types.ts:91](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L91) | +| `dashboard` | [`TypeInput`](recipe-dashboard-types#typeinput) | [types.ts:92](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L92) | +| `emailpassword` | [`TypeInput`](recipe-emailpassword-types#typeinput) | [types.ts:93](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L93) | +| `emailverification` | [`TypeInput`](recipe-emailverification-types#typeinput) | [types.ts:94](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L94) | +| `jwt` | [`TypeInput`](recipe-jwt-types#typeinput) | [types.ts:95](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L95) | +| `multifactorauth` | [`TypeInput`](recipe-multifactorauth-types#typeinput) | [types.ts:96](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L96) | +| `multitenancy` | [`TypeInput`](recipe-multitenancy-types#typeinput) | [types.ts:97](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L97) | +| `oauth2provider` | [`TypeInput`](recipe-oauth2provider-types#typeinput) | [types.ts:98](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L98) | +| `openid` | [`TypeInput`](recipe-openid-types#typeinput) | [types.ts:99](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L99) | +| `passwordless` | [`TypeInput`](recipe-passwordless-types#typeinput) | [types.ts:100](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L100) | | `session` | `SessionTypeInput` | [types.ts:101](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L101) | -| `thirdparty` | [`TypeInput`](recipe-thirdparty-types.mdx#typeinput) | [types.ts:102](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L102) | -| `totp` | [`TypeInput`](recipe-totp-types.mdx#typeinput) | [types.ts:103](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L103) | -| `usermetadata` | [`TypeInput`](recipe-usermetadata-types.mdx#typeinput) | [types.ts:104](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L104) | -| `userroles` | [`TypeInput`](recipe-userroles-types.mdx#typeinput) | [types.ts:105](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L105) | -| `webauthn` | [`TypeInput`](recipe-webauthn-types.mdx#typeinput) | [types.ts:106](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L106) | +| `thirdparty` | [`TypeInput`](recipe-thirdparty-types#typeinput) | [types.ts:102](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L102) | +| `totp` | [`TypeInput`](recipe-totp-types#typeinput) | [types.ts:103](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L103) | +| `usermetadata` | [`TypeInput`](recipe-usermetadata-types#typeinput) | [types.ts:104](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L104) | +| `userroles` | [`TypeInput`](recipe-userroles-types#typeinput) | [types.ts:105](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L105) | +| `webauthn` | [`TypeInput`](recipe-webauthn-types#typeinput) | [types.ts:106](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L106) | *** @@ -456,7 +449,7 @@ Defined in: [types.ts:231](https://github.com/supertokens/supertokens-node/blob/ | `emails` | `string`[] | [types.ts:236](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L236) | | `id` | `string` | [types.ts:232](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L232) | | `isPrimaryUser` | `boolean` | [types.ts:234](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L234) | -| `loginMethods` | [`RecipeLevelUser`](recipe-accountlinking-types.mdx#recipeleveluser) & `object`[] | [types.ts:245](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L245) | +| `loginMethods` | [`RecipeLevelUser`](recipe-accountlinking-types#recipeleveluser) & `object`[] | [types.ts:245](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L245) | | `phoneNumbers` | `string`[] | [types.ts:237](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L237) | | `tenantIds` | `string`[] | [types.ts:235](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L235) | | `thirdParty` | `object`[] | [types.ts:238](https://github.com/supertokens/supertokens-node/blob/8353a9a70d8b17dd9ff6ffe41201fa2ef0e60218/lib/ts/types.ts#L238) | diff --git a/docs/references/backend-sdks/user-context.mdx b/docs/references/backend-sdks/user-context.mdx index c252f3a0ab..7b88b30213 100644 --- a/docs/references/backend-sdks/user-context.mdx +++ b/docs/references/backend-sdks/user-context.mdx @@ -1,19 +1,10 @@ --- -id: user-context title: User Context -hide_title: true -sidebar_position: 6 -description: >- - Pass information across API functions using user context for custom execution - scenarios. -page_type: sdk-reference -category: backend-sdk +description: Pass information across API functions using user context for custom execution scenarios. +sidebar: + order: 6 --- - - -# User context - ## Overview The `UserContext` mechanism is a way to pass information across recipe or API functions to customize the authentication flow inside a specific *execution context*. @@ -22,7 +13,7 @@ By default, the user context passed to APIs and functions contains the request o ## Prerequisites -:::info Important +:::info[Important] This feature is only available for SDKs versions: - NodeJS >= `v9.0` - Python >= `v0.5` @@ -39,10 +30,10 @@ This is as opposed to it invoking from the sign in API, when it should continue To achieve this, all the API interface and recipe interface functions take a parameter called `userContext`, which is by default an empty object. When overriding the functions, anything can be added to this object, and that information carries onto the next set of functions called in the API. - - + + -```tsx +```tsx {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59} import SuperTokens from "supertokens-node"; import ThirdParty from "supertokens-node/recipe/thirdparty" import EmailPassword from "supertokens-node/recipe/emailpassword" @@ -58,7 +49,6 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -79,10 +69,8 @@ SuperTokens.init({ } }, } - // highlight-end }), ThirdParty.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -105,16 +93,15 @@ SuperTokens.init({ } }, } - // highlight-end }) ] }); ``` - - + + -```go +```go {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59} import ( "github.com/supertokens/supertokens-golang/recipe/emailpassword" "github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels" @@ -127,7 +114,6 @@ func main() { supertokens.Init(supertokens.TypeInput{ RecipeList: []supertokens.Recipe{ thirdparty.Init(&tpmodels.TypeInput{ - // highlight-start Override: &tpmodels.OverrideStruct{ Functions: func(originalImplementation tpmodels.RecipeInterface) tpmodels.RecipeInterface { ogSignInUp := *originalImplementation.SignInUp @@ -156,10 +142,8 @@ func main() { return originalImplementation }, }, - // highlight-end }), emailpassword.Init(&epmodels.TypeInput{ - // highlight-start Override: &epmodels.OverrideStruct{ APIs: func(originalImplementation epmodels.APIInterface) epmodels.APIInterface { ogSignUpPOST := *originalImplementation.SignUpPOST @@ -177,16 +161,15 @@ func main() { return originalImplementation }, }, - // highlight-end }), }, }) } ``` - - + + -```python +```python {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92} from supertokens_python import init, InputAppInfo from supertokens_python.recipe import thirdparty, emailpassword from supertokens_python.recipe.thirdparty.interfaces import ( @@ -200,7 +183,6 @@ from supertokens_python.recipe.thirdparty.types import RawUserInfoFromProvider from supertokens_python.recipe.session.interfaces import SessionContainer -# highlight-start def override_emailpassword_apis(original_implementation: APIInterface): original_sign_up_post = original_implementation.sign_up_post @@ -280,12 +262,9 @@ def override_thirdparty_functions(original_implementation: RecipeInterface): return original_implementation -# highlight-end - - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ thirdparty.init( override=thirdparty.InputOverrideConfig( @@ -298,13 +277,13 @@ init( ], ) ``` - - + + Then consume that context in the `createNewSession` function to return an empty function in case the `userContext.isSignUp` is `true`. - - + + ```tsx import SuperTokens from "supertokens-node"; @@ -379,8 +358,8 @@ SuperTokens.init({ }); ``` - - + + ```go import ( @@ -462,10 +441,10 @@ func main() { }) } ``` - - + + -```python +```python {17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51} from supertokens_python import init, InputAppInfo from supertokens_python.recipe.session.interfaces import ( RecipeInterface, @@ -482,8 +461,6 @@ from supertokens_python.types import RecipeUserId _T = TypeVar("_T") -# highlight-start - def override_session_functions(original_implementation: RecipeInterface): original_create_new_session = original_implementation.create_new_session @@ -518,12 +495,9 @@ def override_session_functions(original_implementation: RecipeInterface): return original_implementation -# highlight-end - - init( app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), - framework="...", # type: ignore + framework="...", recipe_list=[ session.init( override=session.InputOverrideConfig(functions=override_session_functions) @@ -652,12 +626,11 @@ class EmptySession(session.SessionContainer): def get_tenant_id(self, user_context: Union[Dict[str, Any], None] = None) -> str: return "" ``` - - + + As a summary, when the sign up API invokes, the initial value of `userContext` is an empty object. Change that user context to add the `isSignUp` field, ensuring that information communicates to the `createNewSession` function. When that function invokes, it checks if `isSignUp === true`, and if it is, it doesn't call the original implementation, and instead, returns an empty session. This way, the system does not create a session if the user is signing up, but it creates one if the user is signing in. Note that there are other ways of achieving this, but the above showcases how user context can use to communicate across recipes and across API & Recipe functions. - diff --git a/docs/references/backend-sdks/user-object.mdx b/docs/references/backend-sdks/user-object.mdx index ae4799bd26..c39d9163d8 100644 --- a/docs/references/backend-sdks/user-object.mdx +++ b/docs/references/backend-sdks/user-object.mdx @@ -1,23 +1,17 @@ --- title: User Object -hide_title: true -sidebar_position: 6 -description: >- - User Object page explains user structure, primary vs recipe user IDs, and - account linking. -page_type: sdk-reference -category: backend-sdk +description: User Object page explains user structure, primary vs recipe user IDs, and account linking. +sidebar: + order: 6 --- -# The user object - ## Overview The user object represents the entity that exposes user information during an authentication flow. ## Prerequisites -:::info Important +:::info[Important] This is only applicable for NodeJS SDK >= 16.0 and for Python SDK >= 0.25.0. For other versions, or SDKs, please see: https://github.com/supertokens/core-driver-interface/wiki ::: @@ -63,9 +57,7 @@ This is only applicable for NodeJS SDK >= 16.0 and for Python SDK >= 0.25.0. For
- -## Code sample - + ```ts type User = { id: string; @@ -108,7 +100,7 @@ class RecipeUserId { } ``` - + diff --git a/docs/references/cdi/_category_.json b/docs/references/cdi/_category_.json deleted file mode 100644 index a3516cd5a5..0000000000 --- a/docs/references/cdi/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Core Driver Interface", - "customProps": { "isMainCategory": true }, - "position": 5 -} diff --git a/docs/references/cdi/account-linking/_category_.json b/docs/references/cdi/account-linking/_category_.json deleted file mode 100644 index 6caee7b7ab..0000000000 --- a/docs/references/cdi/account-linking/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Account Linking", - "position": 1 -} diff --git a/docs/references/cdi/account-linking/get-accountlinking-user-link-check.mdx b/docs/references/cdi/account-linking/get-accountlinking-user-link-check.mdx deleted file mode 100644 index 0a3f64f27b..0000000000 --- a/docs/references/cdi/account-linking/get-accountlinking-user-link-check.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Check account linking possibility -sidebar_label: get Check account linking possibility -sidebar_position: 1 -description: >- - GET /appid-{appId}/recipe/accountlinking/user/link/check endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/account-linking/get-accountlinking-user-primary-check.mdx b/docs/references/cdi/account-linking/get-accountlinking-user-primary-check.mdx deleted file mode 100644 index 439b65fd96..0000000000 --- a/docs/references/cdi/account-linking/get-accountlinking-user-primary-check.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Check primary user creation possibility -sidebar_label: get Check primary user creation possibility -sidebar_position: 2 -description: >- - GET /appid-{appId}/recipe/accountlinking/user/primary/check endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/account-linking/meta.ts b/docs/references/cdi/account-linking/meta.ts new file mode 100644 index 0000000000..56d9b14e67 --- /dev/null +++ b/docs/references/cdi/account-linking/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Account Linking", + "icon": "file-user", + "order": 1 +}); diff --git a/docs/references/cdi/account-linking/post-accountlinking-user-link.mdx b/docs/references/cdi/account-linking/post-accountlinking-user-link.mdx deleted file mode 100644 index 54caca9e09..0000000000 --- a/docs/references/cdi/account-linking/post-accountlinking-user-link.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Link user accounts together -sidebar_label: post Link user accounts together -sidebar_position: 3 -description: >- - POST /appid-{appId}/recipe/accountlinking/user/link endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/account-linking/post-accountlinking-user-primary.mdx b/docs/references/cdi/account-linking/post-accountlinking-user-primary.mdx deleted file mode 100644 index d581ea6e94..0000000000 --- a/docs/references/cdi/account-linking/post-accountlinking-user-primary.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Create primary user account -sidebar_label: post Create primary user account -sidebar_position: 4 -description: >- - POST /appid-{appId}/recipe/accountlinking/user/primary endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/account-linking/post-accountlinking-user-unlink.mdx b/docs/references/cdi/account-linking/post-accountlinking-user-unlink.mdx deleted file mode 100644 index 2f37e598bc..0000000000 --- a/docs/references/cdi/account-linking/post-accountlinking-user-unlink.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Unlink user accounts -sidebar_label: post Unlink user accounts -sidebar_position: 5 -description: >- - POST /appid-{appId}/recipe/accountlinking/user/unlink endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/_category_.json b/docs/references/cdi/core/_category_.json deleted file mode 100644 index 4b7aa812e4..0000000000 --- a/docs/references/cdi/core/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Core", - "position": 3 -} diff --git a/docs/references/cdi/core/delete-ee-license.mdx b/docs/references/cdi/core/delete-ee-license.mdx deleted file mode 100644 index 53a2bee8b8..0000000000 --- a/docs/references/cdi/core/delete-ee-license.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Delete license key -sidebar_label: delete Delete license key -sidebar_position: 24 -description: 'DELETE `/appid-{appId}/ee/license` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/delete-hello.mdx b/docs/references/cdi/core/delete-hello.mdx deleted file mode 100644 index f931f2aa5e..0000000000 --- a/docs/references/cdi/core/delete-hello.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Delete hello message -sidebar_label: delete Delete hello message -sidebar_position: 23 -description: 'DELETE `/appid-{appId}/{tenantId}/hello` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-apiversion.mdx b/docs/references/cdi/core/get-apiversion.mdx deleted file mode 100644 index 51e28ff3cd..0000000000 --- a/docs/references/cdi/core/get-apiversion.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get API version -sidebar_label: get Get API version -sidebar_position: 6 -description: 'GET `/appid-{appId}/apiversion` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-config.mdx b/docs/references/cdi/core/get-config.mdx deleted file mode 100644 index ce5b186499..0000000000 --- a/docs/references/cdi/core/get-config.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get config file path -sidebar_label: get Get config file path -sidebar_position: 15 -description: GET `/config` endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-ee-featureflag.mdx b/docs/references/cdi/core/get-ee-featureflag.mdx deleted file mode 100644 index 2dd4e0ecf3..0000000000 --- a/docs/references/cdi/core/get-ee-featureflag.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get enterprise features -sidebar_label: get Get enterprise features -sidebar_position: 7 -description: 'GET `/appid-{appId}/ee/featureflag` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-ee-license.mdx b/docs/references/cdi/core/get-ee-license.mdx deleted file mode 100644 index 5b2696a9b6..0000000000 --- a/docs/references/cdi/core/get-ee-license.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get license key -sidebar_label: get Get license key -sidebar_position: 8 -description: 'GET `/appid-{appId}/ee/license` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-hello.mdx b/docs/references/cdi/core/get-hello.mdx deleted file mode 100644 index cec7b7af60..0000000000 --- a/docs/references/cdi/core/get-hello.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get hello message -sidebar_label: get Get hello message -sidebar_position: 2 -description: 'GET `/appid-{appId}/{tenantId}/hello` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-requests-stats.mdx b/docs/references/cdi/core/get-requests-stats.mdx deleted file mode 100644 index 94ea575362..0000000000 --- a/docs/references/cdi/core/get-requests-stats.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get requests stats -sidebar_label: get Get requests stats -sidebar_position: 10 -description: 'GET `/appid-{appId}/requests/stats` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-root.mdx b/docs/references/cdi/core/get-root.mdx deleted file mode 100644 index 5d6969f9c6..0000000000 --- a/docs/references/cdi/core/get-root.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get hello message on root path -sidebar_label: get Get hello message on root path -sidebar_position: 1 -description: 'GET `/appid-{appId}/{tenantId}/` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-telemetry.mdx b/docs/references/cdi/core/get-telemetry.mdx deleted file mode 100644 index a176f67c96..0000000000 --- a/docs/references/cdi/core/get-telemetry.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get telemetry ID -sidebar_label: get Get telemetry ID -sidebar_position: 11 -description: 'GET `/appid-{appId}/telemetry` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-user-id.mdx b/docs/references/cdi/core/get-user-id.mdx deleted file mode 100644 index 72c35b03b5..0000000000 --- a/docs/references/cdi/core/get-user-id.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get user ID -sidebar_label: get Get user ID -sidebar_position: 12 -description: 'GET `/appid-{appId}/user/id` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-user-search-tags.mdx b/docs/references/cdi/core/get-user-search-tags.mdx deleted file mode 100644 index b2d37c03dd..0000000000 --- a/docs/references/cdi/core/get-user-search-tags.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get search tags -sidebar_label: get Get search tags -sidebar_position: 13 -description: 'GET `/appid-{appId}/user/search/tags` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-userid-map.mdx b/docs/references/cdi/core/get-userid-map.mdx deleted file mode 100644 index 44ae6a0cd6..0000000000 --- a/docs/references/cdi/core/get-userid-map.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get user ID mapping -sidebar_label: get Get user ID mapping -sidebar_position: 9 -description: 'GET `/appid-{appId}/recipe/userid/map` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-users-by-accountinfo.mdx b/docs/references/cdi/core/get-users-by-accountinfo.mdx deleted file mode 100644 index 1747003622..0000000000 --- a/docs/references/cdi/core/get-users-by-accountinfo.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get users by account info -sidebar_label: get Get users by account info -sidebar_position: 4 -description: >- - GET `/appid-{appId}/{tenantId}/users/by-accountinfo` endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-users-count-active.mdx b/docs/references/cdi/core/get-users-count-active.mdx deleted file mode 100644 index fdd61f6522..0000000000 --- a/docs/references/cdi/core/get-users-count-active.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get active users count -sidebar_label: get Get active users count -sidebar_position: 14 -description: 'GET `/appid-{appId}/users/count/active` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-users-count.mdx b/docs/references/cdi/core/get-users-count.mdx deleted file mode 100644 index 451f1206a3..0000000000 --- a/docs/references/cdi/core/get-users-count.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get users count -sidebar_label: get Get users count -sidebar_position: 5 -description: 'GET `/appid-{appId}/{tenantId}/users/count` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/get-users.mdx b/docs/references/cdi/core/get-users.mdx deleted file mode 100644 index 79f840c034..0000000000 --- a/docs/references/cdi/core/get-users.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get users -sidebar_label: get Get users -sidebar_position: 3 -description: 'GET `/appid-{appId}/{tenantId}/users` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/meta.ts b/docs/references/cdi/core/meta.ts new file mode 100644 index 0000000000..07ba0f8c50 --- /dev/null +++ b/docs/references/cdi/core/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Core", + "icon": "cpu", + "order": 3 +}); diff --git a/docs/references/cdi/core/post-hello.mdx b/docs/references/cdi/core/post-hello.mdx deleted file mode 100644 index 9175db22c0..0000000000 --- a/docs/references/cdi/core/post-hello.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Post hello message -sidebar_label: post Post hello message -sidebar_position: 16 -description: 'POST `/appid-{appId}/{tenantId}/hello` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/post-user-remove.mdx b/docs/references/cdi/core/post-user-remove.mdx deleted file mode 100644 index 8fcfaf0a3d..0000000000 --- a/docs/references/cdi/core/post-user-remove.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Delete user -sidebar_label: post Delete user -sidebar_position: 19 -description: 'POST `/appid-{appId}/user/remove` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/post-userid-map-remove.mdx b/docs/references/cdi/core/post-userid-map-remove.mdx deleted file mode 100644 index b069e89bec..0000000000 --- a/docs/references/cdi/core/post-userid-map-remove.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Remove user ID mapping -sidebar_label: post Remove user ID mapping -sidebar_position: 18 -description: 'POST `/appid-{appId}/recipe/userid/map/remove` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/post-userid-map.mdx b/docs/references/cdi/core/post-userid-map.mdx deleted file mode 100644 index 5b266adfa1..0000000000 --- a/docs/references/cdi/core/post-userid-map.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Create user ID mapping -sidebar_label: post Create user ID mapping -sidebar_position: 17 -description: 'POST `/appid-{appId}/recipe/userid/map` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/put-ee-license.mdx b/docs/references/cdi/core/put-ee-license.mdx deleted file mode 100644 index 96482b617f..0000000000 --- a/docs/references/cdi/core/put-ee-license.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Set license key -sidebar_label: put Set license key -sidebar_position: 21 -description: 'PUT `/appid-{appId}/ee/license` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/put-hello.mdx b/docs/references/cdi/core/put-hello.mdx deleted file mode 100644 index 76aa70c913..0000000000 --- a/docs/references/cdi/core/put-hello.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Put hello message -sidebar_label: put Put hello message -sidebar_position: 20 -description: 'PUT `/appid-{appId}/{tenantId}/hello` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/core/put-userid-external-user-id-info.mdx b/docs/references/cdi/core/put-userid-external-user-id-info.mdx deleted file mode 100644 index 761df0e92d..0000000000 --- a/docs/references/cdi/core/put-userid-external-user-id-info.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Update external user info -sidebar_label: put Update external user info -sidebar_position: 22 -description: >- - PUT `/appid-{appId}/recipe/userid/external-user-id-info` endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/dashboard/_category_.json b/docs/references/cdi/dashboard/_category_.json deleted file mode 100644 index 78534d5630..0000000000 --- a/docs/references/cdi/dashboard/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Dashboard", - "position": 4 -} diff --git a/docs/references/cdi/dashboard/delete-dashboard-session.mdx b/docs/references/cdi/dashboard/delete-dashboard-session.mdx deleted file mode 100644 index 5b4fb0f52a..0000000000 --- a/docs/references/cdi/dashboard/delete-dashboard-session.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Revoke dashboard user session -sidebar_label: delete Revoke dashboard user session -sidebar_position: 8 -description: 'DELETE `/appid-{appId}/recipe/dashboard/session` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/dashboard/delete-dashboard-user.mdx b/docs/references/cdi/dashboard/delete-dashboard-user.mdx deleted file mode 100644 index 441ab8936c..0000000000 --- a/docs/references/cdi/dashboard/delete-dashboard-user.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Delete dashboard user -sidebar_label: delete Delete dashboard user -sidebar_position: 9 -description: 'DELETE `/appid-{appId}/recipe/dashboard/user` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/dashboard/get-dashboard-tenant-core-config.mdx b/docs/references/cdi/dashboard/get-dashboard-tenant-core-config.mdx deleted file mode 100644 index c179d0c2ff..0000000000 --- a/docs/references/cdi/dashboard/get-dashboard-tenant-core-config.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get the core config -sidebar_label: get Get the core config -sidebar_position: 1 -description: >- - GET `/appid-{appId}/{tenantId}/recipe/dashboard/tenant/core-config` endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/dashboard/get-dashboard-user-sessions.mdx b/docs/references/cdi/dashboard/get-dashboard-user-sessions.mdx deleted file mode 100644 index 71e86c28c8..0000000000 --- a/docs/references/cdi/dashboard/get-dashboard-user-sessions.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get all sessions for dashboard user -sidebar_label: get Get all sessions for dashboard user -sidebar_position: 2 -description: >- - GET `/appid-{appId}/recipe/dashboard/user/sessions` endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/dashboard/get-dashboard-users.mdx b/docs/references/cdi/dashboard/get-dashboard-users.mdx deleted file mode 100644 index 74d3e12d32..0000000000 --- a/docs/references/cdi/dashboard/get-dashboard-users.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get all dashboard users -sidebar_label: get Get all dashboard users -sidebar_position: 3 -description: 'GET `/appid-{appId}/recipe/dashboard/users` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/dashboard/meta.ts b/docs/references/cdi/dashboard/meta.ts new file mode 100644 index 0000000000..102248e044 --- /dev/null +++ b/docs/references/cdi/dashboard/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Dashboard", + "icon": "layout-dashboard", + "order": 4 +}); diff --git a/docs/references/cdi/dashboard/post-dashboard-session-verify.mdx b/docs/references/cdi/dashboard/post-dashboard-session-verify.mdx deleted file mode 100644 index e51812e77a..0000000000 --- a/docs/references/cdi/dashboard/post-dashboard-session-verify.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Verify dashboard user session -sidebar_label: post Verify dashboard user session -sidebar_position: 4 -description: >- - POST `/appid-{appId}/recipe/dashboard/session/verify` endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/dashboard/post-dashboard-signin.mdx b/docs/references/cdi/dashboard/post-dashboard-signin.mdx deleted file mode 100644 index f489a70452..0000000000 --- a/docs/references/cdi/dashboard/post-dashboard-signin.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Sign in dashboard user -sidebar_label: post Sign in dashboard user -sidebar_position: 5 -description: 'POST `/appid-{appId}/recipe/dashboard/signin` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/dashboard/post-dashboard-user.mdx b/docs/references/cdi/dashboard/post-dashboard-user.mdx deleted file mode 100644 index c5a1a80d4f..0000000000 --- a/docs/references/cdi/dashboard/post-dashboard-user.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Create dashboard user -sidebar_label: post Create dashboard user -sidebar_position: 6 -description: 'POST `/appid-{appId}/recipe/dashboard/user` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/dashboard/put-dashboard-user.mdx b/docs/references/cdi/dashboard/put-dashboard-user.mdx deleted file mode 100644 index d29dbe355f..0000000000 --- a/docs/references/cdi/dashboard/put-dashboard-user.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Update dashboard user -sidebar_label: put Update dashboard user -sidebar_position: 7 -description: 'PUT `/appid-{appId}/recipe/dashboard/user` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-password/_category_.json b/docs/references/cdi/email-password/_category_.json deleted file mode 100644 index 93d1cf49e1..0000000000 --- a/docs/references/cdi/email-password/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Email/Password", - "position": 6 -} diff --git a/docs/references/cdi/email-password/get-user.mdx b/docs/references/cdi/email-password/get-user.mdx deleted file mode 100644 index d301b87953..0000000000 --- a/docs/references/cdi/email-password/get-user.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get email password user -sidebar_label: get Get email password user (deprecated) -sidebar_position: 1 -description: 'GET `/appid-{appId}/{tenantId}/recipe/user` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-password/meta.ts b/docs/references/cdi/email-password/meta.ts new file mode 100644 index 0000000000..4053ab2748 --- /dev/null +++ b/docs/references/cdi/email-password/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Email/Password", + "icon": "rectangle-ellipsis", + "order": 6 +}); diff --git a/docs/references/cdi/email-password/post-signin.mdx b/docs/references/cdi/email-password/post-signin.mdx deleted file mode 100644 index dc6a2b5bf5..0000000000 --- a/docs/references/cdi/email-password/post-signin.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Sign in user -sidebar_label: post Sign in user -sidebar_position: 2 -description: 'POST `/appid-{appId}/{tenantId}/recipe/signin` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-password/post-signup.mdx b/docs/references/cdi/email-password/post-signup.mdx deleted file mode 100644 index 7f0fcda751..0000000000 --- a/docs/references/cdi/email-password/post-signup.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Sign up user -sidebar_label: post Sign up user -sidebar_position: 3 -description: 'POST `/appid-{appId}/{tenantId}/recipe/signup` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-password/post-user-password-reset-token-consume.mdx b/docs/references/cdi/email-password/post-user-password-reset-token-consume.mdx deleted file mode 100644 index 9dd015180c..0000000000 --- a/docs/references/cdi/email-password/post-user-password-reset-token-consume.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Consume password reset token -sidebar_label: post Consume password reset token -sidebar_position: 6 -description: >- - POST /appid-{appId}/{tenantId}/recipe/user/password/reset/token/consume - endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-password/post-user-password-reset-token.mdx b/docs/references/cdi/email-password/post-user-password-reset-token.mdx deleted file mode 100644 index 4cd5b80c8d..0000000000 --- a/docs/references/cdi/email-password/post-user-password-reset-token.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Generate password reset token -sidebar_label: post Generate password reset token -sidebar_position: 5 -description: >- - POST /appid-{appId}/{tenantId}/recipe/user/password/reset/token endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-password/post-user-password-reset.mdx b/docs/references/cdi/email-password/post-user-password-reset.mdx deleted file mode 100644 index 511bbefcdd..0000000000 --- a/docs/references/cdi/email-password/post-user-password-reset.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Reset user password -sidebar_label: post Reset user password (deprecated) -sidebar_position: 4 -description: >- - POST /appid-{appId}/{tenantId}/recipe/user/password/reset endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-password/post-user-passwordhash-import.mdx b/docs/references/cdi/email-password/post-user-passwordhash-import.mdx deleted file mode 100644 index 1ee55cecad..0000000000 --- a/docs/references/cdi/email-password/post-user-passwordhash-import.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Import user with hash -sidebar_label: post Import user with hash -sidebar_position: 7 -description: >- - POST /appid-{appId}/{tenantId}/recipe/user/passwordhash/import endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-password/put-user.mdx b/docs/references/cdi/email-password/put-user.mdx deleted file mode 100644 index fdd80a5b9c..0000000000 --- a/docs/references/cdi/email-password/put-user.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Update user info -sidebar_label: put Update user info -sidebar_position: 8 -description: 'PUT /appid-{appId}/{tenantId}/recipe/user endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-verification/_category_.json b/docs/references/cdi/email-verification/_category_.json deleted file mode 100644 index c47c04104f..0000000000 --- a/docs/references/cdi/email-verification/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Email Verification", - "position": 5 -} diff --git a/docs/references/cdi/email-verification/get-user-email-verify.mdx b/docs/references/cdi/email-verification/get-user-email-verify.mdx deleted file mode 100644 index 4aa82040c8..0000000000 --- a/docs/references/cdi/email-verification/get-user-email-verify.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Check email verification -sidebar_label: get Check email verification -sidebar_position: 1 -description: 'GET /appid-{appId}/recipe/user/email/verify endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-verification/meta.ts b/docs/references/cdi/email-verification/meta.ts new file mode 100644 index 0000000000..16329927c7 --- /dev/null +++ b/docs/references/cdi/email-verification/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Email Verification", + "icon": "mail-check", + "order": 5 +}); diff --git a/docs/references/cdi/email-verification/post-user-email-verify-remove.mdx b/docs/references/cdi/email-verification/post-user-email-verify-remove.mdx deleted file mode 100644 index 6013d0add7..0000000000 --- a/docs/references/cdi/email-verification/post-user-email-verify-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Unverify email -sidebar_label: post Unverify email -sidebar_position: 5 -description: >- - POST /appid-{appId}/recipe/user/email/verify/remove endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-verification/post-user-email-verify-token-remove.mdx b/docs/references/cdi/email-verification/post-user-email-verify-token-remove.mdx deleted file mode 100644 index d8e63395e9..0000000000 --- a/docs/references/cdi/email-verification/post-user-email-verify-token-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Remove email verification tokens -sidebar_label: post Remove email verification tokens -sidebar_position: 4 -description: >- - POST /appid-{appId}/{tenantId}/recipe/user/email/verify/token/remove endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-verification/post-user-email-verify-token.mdx b/docs/references/cdi/email-verification/post-user-email-verify-token.mdx deleted file mode 100644 index ec4ba9c95c..0000000000 --- a/docs/references/cdi/email-verification/post-user-email-verify-token.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Generate email verification token -sidebar_label: post Generate email verification token -sidebar_position: 3 -description: >- - POST /appid-{appId}/{tenantId}/recipe/user/email/verify/token endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/email-verification/post-user-email-verify.mdx b/docs/references/cdi/email-verification/post-user-email-verify.mdx deleted file mode 100644 index 7065810bb2..0000000000 --- a/docs/references/cdi/email-verification/post-user-email-verify.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Verify email -sidebar_label: post Verify email -sidebar_position: 2 -description: >- - POST /appid-{appId}/{tenantId}/recipe/user/email/verify endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/import/_category_.json b/docs/references/cdi/import/_category_.json deleted file mode 100644 index 8cda0027b4..0000000000 --- a/docs/references/cdi/import/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Bulk Import", - "position": 2 -} diff --git a/docs/references/cdi/import/delete-bulk-import-users.mdx b/docs/references/cdi/import/delete-bulk-import-users.mdx deleted file mode 100644 index 36efd77b64..0000000000 --- a/docs/references/cdi/import/delete-bulk-import-users.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Delete bulk import users -sidebar_label: post Delete bulk import users -sidebar_position: 4 -description: 'POST /appid-{appId}/bulk-import/users/remove endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/import/get-bulk-import-users-count.mdx b/docs/references/cdi/import/get-bulk-import-users-count.mdx deleted file mode 100644 index a033ec1030..0000000000 --- a/docs/references/cdi/import/get-bulk-import-users-count.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Import one user directly -sidebar_label: post Import one user directly -sidebar_position: 5 -description: POST /appid-/bulk-import/import endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/import/get-bulk-import-users.mdx b/docs/references/cdi/import/get-bulk-import-users.mdx deleted file mode 100644 index cade60590b..0000000000 --- a/docs/references/cdi/import/get-bulk-import-users.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: List bulk import users -sidebar_label: get List bulk import users -sidebar_position: 1 -description: 'GET /appid-{appId}/bulk-import/users endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/import/meta.ts b/docs/references/cdi/import/meta.ts new file mode 100644 index 0000000000..8522b4e5dc --- /dev/null +++ b/docs/references/cdi/import/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Bulk Import", + "icon": "user-plus", + "order": 2 +}); diff --git a/docs/references/cdi/import/post-bulk-import-import.mdx b/docs/references/cdi/import/post-bulk-import-import.mdx deleted file mode 100644 index fb34c16416..0000000000 --- a/docs/references/cdi/import/post-bulk-import-import.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Count bulk import users -sidebar_label: get Count bulk import users -sidebar_position: 2 -description: GET /appid-/bulk-import/users/count endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/import/post-bulk-import-users.mdx b/docs/references/cdi/import/post-bulk-import-users.mdx deleted file mode 100644 index 9dd0a52027..0000000000 --- a/docs/references/cdi/import/post-bulk-import-users.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Add bulk import users -sidebar_label: post Add bulk import users -sidebar_position: 3 -description: 'POST /appid-{appId}/bulk-import/users endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/introduction.mdx b/docs/references/cdi/introduction.mdx index cfcef3ccfb..142b47384a 100644 --- a/docs/references/cdi/introduction.mdx +++ b/docs/references/cdi/introduction.mdx @@ -1,30 +1,20 @@ --- title: Introduction -hide_title: true -sidebar_position: 0.1 -description: >- - Access detailed API specifications for integrating with SuperTokens Core and - frontend SDKs. -pagination_prev: null -pagination_next: null -page_type: overview -category: cdi +description: Access detailed API specifications for integrating with SuperTokens Core and frontend SDKs. +sidebar: + order: 0.1 --- -# Core Driver Interface - - ## Overview The **CDI**, Core Driver Interface, is the API exposed by the **SuperTokens Core** service. It is meant to be consumed only by your backend only. -:::info no-title -In most cases, you don't need to directly interact with the API, since the existing [backend SDKS](/docs/references/backend-sdks/reference) are built on top of it. +:::info +In most cases, you don't need to directly interact with the API, since the existing [backend SDKS](/references/backend-sdks/reference) are built on top of it. ::: - ### URL Structure Most of the endpoints take in two path parameters: `appid-{appId}` and `{tenantId}`. @@ -55,8 +45,4 @@ In order for the core service to accept a request you need to set the `api-key` If you are using the managed service, the token can be accessed from the **Connection Information** section on the deployment's **Overview** page in [the SaaS Dashboard](https://supertokens.com/dashboard). In the context of a self-hosted instance, keys are not created by default. -You have to explicitly [generate them](/docs/platform-configuration/supertokens-core/api-keys). - - - - +You have to explicitly [generate them](/platform-configuration/supertokens-core/api-keys). diff --git a/docs/references/cdi/meta.ts b/docs/references/cdi/meta.ts new file mode 100644 index 0000000000..6be7c44664 --- /dev/null +++ b/docs/references/cdi/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Core Driver Interface", + "icon": "file-terminal", + "order": 5 +}); diff --git a/docs/references/cdi/mfa/_category_.json b/docs/references/cdi/mfa/_category_.json deleted file mode 100644 index 6912806378..0000000000 --- a/docs/references/cdi/mfa/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "MFA", - "position": 7 -} diff --git a/docs/references/cdi/mfa/get-totp-device-list.mdx b/docs/references/cdi/mfa/get-totp-device-list.mdx deleted file mode 100644 index 6cd8e03f49..0000000000 --- a/docs/references/cdi/mfa/get-totp-device-list.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: List user TOTP devices -sidebar_label: get List user TOTP devices -sidebar_position: 1 -description: 'GET /appid-{appId}/recipe/totp/device/list endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/mfa/meta.ts b/docs/references/cdi/mfa/meta.ts new file mode 100644 index 0000000000..533c350eab --- /dev/null +++ b/docs/references/cdi/mfa/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "MFA", + "icon": "shield-check", + "order": 7 +}); diff --git a/docs/references/cdi/mfa/post-totp-device-import.mdx b/docs/references/cdi/mfa/post-totp-device-import.mdx deleted file mode 100644 index ca34bd640a..0000000000 --- a/docs/references/cdi/mfa/post-totp-device-import.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Import existing TOTP device -sidebar_label: post Import existing TOTP device -sidebar_position: 6 -description: POST /recipe/totp/device/import endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/mfa/post-totp-device-remove.mdx b/docs/references/cdi/mfa/post-totp-device-remove.mdx deleted file mode 100644 index 7a0d85b5f1..0000000000 --- a/docs/references/cdi/mfa/post-totp-device-remove.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Remove TOTP device -sidebar_label: post Remove TOTP device -sidebar_position: 5 -description: 'POST /appid-{appId}/recipe/totp/device/remove endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/mfa/post-totp-device-verify.mdx b/docs/references/cdi/mfa/post-totp-device-verify.mdx deleted file mode 100644 index 6bcef8ffcb..0000000000 --- a/docs/references/cdi/mfa/post-totp-device-verify.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Verify TOTP device -sidebar_label: post Verify TOTP device -sidebar_position: 2 -description: >- - POST /appid-{appId}/{tenantId}/recipe/totp/device/verify endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/mfa/post-totp-device.mdx b/docs/references/cdi/mfa/post-totp-device.mdx deleted file mode 100644 index 5a49941191..0000000000 --- a/docs/references/cdi/mfa/post-totp-device.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Add TOTP device for user -sidebar_label: post Add TOTP device for user -sidebar_position: 4 -description: 'POST /appid-{appId}/recipe/totp/device endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/mfa/post-totp-verify.mdx b/docs/references/cdi/mfa/post-totp-verify.mdx deleted file mode 100644 index 194f408524..0000000000 --- a/docs/references/cdi/mfa/post-totp-verify.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Verify TOTP code -sidebar_label: post Verify TOTP code -sidebar_position: 3 -description: >- - POST /appid-{appId}/{tenantId}/recipe/totp/verify endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/mfa/put-totp-device.mdx b/docs/references/cdi/mfa/put-totp-device.mdx deleted file mode 100644 index 4316fe10c5..0000000000 --- a/docs/references/cdi/mfa/put-totp-device.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Update TOTP device name -sidebar_label: put Update TOTP device name -sidebar_position: 7 -description: 'PUT /appid-{appId}/recipe/totp/device endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/_category_.json b/docs/references/cdi/multitenancy/_category_.json deleted file mode 100644 index 438459d13e..0000000000 --- a/docs/references/cdi/multitenancy/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Multitenancy", - "position": 8 -} diff --git a/docs/references/cdi/multitenancy/get-multitenancy-app-list-v2.mdx b/docs/references/cdi/multitenancy/get-multitenancy-app-list-v2.mdx deleted file mode 100644 index 85b279b3f8..0000000000 --- a/docs/references/cdi/multitenancy/get-multitenancy-app-list-v2.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: List apps -sidebar_label: get List apps -sidebar_position: 6 -description: GET /recipe/multitenancy/app/list/v2 endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/get-multitenancy-app-list.mdx b/docs/references/cdi/multitenancy/get-multitenancy-app-list.mdx deleted file mode 100644 index 8b642c5455..0000000000 --- a/docs/references/cdi/multitenancy/get-multitenancy-app-list.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: List apps -sidebar_label: get List apps (deprecated) -sidebar_position: 5 -description: GET /recipe/multitenancy/app/list endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list-v2.mdx b/docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list-v2.mdx deleted file mode 100644 index 85edd56da4..0000000000 --- a/docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list-v2.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: List connection uri domains -sidebar_label: get List connection uri domains -sidebar_position: 8 -description: >- - GET /recipe/multitenancy/connectionuridomain/list/v2 endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list.mdx b/docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list.mdx deleted file mode 100644 index 5025bc4ee1..0000000000 --- a/docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: List connection uri domains -sidebar_label: get List connection uri domains (deprecated) -sidebar_position: 7 -description: >- - GET /recipe/multitenancy/connectionuridomain/list endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/get-multitenancy-tenant-list-v2.mdx b/docs/references/cdi/multitenancy/get-multitenancy-tenant-list-v2.mdx deleted file mode 100644 index e77318415b..0000000000 --- a/docs/references/cdi/multitenancy/get-multitenancy-tenant-list-v2.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: List tenants in an app -sidebar_label: get List tenants in an app -sidebar_position: 4 -description: >- - GET /appid-{appId}/recipe/multitenancy/tenant/list/v2 endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/get-multitenancy-tenant-list.mdx b/docs/references/cdi/multitenancy/get-multitenancy-tenant-list.mdx deleted file mode 100644 index 8380f05bc5..0000000000 --- a/docs/references/cdi/multitenancy/get-multitenancy-tenant-list.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: List tenants in an app -sidebar_label: get List tenants in an app (deprecated) -sidebar_position: 3 -description: >- - GET /appid-{appId}/recipe/multitenancy/tenant/list endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/get-multitenancy-tenant-v2.mdx b/docs/references/cdi/multitenancy/get-multitenancy-tenant-v2.mdx deleted file mode 100644 index af7a6dd864..0000000000 --- a/docs/references/cdi/multitenancy/get-multitenancy-tenant-v2.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get tenant configuration -sidebar_label: get Get tenant configuration -sidebar_position: 2 -description: >- - GET /appid-{appId}/{tenantId}/recipe/multitenancy/tenant/v2 endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/get-multitenancy-tenant.mdx b/docs/references/cdi/multitenancy/get-multitenancy-tenant.mdx deleted file mode 100644 index 174992f6cb..0000000000 --- a/docs/references/cdi/multitenancy/get-multitenancy-tenant.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get tenant configuration -sidebar_label: get Get tenant configuration (deprecated) -sidebar_position: 1 -description: >- - GET /appid-{appId}/{tenantId}/recipe/multitenancy/tenant endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/meta.ts b/docs/references/cdi/multitenancy/meta.ts new file mode 100644 index 0000000000..53bcd47f15 --- /dev/null +++ b/docs/references/cdi/multitenancy/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Multitenancy", + "icon": "house-plus", + "order": 8 +}); diff --git a/docs/references/cdi/multitenancy/post-multitenancy-app-remove.mdx b/docs/references/cdi/multitenancy/post-multitenancy-app-remove.mdx deleted file mode 100644 index dcec5e7396..0000000000 --- a/docs/references/cdi/multitenancy/post-multitenancy-app-remove.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Delete app -sidebar_label: post Delete app -sidebar_position: 13 -description: POST /recipe/multitenancy/app/remove endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/post-multitenancy-config-thirdparty-remove.mdx b/docs/references/cdi/multitenancy/post-multitenancy-config-thirdparty-remove.mdx deleted file mode 100644 index d42283c937..0000000000 --- a/docs/references/cdi/multitenancy/post-multitenancy-config-thirdparty-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Delete ThirdParty Provider configuration -sidebar_label: post Delete ThirdParty Provider configuration -sidebar_position: 9 -description: >- - POST /appid-{appId}/{tenantId}/recipe/multitenancy/config/thirdparty/remove - endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/post-multitenancy-connectionuridomain-remove.mdx b/docs/references/cdi/multitenancy/post-multitenancy-connectionuridomain-remove.mdx deleted file mode 100644 index bf4ab3b4d4..0000000000 --- a/docs/references/cdi/multitenancy/post-multitenancy-connectionuridomain-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Remove connection uri domain -sidebar_label: post Remove connection uri domain -sidebar_position: 14 -description: >- - POST /recipe/multitenancy/connectionuridomain/remove endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/post-multitenancy-tenant-remove.mdx b/docs/references/cdi/multitenancy/post-multitenancy-tenant-remove.mdx deleted file mode 100644 index 5229a2869b..0000000000 --- a/docs/references/cdi/multitenancy/post-multitenancy-tenant-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Delete a tenant -sidebar_label: post Delete a tenant -sidebar_position: 12 -description: >- - POST /appid-{appId}/recipe/multitenancy/tenant/remove endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/post-multitenancy-tenant-user-remove.mdx b/docs/references/cdi/multitenancy/post-multitenancy-tenant-user-remove.mdx deleted file mode 100644 index 072d599710..0000000000 --- a/docs/references/cdi/multitenancy/post-multitenancy-tenant-user-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Remove user tenant association -sidebar_label: post Remove user tenant association -sidebar_position: 11 -description: >- - POST /appid-{appId}/{tenantId}/recipe/multitenancy/tenant/user/remove endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/post-multitenancy-tenant-user.mdx b/docs/references/cdi/multitenancy/post-multitenancy-tenant-user.mdx deleted file mode 100644 index 029b3301de..0000000000 --- a/docs/references/cdi/multitenancy/post-multitenancy-tenant-user.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Add user tenant association -sidebar_label: post Add user tenant association -sidebar_position: 10 -description: >- - POST /appid-{appId}/{tenantId}/recipe/multitenancy/tenant/user endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/put-multitenancy-app-v2.mdx b/docs/references/cdi/multitenancy/put-multitenancy-app-v2.mdx deleted file mode 100644 index 7b112f4700..0000000000 --- a/docs/references/cdi/multitenancy/put-multitenancy-app-v2.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Upsert app -sidebar_label: put Upsert app -sidebar_position: 19 -description: PUT /recipe/multitenancy/app/v2 endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/put-multitenancy-app.mdx b/docs/references/cdi/multitenancy/put-multitenancy-app.mdx deleted file mode 100644 index 0e0353d868..0000000000 --- a/docs/references/cdi/multitenancy/put-multitenancy-app.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Upsert app -sidebar_label: put Upsert app (deprecated) -sidebar_position: 18 -description: PUT /recipe/multitenancy/app endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/put-multitenancy-config-thirdparty.mdx b/docs/references/cdi/multitenancy/put-multitenancy-config-thirdparty.mdx deleted file mode 100644 index a5eff3e1fd..0000000000 --- a/docs/references/cdi/multitenancy/put-multitenancy-config-thirdparty.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Upsert ThirdParty Provider configuration -sidebar_label: put Upsert ThirdParty Provider configuration -sidebar_position: 15 -description: >- - PUT /appid-{appId}/{tenantId}/recipe/multitenancy/config/thirdparty endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain-v2.mdx b/docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain-v2.mdx deleted file mode 100644 index d6a1b45405..0000000000 --- a/docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain-v2.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Upsert connection uri domain -sidebar_label: put Upsert connection uri domain -sidebar_position: 21 -description: >- - PUT /recipe/multitenancy/connectionuridomain/v2 endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain.mdx b/docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain.mdx deleted file mode 100644 index f57be05b71..0000000000 --- a/docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Upsert connection URI domain -sidebar_label: put Upsert connection URI domain (deprecated) -sidebar_position: 20 -description: PUT /recipe/multitenancy/connectionuridomain endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/put-multitenancy-tenant-v2.mdx b/docs/references/cdi/multitenancy/put-multitenancy-tenant-v2.mdx deleted file mode 100644 index 9a3dbe8e82..0000000000 --- a/docs/references/cdi/multitenancy/put-multitenancy-tenant-v2.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Upsert tenant -sidebar_label: put Upsert tenant -sidebar_position: 17 -description: >- - PUT /appid-{appId}/recipe/multitenancy/tenant/v2 endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/multitenancy/put-multitenancy-tenant.mdx b/docs/references/cdi/multitenancy/put-multitenancy-tenant.mdx deleted file mode 100644 index ae192fd767..0000000000 --- a/docs/references/cdi/multitenancy/put-multitenancy-tenant.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Upsert tenant -sidebar_label: put Upsert tenant (deprecated) -sidebar_position: 16 -description: 'PUT /appid-{appId}/recipe/multitenancy/tenant endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/_category_.json b/docs/references/cdi/oauth/_category_.json deleted file mode 100644 index 7644618425..0000000000 --- a/docs/references/cdi/oauth/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "OAuth", - "position": 9 -} diff --git a/docs/references/cdi/oauth/get-jwks.mdx b/docs/references/cdi/oauth/get-jwks.mdx deleted file mode 100644 index 7ec2141554..0000000000 --- a/docs/references/cdi/oauth/get-jwks.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get JWT keys -sidebar_label: get Get JWT keys (deprecated) -sidebar_position: 2 -description: 'GET /appid-{appId}/recipe/jwt/jwks endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/get-oauth2-auth.mdx b/docs/references/cdi/oauth/get-oauth2-auth.mdx deleted file mode 100644 index f02d33afd0..0000000000 --- a/docs/references/cdi/oauth/get-oauth2-auth.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get OAuth2 Auth -sidebar_label: get Get OAuth2 Auth -sidebar_position: 3 -description: 'GET /appid-{appId}/recipe/oauth/auth endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/get-oauth2-client.mdx b/docs/references/cdi/oauth/get-oauth2-client.mdx deleted file mode 100644 index f5286d2ca3..0000000000 --- a/docs/references/cdi/oauth/get-oauth2-client.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get OAuth2 Client -sidebar_label: get Get OAuth2 Client -sidebar_position: 6 -description: 'GET /appid-{appId}/recipe/oauth/clients endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/get-oauth2-clients.mdx b/docs/references/cdi/oauth/get-oauth2-clients.mdx deleted file mode 100644 index 90142f304a..0000000000 --- a/docs/references/cdi/oauth/get-oauth2-clients.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: List OAuth2 Clients -sidebar_label: get List OAuth2 Clients -sidebar_position: 7 -description: 'GET /appid-{appId}/recipe/oauth/clients/list endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/get-oauth2-consent-request.mdx b/docs/references/cdi/oauth/get-oauth2-consent-request.mdx deleted file mode 100644 index d6e7982623..0000000000 --- a/docs/references/cdi/oauth/get-oauth2-consent-request.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get OAuth2 Consent Request -sidebar_label: get Get OAuth2 Consent Request -sidebar_position: 4 -description: >- - GET /appid-{appId}/recipe/oauth/auth/requests/consent endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/get-oauth2-login-request.mdx b/docs/references/cdi/oauth/get-oauth2-login-request.mdx deleted file mode 100644 index 48e64edd94..0000000000 --- a/docs/references/cdi/oauth/get-oauth2-login-request.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get OAuth2 Login Request -sidebar_label: get Get OAuth2 Login Request -sidebar_position: 5 -description: >- - GET /appid-{appId}/recipe/oauth/auth/requests/login endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/get-oauth2-sessions-logout.mdx b/docs/references/cdi/oauth/get-oauth2-sessions-logout.mdx deleted file mode 100644 index 291713dd3e..0000000000 --- a/docs/references/cdi/oauth/get-oauth2-sessions-logout.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get OAuth2 Sessions Logout -sidebar_label: get Get OAuth2 Sessions Logout -sidebar_position: 8 -description: >- - GET /appid-{appId}/recipe/oauth/sessions/logout endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/get-oauth2-token.mdx b/docs/references/cdi/oauth/get-oauth2-token.mdx deleted file mode 100644 index 3e9e3d2f43..0000000000 --- a/docs/references/cdi/oauth/get-oauth2-token.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get OAuth2 Token -sidebar_label: post Get OAuth2 Token -sidebar_position: 13 -description: 'POST /appid-{appId}/recipe/oauth/token endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/get-well-known-jwks.mdx b/docs/references/cdi/oauth/get-well-known-jwks.mdx deleted file mode 100644 index 62ecb4d092..0000000000 --- a/docs/references/cdi/oauth/get-well-known-jwks.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get well-known JWT keys -sidebar_label: get Get well-known JWT keys -sidebar_position: 1 -description: 'GET /appid-{appId}/.well-known/jwks.json endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/meta.ts b/docs/references/cdi/oauth/meta.ts new file mode 100644 index 0000000000..6e07606eaf --- /dev/null +++ b/docs/references/cdi/oauth/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "OAuth", + "icon": "key-round", + "order": 9 +}); diff --git a/docs/references/cdi/oauth/post-oauth2-client-remove.mdx b/docs/references/cdi/oauth/post-oauth2-client-remove.mdx deleted file mode 100644 index 48f8f92650..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-client-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Remove OAuth2 Client -sidebar_label: post Remove OAuth2 Client -sidebar_position: 10 -description: >- - POST /appid-{appId}/recipe/oauth/clients/remove endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-client.mdx b/docs/references/cdi/oauth/post-oauth2-client.mdx deleted file mode 100644 index bbf0fb4c05..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-client.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Create OAuth2 Client -sidebar_label: post Create OAuth2 Client -sidebar_position: 9 -description: 'POST /appid-{appId}/recipe/oauth/clients endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-consent-request-accept.mdx b/docs/references/cdi/oauth/post-oauth2-consent-request-accept.mdx deleted file mode 100644 index be5e47af42..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-consent-request-accept.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Accept OAuth2 Consent Request -sidebar_label: put Accept OAuth2 Consent Request -sidebar_position: 16 -description: >- - PUT /appid-{appId}/recipe/oauth/auth/requests/consent/accept endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-consent-request-reject.mdx b/docs/references/cdi/oauth/post-oauth2-consent-request-reject.mdx deleted file mode 100644 index d63bc2791a..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-consent-request-reject.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Reject OAuth2 Consent Request -sidebar_label: put Reject OAuth2 Consent Request -sidebar_position: 17 -description: >- - PUT /appid-{appId}/recipe/oauth/auth/requests/consent/reject endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-login-request-accept.mdx b/docs/references/cdi/oauth/post-oauth2-login-request-accept.mdx deleted file mode 100644 index fa99f5b352..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-login-request-accept.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Accept OAuth2 Login Request -sidebar_label: put Accept OAuth2 Login Request -sidebar_position: 18 -description: >- - PUT /appid-{appId}/recipe/oauth/auth/requests/login/accept endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-login-request-reject.mdx b/docs/references/cdi/oauth/post-oauth2-login-request-reject.mdx deleted file mode 100644 index 0f79d699a4..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-login-request-reject.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Reject OAuth2 Login Request -sidebar_label: put Reject OAuth2 Login Request -sidebar_position: 19 -description: >- - PUT /appid-{appId}/recipe/oauth/auth/requests/login/reject endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-logout-request-accept.mdx b/docs/references/cdi/oauth/post-oauth2-logout-request-accept.mdx deleted file mode 100644 index d3b4491ea4..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-logout-request-accept.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Accept OAuth2 Logout Request -sidebar_label: put Accept OAuth2 Logout Request -sidebar_position: 20 -description: >- - PUT /appid-{appId}/recipe/oauth/auth/requests/logout/accept endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-logout-request-reject.mdx b/docs/references/cdi/oauth/post-oauth2-logout-request-reject.mdx deleted file mode 100644 index 0ece7aa2d2..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-logout-request-reject.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Reject OAuth2 Logout Request -sidebar_label: put Reject OAuth2 Logout Request -sidebar_position: 21 -description: >- - PUT /appid-{appId}/recipe/oauth/auth/requests/logout/reject endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-session-revoke.mdx b/docs/references/cdi/oauth/post-oauth2-session-revoke.mdx deleted file mode 100644 index 54269159c4..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-session-revoke.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Revoke OAuth2 Session -sidebar_label: post Revoke OAuth2 Session -sidebar_position: 12 -description: >- - POST /appid-{appId}/recipe/oauth/session/revoke endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-token-introspect.mdx b/docs/references/cdi/oauth/post-oauth2-token-introspect.mdx deleted file mode 100644 index 881734431f..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-token-introspect.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Introspect OAuth2 Token -sidebar_label: post Introspect OAuth2 Token -sidebar_position: 11 -description: 'POST /appid-{appId}/recipe/oauth/introspect endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-token-revoke.mdx b/docs/references/cdi/oauth/post-oauth2-token-revoke.mdx deleted file mode 100644 index d74b279845..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-token-revoke.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Revoke OAuth2 Token -sidebar_label: post Revoke OAuth2 Token -sidebar_position: 14 -description: 'POST /appid-{appId}/recipe/oauth/token/revoke endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/post-oauth2-tokens-revoke.mdx b/docs/references/cdi/oauth/post-oauth2-tokens-revoke.mdx deleted file mode 100644 index 7f1aa4e42c..0000000000 --- a/docs/references/cdi/oauth/post-oauth2-tokens-revoke.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Revoke OAuth2 Token -sidebar_label: post Revoke OAuth2 Token -sidebar_position: 15 -description: 'POST /appid-{appId}/recipe/oauth/tokens/revoke endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/oauth/put-oauth2-client.mdx b/docs/references/cdi/oauth/put-oauth2-client.mdx deleted file mode 100644 index 91e70d0be7..0000000000 --- a/docs/references/cdi/oauth/put-oauth2-client.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Update OAuth2 Client -sidebar_label: put Update OAuth2 Client -sidebar_position: 22 -description: 'PUT /appid-{appId}/recipe/oauth/clients endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/passwordless/_category_.json b/docs/references/cdi/passwordless/_category_.json deleted file mode 100644 index 12cacdc38f..0000000000 --- a/docs/references/cdi/passwordless/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Passwordless", - "position": 10 -} diff --git a/docs/references/cdi/passwordless/get-signinup-codes.mdx b/docs/references/cdi/passwordless/get-signinup-codes.mdx deleted file mode 100644 index d48719f07b..0000000000 --- a/docs/references/cdi/passwordless/get-signinup-codes.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: List passwordless codes -sidebar_label: get List passwordless codes -sidebar_position: 1 -description: >- - GET /appid-{appId}/{tenantId}/recipe/signinup/codes endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/passwordless/get-user.mdx b/docs/references/cdi/passwordless/get-user.mdx deleted file mode 100644 index f5063cec9c..0000000000 --- a/docs/references/cdi/passwordless/get-user.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get passwordless user -sidebar_label: get Get passwordless user (deprecated) -sidebar_position: 2 -description: 'GET /appid-{appId}/{tenantId}/recipe/user ⠀ endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/passwordless/meta.ts b/docs/references/cdi/passwordless/meta.ts new file mode 100644 index 0000000000..21a6e16efb --- /dev/null +++ b/docs/references/cdi/passwordless/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Passwordless", + "icon": "wand-sparkles", + "order": 10 +}); diff --git a/docs/references/cdi/passwordless/post-signinup-code-check.mdx b/docs/references/cdi/passwordless/post-signinup-code-check.mdx deleted file mode 100644 index 0dbeee6777..0000000000 --- a/docs/references/cdi/passwordless/post-signinup-code-check.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Check passwordless code -sidebar_label: post Check passwordless code -sidebar_position: 4 -description: >- - POST /appid-{appId}/{tenantId}/recipe/signinup/code/check endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/passwordless/post-signinup-code-consume.mdx b/docs/references/cdi/passwordless/post-signinup-code-consume.mdx deleted file mode 100644 index fdc5d9310d..0000000000 --- a/docs/references/cdi/passwordless/post-signinup-code-consume.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Consume passwordless code -sidebar_label: post Consume passwordless code -sidebar_position: 5 -description: >- - POST /appid-{appId}/{tenantId}/recipe/signinup/code/consume endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/passwordless/post-signinup-code-remove.mdx b/docs/references/cdi/passwordless/post-signinup-code-remove.mdx deleted file mode 100644 index 71cc60e2b3..0000000000 --- a/docs/references/cdi/passwordless/post-signinup-code-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Revoke passwordless code -sidebar_label: post Revoke passwordless code -sidebar_position: 6 -description: >- - POST /appid-{appId}/{tenantId}/recipe/signinup/code/remove endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/passwordless/post-signinup-code.mdx b/docs/references/cdi/passwordless/post-signinup-code.mdx deleted file mode 100644 index 8a039ffdb9..0000000000 --- a/docs/references/cdi/passwordless/post-signinup-code.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Start passwordless sign in -sidebar_label: post Start passwordless sign in -sidebar_position: 3 -description: >- - POST /appid-{appId}/{tenantId}/recipe/signinup/code endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/passwordless/post-signinup-codes-remove.mdx b/docs/references/cdi/passwordless/post-signinup-codes-remove.mdx deleted file mode 100644 index f1bbff496f..0000000000 --- a/docs/references/cdi/passwordless/post-signinup-codes-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Revoke all user codes -sidebar_label: post Revoke all user codes -sidebar_position: 7 -description: >- - POST /appid-{appId}/{tenantId}/recipe/signinup/codes/remove endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/passwordless/put-user.mdx b/docs/references/cdi/passwordless/put-user.mdx deleted file mode 100644 index b26473eb87..0000000000 --- a/docs/references/cdi/passwordless/put-user.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Update passwordless user -sidebar_label: put Update passwordless user -sidebar_position: 8 -description: 'PUT /appid-{appId}/{tenantId}/recipe/user ⠀ endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/_category_.json b/docs/references/cdi/session/_category_.json deleted file mode 100644 index afa4a5a155..0000000000 --- a/docs/references/cdi/session/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Session", - "position": 11 -} diff --git a/docs/references/cdi/session/get-jwt-data.mdx b/docs/references/cdi/session/get-jwt-data.mdx deleted file mode 100644 index 96ce5b664b..0000000000 --- a/docs/references/cdi/session/get-jwt-data.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get JWT data -sidebar_label: get Get JWT data (deprecated) -sidebar_position: 1 -description: 'GET `/appid-{appId}/{tenantId}/recipe/jwt/data` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/get-session-data.mdx b/docs/references/cdi/session/get-session-data.mdx deleted file mode 100644 index e393595e97..0000000000 --- a/docs/references/cdi/session/get-session-data.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get session data -sidebar_label: get Get session data (deprecated) -sidebar_position: 4 -description: 'GET `/appid-{appId}/recipe/session/data` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/get-session-user.mdx b/docs/references/cdi/session/get-session-user.mdx deleted file mode 100644 index 791dd10b69..0000000000 --- a/docs/references/cdi/session/get-session-user.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get user session handles -sidebar_label: get Get user session handles -sidebar_position: 2 -description: >- - GET /appid-{appId}/{tenantId}/recipe/session/user endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/get-session.mdx b/docs/references/cdi/session/get-session.mdx deleted file mode 100644 index 48d3fb8fc3..0000000000 --- a/docs/references/cdi/session/get-session.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get session info -sidebar_label: get Get session info -sidebar_position: 3 -description: 'GET `/appid-{appId}/recipe/session` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/meta.ts b/docs/references/cdi/session/meta.ts new file mode 100644 index 0000000000..128805b149 --- /dev/null +++ b/docs/references/cdi/session/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Session", + "icon": "clock-3", + "order": 11 +}); diff --git a/docs/references/cdi/session/post-jwt.mdx b/docs/references/cdi/session/post-jwt.mdx deleted file mode 100644 index 61bafaf31e..0000000000 --- a/docs/references/cdi/session/post-jwt.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Create signed JWT -sidebar_label: post Create signed JWT -sidebar_position: 7 -description: 'POST `/appid-{appId}/recipe/jwt` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/post-session-refresh.mdx b/docs/references/cdi/session/post-session-refresh.mdx deleted file mode 100644 index cf0344924b..0000000000 --- a/docs/references/cdi/session/post-session-refresh.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Refresh session -sidebar_label: post Refresh session -sidebar_position: 8 -description: 'POST `/appid-{appId}/recipe/session/refresh` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/post-session-regenerate.mdx b/docs/references/cdi/session/post-session-regenerate.mdx deleted file mode 100644 index f9ac5e8920..0000000000 --- a/docs/references/cdi/session/post-session-regenerate.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Regenerate session -sidebar_label: post Regenerate session -sidebar_position: 9 -description: 'POST `/appid-{appId}/recipe/session/regenerate` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/post-session-remove.mdx b/docs/references/cdi/session/post-session-remove.mdx deleted file mode 100644 index 48fb235413..0000000000 --- a/docs/references/cdi/session/post-session-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Delete session -sidebar_label: post Delete session -sidebar_position: 6 -description: >- - POST /appid-{appId}/{tenantId}/recipe/session/remove endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/post-session-verify.mdx b/docs/references/cdi/session/post-session-verify.mdx deleted file mode 100644 index b463292a74..0000000000 --- a/docs/references/cdi/session/post-session-verify.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Verify session -sidebar_label: post Verify session -sidebar_position: 10 -description: 'POST `/appid-{appId}/recipe/session/verify` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/post-session.mdx b/docs/references/cdi/session/post-session.mdx deleted file mode 100644 index 2fce833b61..0000000000 --- a/docs/references/cdi/session/post-session.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Create new session -sidebar_label: post Create new session -sidebar_position: 5 -description: 'POST `/appid-{appId}/{tenantId}/recipe/session` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/put-jwt-data.mdx b/docs/references/cdi/session/put-jwt-data.mdx deleted file mode 100644 index 6984e8aca7..0000000000 --- a/docs/references/cdi/session/put-jwt-data.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Update JWT data -sidebar_label: put Update JWT data -sidebar_position: 11 -description: 'PUT `/appid-{appId}/{tenantId}/recipe/jwt/data` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/session/put-session-data.mdx b/docs/references/cdi/session/put-session-data.mdx deleted file mode 100644 index 365b8afe56..0000000000 --- a/docs/references/cdi/session/put-session-data.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Update session data -sidebar_label: put Update session data -sidebar_position: 12 -description: 'PUT `/appid-{appId}/recipe/session/data` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/thirdparty/_category_.json b/docs/references/cdi/thirdparty/_category_.json deleted file mode 100644 index 1b293a57ec..0000000000 --- a/docs/references/cdi/thirdparty/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "ThirdParty", - "position": 12 -} diff --git a/docs/references/cdi/thirdparty/get-user.mdx b/docs/references/cdi/thirdparty/get-user.mdx deleted file mode 100644 index 32db0c12cd..0000000000 --- a/docs/references/cdi/thirdparty/get-user.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get third party user -sidebar_label: get Get third party user (deprecated) -sidebar_position: 1 -description: 'GET `/appid-{appId}/{tenantId}/recipe/user⠀` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/thirdparty/get-users-by-email.mdx b/docs/references/cdi/thirdparty/get-users-by-email.mdx deleted file mode 100644 index 7ad78bedf7..0000000000 --- a/docs/references/cdi/thirdparty/get-users-by-email.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get users by email -sidebar_label: get Get users by email (deprecated) -sidebar_position: 2 -description: >- - GET /appid-{appId}/{tenantId}/recipe/users/by-email endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/thirdparty/meta.ts b/docs/references/cdi/thirdparty/meta.ts new file mode 100644 index 0000000000..ceef54828e --- /dev/null +++ b/docs/references/cdi/thirdparty/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "ThirdParty", + "icon": "share-2", + "order": 12 +}); diff --git a/docs/references/cdi/thirdparty/post-signinup.mdx b/docs/references/cdi/thirdparty/post-signinup.mdx deleted file mode 100644 index 82ab8a7378..0000000000 --- a/docs/references/cdi/thirdparty/post-signinup.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Sign in/up third party user -sidebar_label: post Sign in/up third party user -sidebar_position: 3 -description: 'POST `/appid-{appId}/{tenantId}/recipe/signinup` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-metadata/_category_.json b/docs/references/cdi/user-metadata/_category_.json deleted file mode 100644 index 3b50cac88d..0000000000 --- a/docs/references/cdi/user-metadata/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "User Metadata", - "position": 13 -} diff --git a/docs/references/cdi/user-metadata/get-user-metadata.mdx b/docs/references/cdi/user-metadata/get-user-metadata.mdx deleted file mode 100644 index 4823c3c5e8..0000000000 --- a/docs/references/cdi/user-metadata/get-user-metadata.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get user metadata -sidebar_label: get Get user metadata -sidebar_position: 1 -description: 'GET `/appid-{appId}/recipe/user/metadata` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-metadata/meta.ts b/docs/references/cdi/user-metadata/meta.ts new file mode 100644 index 0000000000..a21c05c1c0 --- /dev/null +++ b/docs/references/cdi/user-metadata/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "User Metadata", + "icon": "braces", + "order": 13 +}); diff --git a/docs/references/cdi/user-metadata/post-user-metadata-remove.mdx b/docs/references/cdi/user-metadata/post-user-metadata-remove.mdx deleted file mode 100644 index bc8895ff69..0000000000 --- a/docs/references/cdi/user-metadata/post-user-metadata-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Remove user metadata -sidebar_label: post Remove user metadata -sidebar_position: 2 -description: >- - POST /appid-{appId}/recipe/user/metadata/remove endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-metadata/put-user-metadata.mdx b/docs/references/cdi/user-metadata/put-user-metadata.mdx deleted file mode 100644 index baf394c2c4..0000000000 --- a/docs/references/cdi/user-metadata/put-user-metadata.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Update user metadata -sidebar_label: put Update user metadata -sidebar_position: 3 -description: 'PUT `/appid-{appId}/recipe/user/metadata` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-roles/_category_.json b/docs/references/cdi/user-roles/_category_.json deleted file mode 100644 index c2d65ca895..0000000000 --- a/docs/references/cdi/user-roles/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "User Roles", - "position": 14 -} diff --git a/docs/references/cdi/user-roles/get-permission-roles.mdx b/docs/references/cdi/user-roles/get-permission-roles.mdx deleted file mode 100644 index 5cc99fa88b..0000000000 --- a/docs/references/cdi/user-roles/get-permission-roles.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get permission roles -sidebar_label: get Get permission roles -sidebar_position: 3 -description: 'GET `/appid-{appId}/recipe/permission/roles` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-roles/get-role-permissions.mdx b/docs/references/cdi/user-roles/get-role-permissions.mdx deleted file mode 100644 index 3fd85c7670..0000000000 --- a/docs/references/cdi/user-roles/get-role-permissions.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get role permissions -sidebar_label: get Get role permissions -sidebar_position: 4 -description: 'GET `/appid-{appId}/recipe/role/permissions` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-roles/get-role-users.mdx b/docs/references/cdi/user-roles/get-role-users.mdx deleted file mode 100644 index a80bc2a241..0000000000 --- a/docs/references/cdi/user-roles/get-role-users.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get users with role -sidebar_label: get Get users with role -sidebar_position: 1 -description: >- - GET /appid-{appId}/{tenantId}/recipe/role/users endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-roles/get-roles.mdx b/docs/references/cdi/user-roles/get-roles.mdx deleted file mode 100644 index 7f0681acca..0000000000 --- a/docs/references/cdi/user-roles/get-roles.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get all roles -sidebar_label: get Get all roles -sidebar_position: 5 -description: 'GET `/appid-{appId}/recipe/roles` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-roles/get-user-roles.mdx b/docs/references/cdi/user-roles/get-user-roles.mdx deleted file mode 100644 index d5838f5a98..0000000000 --- a/docs/references/cdi/user-roles/get-user-roles.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get user roles -sidebar_label: get Get user roles -sidebar_position: 2 -description: >- - GET /appid-{appId}/{tenantId}/recipe/user/roles endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-roles/meta.ts b/docs/references/cdi/user-roles/meta.ts new file mode 100644 index 0000000000..04b907f600 --- /dev/null +++ b/docs/references/cdi/user-roles/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "User Roles", + "icon": "shield-user", + "order": 14 +}); diff --git a/docs/references/cdi/user-roles/post-role-permissions-remove.mdx b/docs/references/cdi/user-roles/post-role-permissions-remove.mdx deleted file mode 100644 index 45a65dfc53..0000000000 --- a/docs/references/cdi/user-roles/post-role-permissions-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Remove role permissions -sidebar_label: post Remove role permissions -sidebar_position: 7 -description: >- - POST /appid-{appId}/recipe/role/permissions/remove endpoint exposed by the CDI - API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-roles/post-role-remove.mdx b/docs/references/cdi/user-roles/post-role-remove.mdx deleted file mode 100644 index 3036b00a87..0000000000 --- a/docs/references/cdi/user-roles/post-role-remove.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Delete role -sidebar_label: post Delete role -sidebar_position: 8 -description: 'POST `/appid-{appId}/recipe/role/remove` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-roles/post-user-role-remove.mdx b/docs/references/cdi/user-roles/post-user-role-remove.mdx deleted file mode 100644 index 694874c720..0000000000 --- a/docs/references/cdi/user-roles/post-user-role-remove.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Remove user role -sidebar_label: post Remove user role -sidebar_position: 6 -description: >- - POST /appid-{appId}/{tenantId}/recipe/user/role/remove endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-roles/put-role.mdx b/docs/references/cdi/user-roles/put-role.mdx deleted file mode 100644 index 53f52bab4a..0000000000 --- a/docs/references/cdi/user-roles/put-role.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Create or update role -sidebar_label: put Create or update role -sidebar_position: 10 -description: 'PUT `/appid-{appId}/recipe/role` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/user-roles/put-user-role.mdx b/docs/references/cdi/user-roles/put-user-role.mdx deleted file mode 100644 index 41bd2d3b82..0000000000 --- a/docs/references/cdi/user-roles/put-user-role.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Add user role -sidebar_label: put Add user role -sidebar_position: 9 -description: 'PUT `/appid-{appId}/{tenantId}/recipe/user/role` endpoint exposed by the CDI API' -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/_category_.json b/docs/references/cdi/webauthn/_category_.json deleted file mode 100644 index 14492eeddd..0000000000 --- a/docs/references/cdi/webauthn/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "WebAuthn", - "position": 15 -} diff --git a/docs/references/cdi/webauthn/delete-webauthn-credential.mdx b/docs/references/cdi/webauthn/delete-webauthn-credential.mdx deleted file mode 100644 index 493e002938..0000000000 --- a/docs/references/cdi/webauthn/delete-webauthn-credential.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Remove WebAuthn credential -sidebar_label: delete Remove WebAuthn credential -sidebar_position: 14 -description: >- - DELETE /appid-{appId}/{tenantId}/recipe/webauthn/user/credential/remove - endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/delete-webauthn-options.mdx b/docs/references/cdi/webauthn/delete-webauthn-options.mdx deleted file mode 100644 index fddcbc8c00..0000000000 --- a/docs/references/cdi/webauthn/delete-webauthn-options.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Remove WebAuthn options -sidebar_label: delete Remove WebAuthn options -sidebar_position: 13 -description: >- - DELETE /appid-{appId}/{tenantId}/recipe/webauthn/options/remove endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/get-webauthn-credential.mdx b/docs/references/cdi/webauthn/get-webauthn-credential.mdx deleted file mode 100644 index aabda2a243..0000000000 --- a/docs/references/cdi/webauthn/get-webauthn-credential.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get WebAuthn credential -sidebar_label: get Get WebAuthn credential -sidebar_position: 2 -description: >- - GET /appid-{appId}/{tenantId}/recipe/webauthn/user/credential endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/get-webauthn-credentials.mdx b/docs/references/cdi/webauthn/get-webauthn-credentials.mdx deleted file mode 100644 index 2ab0db8c68..0000000000 --- a/docs/references/cdi/webauthn/get-webauthn-credentials.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: List WebAuthn credentials -sidebar_label: get List WebAuthn credentials -sidebar_position: 3 -description: >- - GET /appid-{appId}/{tenantId}/recipe/webauthn/user/credential/list endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/get-webauthn-options.mdx b/docs/references/cdi/webauthn/get-webauthn-options.mdx deleted file mode 100644 index 0e85f2cf5d..0000000000 --- a/docs/references/cdi/webauthn/get-webauthn-options.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get WebAuthn options -sidebar_label: get Get WebAuthn options -sidebar_position: 1 -description: >- - GET /appid-{appId}/{tenantId}/recipe/webauthn/options endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/meta.ts b/docs/references/cdi/webauthn/meta.ts new file mode 100644 index 0000000000..e05c0c31e4 --- /dev/null +++ b/docs/references/cdi/webauthn/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "WebAuthn", + "icon": "fingerprint", + "order": 15 +}); diff --git a/docs/references/cdi/webauthn/post-webauthn-recover.mdx b/docs/references/cdi/webauthn/post-webauthn-recover.mdx deleted file mode 100644 index 882b7a73ee..0000000000 --- a/docs/references/cdi/webauthn/post-webauthn-recover.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Recover WebAuthn user -sidebar_label: get Recover WebAuthn user -sidebar_position: 4 -description: >- - GET /appid-{appId}/{tenantId}/recipe/webauthn/user/recover endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/post-webauthn-register.mdx b/docs/references/cdi/webauthn/post-webauthn-register.mdx deleted file mode 100644 index 19ab7996f7..0000000000 --- a/docs/references/cdi/webauthn/post-webauthn-register.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Register WebAuthn credential -sidebar_label: post Register WebAuthn credential -sidebar_position: 9 -description: >- - POST /appid-{appId}/{tenantId}/recipe/webauthn/user/credential/register - endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/post-webauthn-registration-options.mdx b/docs/references/cdi/webauthn/post-webauthn-registration-options.mdx deleted file mode 100644 index 0716659d87..0000000000 --- a/docs/references/cdi/webauthn/post-webauthn-registration-options.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Generate registration options -sidebar_label: post Generate registration options -sidebar_position: 5 -description: >- - POST /appid-{appId}/{tenantId}/recipe/webauthn/options/register endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/post-webauthn-signin-options.mdx b/docs/references/cdi/webauthn/post-webauthn-signin-options.mdx deleted file mode 100644 index 0c952a15b5..0000000000 --- a/docs/references/cdi/webauthn/post-webauthn-signin-options.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Generate authentication options -sidebar_label: post Generate authentication options -sidebar_position: 6 -description: >- - POST /appid-{appId}/{tenantId}/recipe/webauthn/options/signin endpoint exposed - by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/post-webauthn-signin.mdx b/docs/references/cdi/webauthn/post-webauthn-signin.mdx deleted file mode 100644 index d92ccd8124..0000000000 --- a/docs/references/cdi/webauthn/post-webauthn-signin.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Sign in WebAuthn user -sidebar_label: post Sign in WebAuthn user -sidebar_position: 7 -description: >- - POST /appid-{appId}/{tenantId}/recipe/webauthn/signin endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/post-webauthn-signup.mdx b/docs/references/cdi/webauthn/post-webauthn-signup.mdx deleted file mode 100644 index e908dc8789..0000000000 --- a/docs/references/cdi/webauthn/post-webauthn-signup.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Sign up WebAuthn user -sidebar_label: post Sign up WebAuthn user -sidebar_position: 8 -description: >- - POST /appid-{appId}/{tenantId}/recipe/webauthn/signup endpoint exposed by the - CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/post-webauthn-token-consume.mdx b/docs/references/cdi/webauthn/post-webauthn-token-consume.mdx deleted file mode 100644 index 49ddadc3fd..0000000000 --- a/docs/references/cdi/webauthn/post-webauthn-token-consume.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Consume recovery token -sidebar_label: post Consume recovery token -sidebar_position: 11 -description: >- - POST /appid-{appId}/{tenantId}/recipe/webauthn/user/recover/token/consume - endpoint exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/post-webauthn-token-recovery.mdx b/docs/references/cdi/webauthn/post-webauthn-token-recovery.mdx deleted file mode 100644 index 70703160e4..0000000000 --- a/docs/references/cdi/webauthn/post-webauthn-token-recovery.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Generate recovery token -sidebar_label: post Generate recovery token -sidebar_position: 10 -description: >- - POST /appid-{appId}/{tenantId}/recipe/webauthn/user/recover/token endpoint - exposed by the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/cdi/webauthn/put-webauthn-email.mdx b/docs/references/cdi/webauthn/put-webauthn-email.mdx deleted file mode 100644 index 40233be857..0000000000 --- a/docs/references/cdi/webauthn/put-webauthn-email.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Update email -sidebar_label: put Update email -sidebar_position: 12 -description: >- - PUT /appid-{appId}/{tenantId}/recipe/webauthn/user/email endpoint exposed by - the CDI API -page_type: api-reference -hide_title: true -category: cdi ---- - - diff --git a/docs/references/compatibility-table.mdx b/docs/references/compatibility-table.mdx index 7219c8e6cd..0fe8b87ba6 100644 --- a/docs/references/compatibility-table.mdx +++ b/docs/references/compatibility-table.mdx @@ -1,21 +1,12 @@ --- title: SDK Compatibility Table -hide_title: true -hide_table_of_contents: true -sidebar_position: 9 -pagination_next: null -pagination_prev: null description: Find the compatible SDK/Core version for your specific tech stack. -page_type: overview -category: references +sidebar: + order: 9 --- - -# SDK compatibility table - - This page helps you find the right version of an SDK/Core given your tech stack. If you are starting out, **you do not need to use this page**. -Instead, you can use the [Quickstart](/docs/quickstart/introduction) to get started. +Instead, you can use the [Quickstart](/quickstart/introduction) to get started. diff --git a/docs/references/fdi/_category_.json b/docs/references/fdi/_category_.json deleted file mode 100644 index c175e4b97d..0000000000 --- a/docs/references/fdi/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Frontend Driver Interface", - "customProps": { "isMainCategory": true }, - "position": 4 -} diff --git a/docs/references/fdi/email-password/_category_.json b/docs/references/fdi/email-password/_category_.json deleted file mode 100644 index 11510dbb2c..0000000000 --- a/docs/references/fdi/email-password/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Email/Password", - "position": 2 -} diff --git a/docs/references/fdi/email-password/get-emailpassword-email-exists.mdx b/docs/references/fdi/email-password/get-emailpassword-email-exists.mdx deleted file mode 100644 index 40a92e4bd6..0000000000 --- a/docs/references/fdi/email-password/get-emailpassword-email-exists.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Check email exists -sidebar_label: get Check email exists -sidebar_position: 1 -description: >- - GET /{apiBasePath}/{tenantId}/emailpassword/email/exists endpoint exposed by - the FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/email-password/get-signup-email-exists.mdx b/docs/references/fdi/email-password/get-signup-email-exists.mdx deleted file mode 100644 index e6e956c88d..0000000000 --- a/docs/references/fdi/email-password/get-signup-email-exists.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Check email exists (deprecated) -sidebar_label: get Check email exists (deprecated) (deprecated) -sidebar_position: 2 -description: >- - GET /{apiBasePath}/{tenantId}/signup/email/exists endpoint exposed by the FDI - API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/email-password/meta.ts b/docs/references/fdi/email-password/meta.ts new file mode 100644 index 0000000000..7e4efd766f --- /dev/null +++ b/docs/references/fdi/email-password/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Email/Password", + "icon": "rectangle-ellipsis", + "order": 2 +}); diff --git a/docs/references/fdi/email-password/post-signin.mdx b/docs/references/fdi/email-password/post-signin.mdx deleted file mode 100644 index fe6bc0b2b6..0000000000 --- a/docs/references/fdi/email-password/post-signin.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Sign in with email -sidebar_label: post Sign in with email -sidebar_position: 3 -description: 'POST `/{apiBasePath}/{tenantId}/signin` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/email-password/post-signup.mdx b/docs/references/fdi/email-password/post-signup.mdx deleted file mode 100644 index 9f281315be..0000000000 --- a/docs/references/fdi/email-password/post-signup.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Sign up with email -sidebar_label: post Sign up with email -sidebar_position: 4 -description: 'POST `/{apiBasePath}/{tenantId}/signup` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/email-password/post-user-password-reset-token.mdx b/docs/references/fdi/email-password/post-user-password-reset-token.mdx deleted file mode 100644 index 442063c908..0000000000 --- a/docs/references/fdi/email-password/post-user-password-reset-token.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Generate password reset token -sidebar_label: post Generate password reset token -sidebar_position: 6 -description: >- - POST /{apiBasePath}/{tenantId}/user/password/reset/token endpoint exposed by - the FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/email-password/post-user-password-reset.mdx b/docs/references/fdi/email-password/post-user-password-reset.mdx deleted file mode 100644 index 99446dbfcd..0000000000 --- a/docs/references/fdi/email-password/post-user-password-reset.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Reset user password -sidebar_label: post Reset user password -sidebar_position: 5 -description: >- - POST /{apiBasePath}/{tenantId}/user/password/reset endpoint exposed by the FDI - API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/email-verification/_category_.json b/docs/references/fdi/email-verification/_category_.json deleted file mode 100644 index 9ce848b736..0000000000 --- a/docs/references/fdi/email-verification/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Email Verification", - "position": 1 -} diff --git a/docs/references/fdi/email-verification/get-user-email-verify.mdx b/docs/references/fdi/email-verification/get-user-email-verify.mdx deleted file mode 100644 index ed12b68fb0..0000000000 --- a/docs/references/fdi/email-verification/get-user-email-verify.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Check email verification status -sidebar_label: get Check email verification status -sidebar_position: 1 -description: 'GET `/{apiBasePath}/user/email/verify` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/email-verification/meta.ts b/docs/references/fdi/email-verification/meta.ts new file mode 100644 index 0000000000..03d4af72f5 --- /dev/null +++ b/docs/references/fdi/email-verification/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Email Verification", + "icon": "mail-check", + "order": 1 +}); diff --git a/docs/references/fdi/email-verification/post-user-email-verify-token.mdx b/docs/references/fdi/email-verification/post-user-email-verify-token.mdx deleted file mode 100644 index 6ffb642725..0000000000 --- a/docs/references/fdi/email-verification/post-user-email-verify-token.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Send email verification -sidebar_label: post Send email verification -sidebar_position: 3 -description: >- - POST /{apiBasePath}/{tenantId}/user/email/verify/token endpoint exposed by the - FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/email-verification/post-user-email-verify.mdx b/docs/references/fdi/email-verification/post-user-email-verify.mdx deleted file mode 100644 index ebd459825c..0000000000 --- a/docs/references/fdi/email-verification/post-user-email-verify.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Verify email address -sidebar_label: post Verify email address -sidebar_position: 2 -description: >- - POST /{apiBasePath}/{tenantId}/user/email/verify endpoint exposed by the FDI - API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/get-example.mdx b/docs/references/fdi/get-example.mdx deleted file mode 100644 index 7b5f75b367..0000000000 --- a/docs/references/fdi/get-example.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Test authentication -sidebar_label: get Test authentication -sidebar_position: 9.5 -description: GET `/example` endpoint exposed by the FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/get-jwt-jwks-json.mdx b/docs/references/fdi/get-jwt-jwks-json.mdx deleted file mode 100644 index c9f11ccf78..0000000000 --- a/docs/references/fdi/get-jwt-jwks-json.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get JWT keys -sidebar_label: get Get JWT keys -sidebar_position: 9.2 -description: 'GET `/{apiBasePath}/jwt/jwks.json` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/get-loginmethods.mdx b/docs/references/fdi/get-loginmethods.mdx deleted file mode 100644 index d2b412ed70..0000000000 --- a/docs/references/fdi/get-loginmethods.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get enabled login methods -sidebar_label: get Get enabled login methods -sidebar_position: 9.1 -description: 'GET `/{apiBasePath}/{tenantId}/loginmethods` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/get-well-known-openid-configuration.mdx b/docs/references/fdi/get-well-known-openid-configuration.mdx deleted file mode 100644 index 2e989c61d7..0000000000 --- a/docs/references/fdi/get-well-known-openid-configuration.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get OpenID config -sidebar_label: get Get OpenID config -sidebar_position: 9.4 -description: >- - GET /{apiBasePath}/.well-known/openid-configuration endpoint exposed by the - FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/introduction.mdx b/docs/references/fdi/introduction.mdx index 8991988d39..b140019559 100644 --- a/docs/references/fdi/introduction.mdx +++ b/docs/references/fdi/introduction.mdx @@ -1,26 +1,17 @@ --- title: Introduction -hide_title: true -sidebar_position: 0.1 -description: >- - Access detailed API specifications for integrating with SuperTokens Core and - frontend SDKs. -pagination_prev: null -pagination_next: null -page_type: overview -category: fdi +description: Access detailed API specifications for integrating with SuperTokens Core and frontend SDKs. +sidebar: + order: 0.1 --- -# Frontend Driver Interface - - ## Overview The **FDI**, Frontend Driver Interface, is the API exposed by the **SuperTokens Backend SDKs**. It is meant to be consumed only by your frontend applications. -:::info no-title -In most cases, you don't need to directly interact with the API, since the existing [frontend SDKS](/docs/references/backend-sdks/reference) are built on top of it. +:::info +In most cases, you don't need to directly interact with the API, since the existing [frontend SDKS](/references/backend-sdks/reference) are built on top of it. If you are using something that does not have SDK support, then you can make use of the FDI resources. ::: @@ -28,11 +19,11 @@ If you are using something that does not have SDK support, then you can make use ### URL Structure All the endpoints are prefixed with `{apiBasePath}`. -This is the property with the same name that you set during [backend SDK initialization](/docs/quickstart/backend-setup#2-initialize-the-sdk). +This is the property with the same name that you set during [backend SDK initialization](/quickstart/backend-setup#2-initialize-the-sdk). Tenant specific actions include a `{tenantId}` parameter. If not set, the default tenant will be used. -Given the following endpoint: `/{apiBasePath}/{tenantId}/signinup`, and the `apiBasePath` set to `auth` during [initialization](/docs/quickstart/backend-setup#2-initialize-the-sdk): +Given the following endpoint: `/{apiBasePath}/{tenantId}/signinup`, and the `apiBasePath` set to `auth` during [initialization](/quickstart/backend-setup#2-initialize-the-sdk): - You can call it without the actual parameter, using `/auth/signinup` in your action. - You can set the values to target a specific tenant: `/auth/myTenant/signinup`. @@ -53,6 +44,4 @@ To know which version you should see: Since this API allows users to sign up or login, most of the endpoints do not require any type of credentials. However, in some situations you have to authenticate your requests. In those cases, you need to choose between using cookies or headers. -The method that you have to use depends on the [token transfer method](/docs/post-authentication/session-management/switch-between-cookies-and-header-authentication) used in your application. - - +The method that you have to use depends on the [token transfer method](/post-authentication/session-management/switch-between-cookies-and-header-authentication) used in your application. diff --git a/docs/references/fdi/meta.ts b/docs/references/fdi/meta.ts new file mode 100644 index 0000000000..704b9db4aa --- /dev/null +++ b/docs/references/fdi/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Frontend Driver Interface", + "icon": "file-code-2", + "order": 4 +}); diff --git a/docs/references/fdi/mfa/_category_.json b/docs/references/fdi/mfa/_category_.json deleted file mode 100644 index 0b63ac877d..0000000000 --- a/docs/references/fdi/mfa/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "MFA", - "position": 3 -} diff --git a/docs/references/fdi/mfa/get-totp-device-list.mdx b/docs/references/fdi/mfa/get-totp-device-list.mdx deleted file mode 100644 index 6c169870a2..0000000000 --- a/docs/references/fdi/mfa/get-totp-device-list.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: List TOTP devices -sidebar_label: get List TOTP devices -sidebar_position: 1 -description: 'GET `/{apiBasePath}/totp/device/list` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/mfa/meta.ts b/docs/references/fdi/mfa/meta.ts new file mode 100644 index 0000000000..8c1afb71e2 --- /dev/null +++ b/docs/references/fdi/mfa/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "MFA", + "icon": "shield-check", + "order": 3 +}); diff --git a/docs/references/fdi/mfa/post-totp-device-remove.mdx b/docs/references/fdi/mfa/post-totp-device-remove.mdx deleted file mode 100644 index d56df888a0..0000000000 --- a/docs/references/fdi/mfa/post-totp-device-remove.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Remove TOTP device -sidebar_label: post Remove TOTP device -sidebar_position: 3 -description: 'POST `/{apiBasePath}/totp/device/remove` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/mfa/post-totp-device-verify.mdx b/docs/references/fdi/mfa/post-totp-device-verify.mdx deleted file mode 100644 index 45567b0abf..0000000000 --- a/docs/references/fdi/mfa/post-totp-device-verify.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Verify TOTP device -sidebar_label: post Verify TOTP device -sidebar_position: 4 -description: 'POST `/{apiBasePath}/totp/device/verify` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/mfa/post-totp-device.mdx b/docs/references/fdi/mfa/post-totp-device.mdx deleted file mode 100644 index f068fccfa0..0000000000 --- a/docs/references/fdi/mfa/post-totp-device.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Create TOTP device -sidebar_label: post Create TOTP device -sidebar_position: 2 -description: 'POST `/{apiBasePath}/totp/device` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/mfa/post-totp-verify.mdx b/docs/references/fdi/mfa/post-totp-verify.mdx deleted file mode 100644 index 1f15527a7e..0000000000 --- a/docs/references/fdi/mfa/post-totp-verify.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Verify TOTP code -sidebar_label: post Verify TOTP code -sidebar_position: 5 -description: 'POST `/{apiBasePath}/totp/verify` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/mfa/put-mfa-info.mdx b/docs/references/fdi/mfa/put-mfa-info.mdx deleted file mode 100644 index 2e5e5ef949..0000000000 --- a/docs/references/fdi/mfa/put-mfa-info.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get MFA factors information -sidebar_label: put Get MFA factors information -sidebar_position: 6 -description: 'PUT `/{apiBasePath}/mfa/info` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/oauth/_category_.json b/docs/references/fdi/oauth/_category_.json deleted file mode 100644 index 220c6d8ae0..0000000000 --- a/docs/references/fdi/oauth/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "OAuth", - "position": 4 -} diff --git a/docs/references/fdi/oauth/get-oauth-auth.mdx b/docs/references/fdi/oauth/get-oauth-auth.mdx deleted file mode 100644 index b566b11c25..0000000000 --- a/docs/references/fdi/oauth/get-oauth-auth.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Start OAuth login -sidebar_label: get Start OAuth login -sidebar_position: 1 -description: 'GET `/{apiBasePath}/oauth/auth` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/oauth/get-oauth-end_session.mdx b/docs/references/fdi/oauth/get-oauth-end_session.mdx deleted file mode 100644 index 6246a2c00d..0000000000 --- a/docs/references/fdi/oauth/get-oauth-end_session.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: End session redirect -sidebar_label: get End session redirect -sidebar_position: 2 -description: 'GET `/{apiBasePath}/oauth/end_session` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/oauth/get-oauth-login.mdx b/docs/references/fdi/oauth/get-oauth-login.mdx deleted file mode 100644 index 0cfde09ab5..0000000000 --- a/docs/references/fdi/oauth/get-oauth-login.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Continue OAuth login -sidebar_label: get Continue OAuth login -sidebar_position: 3 -description: 'GET `/{apiBasePath}/oauth/login` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/oauth/get-oauth-logininfo.mdx b/docs/references/fdi/oauth/get-oauth-logininfo.mdx deleted file mode 100644 index dd7f78c766..0000000000 --- a/docs/references/fdi/oauth/get-oauth-logininfo.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get OAuth login info -sidebar_label: get Get OAuth login info -sidebar_position: 4 -description: 'GET `/{apiBasePath}/oauth/logininfo` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/oauth/get-oauth-userinfo.mdx b/docs/references/fdi/oauth/get-oauth-userinfo.mdx deleted file mode 100644 index c4f7d9ef73..0000000000 --- a/docs/references/fdi/oauth/get-oauth-userinfo.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get OAuth user info -sidebar_label: get Get OAuth user info -sidebar_position: 5 -description: 'GET `/{apiBasePath}/oauth/userinfo` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/oauth/meta.ts b/docs/references/fdi/oauth/meta.ts new file mode 100644 index 0000000000..1befa5a9d0 --- /dev/null +++ b/docs/references/fdi/oauth/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "OAuth", + "icon": "key-round", + "order": 4 +}); diff --git a/docs/references/fdi/oauth/post-oauth-end_session.mdx b/docs/references/fdi/oauth/post-oauth-end_session.mdx deleted file mode 100644 index f8cdbe0d78..0000000000 --- a/docs/references/fdi/oauth/post-oauth-end_session.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: End OAuth session -sidebar_label: post End OAuth session -sidebar_position: 6 -description: 'POST `/{apiBasePath}/oauth/end_session` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/oauth/post-oauth-introspect.mdx b/docs/references/fdi/oauth/post-oauth-introspect.mdx deleted file mode 100644 index 5da6c7b16e..0000000000 --- a/docs/references/fdi/oauth/post-oauth-introspect.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Introspect OAuth token -sidebar_label: post Introspect OAuth token -sidebar_position: 7 -description: 'POST `/{apiBasePath}/oauth/introspect` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/oauth/post-oauth-logout.mdx b/docs/references/fdi/oauth/post-oauth-logout.mdx deleted file mode 100644 index 3b9cac51de..0000000000 --- a/docs/references/fdi/oauth/post-oauth-logout.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Logout OAuth user -sidebar_label: post Logout OAuth user -sidebar_position: 8 -description: 'POST `/{apiBasePath}/oauth/logout` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/oauth/post-oauth-revoke.mdx b/docs/references/fdi/oauth/post-oauth-revoke.mdx deleted file mode 100644 index 66d51f129a..0000000000 --- a/docs/references/fdi/oauth/post-oauth-revoke.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Revoke OAuth token -sidebar_label: post Revoke OAuth token -sidebar_position: 9 -description: 'POST `/{apiBasePath}/oauth/revoke` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/oauth/post-oauth-token.mdx b/docs/references/fdi/oauth/post-oauth-token.mdx deleted file mode 100644 index 607f1a614f..0000000000 --- a/docs/references/fdi/oauth/post-oauth-token.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Exchange OAuth grant -sidebar_label: post Exchange OAuth grant -sidebar_position: 10 -description: 'POST `/{apiBasePath}/oauth/token` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/passwordless/_category_.json b/docs/references/fdi/passwordless/_category_.json deleted file mode 100644 index 9d8d96266f..0000000000 --- a/docs/references/fdi/passwordless/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Passwordless", - "position": 5 -} diff --git a/docs/references/fdi/passwordless/get-passwordless-email-exists.mdx b/docs/references/fdi/passwordless/get-passwordless-email-exists.mdx deleted file mode 100644 index 78a8adc489..0000000000 --- a/docs/references/fdi/passwordless/get-passwordless-email-exists.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Check email exists -sidebar_label: get Check email exists -sidebar_position: 1 -description: >- - GET /{apiBasePath}/{tenantId}/passwordless/email/exists endpoint exposed by - the FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/passwordless/get-passwordless-phoneNumber-exists.mdx b/docs/references/fdi/passwordless/get-passwordless-phoneNumber-exists.mdx deleted file mode 100644 index 9156475538..0000000000 --- a/docs/references/fdi/passwordless/get-passwordless-phoneNumber-exists.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Check phone exists -sidebar_label: get Check phone exists -sidebar_position: 2 -description: >- - GET /{apiBasePath}/{tenantId}/passwordless/phoneNumber/exists endpoint exposed - by the FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/passwordless/get-signup-email-exists.mdx b/docs/references/fdi/passwordless/get-signup-email-exists.mdx deleted file mode 100644 index 2c1d61fb79..0000000000 --- a/docs/references/fdi/passwordless/get-signup-email-exists.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Check email exists (deprecated) -sidebar_label: get Check email exists (deprecated) (deprecated) -sidebar_position: 3 -description: >- - GET /{apiBasePath}/{tenantId}/signup/email/exists⠀⠀ endpoint exposed by the - FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/passwordless/get-signup-phoneNumber-exists.mdx b/docs/references/fdi/passwordless/get-signup-phoneNumber-exists.mdx deleted file mode 100644 index 5629b3366f..0000000000 --- a/docs/references/fdi/passwordless/get-signup-phoneNumber-exists.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Check phone exists (deprecated) -sidebar_label: get Check phone exists (deprecated) (deprecated) -sidebar_position: 4 -description: >- - GET /{apiBasePath}/{tenantId}/signup/phoneNumber/exists endpoint exposed by - the FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/passwordless/meta.ts b/docs/references/fdi/passwordless/meta.ts new file mode 100644 index 0000000000..31ff11c2a3 --- /dev/null +++ b/docs/references/fdi/passwordless/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Passwordless", + "icon": "wand-sparkles", + "order": 5 +}); diff --git a/docs/references/fdi/passwordless/post-signinup-code-consume.mdx b/docs/references/fdi/passwordless/post-signinup-code-consume.mdx deleted file mode 100644 index be106e0ea0..0000000000 --- a/docs/references/fdi/passwordless/post-signinup-code-consume.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Complete passwordless sign in/up -sidebar_label: post Complete passwordless sign in/up -sidebar_position: 6 -description: >- - POST /{apiBasePath}/{tenantId}/signinup/code/consume endpoint exposed by the - FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/passwordless/post-signinup-code-resend.mdx b/docs/references/fdi/passwordless/post-signinup-code-resend.mdx deleted file mode 100644 index 0edb47ecc2..0000000000 --- a/docs/references/fdi/passwordless/post-signinup-code-resend.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Resend passwordless code -sidebar_label: post Resend passwordless code -sidebar_position: 7 -description: >- - POST /{apiBasePath}/{tenantId}/signinup/code/resend endpoint exposed by the - FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/passwordless/post-signinup-code.mdx b/docs/references/fdi/passwordless/post-signinup-code.mdx deleted file mode 100644 index b10185e276..0000000000 --- a/docs/references/fdi/passwordless/post-signinup-code.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Start passwordless sign in/up -sidebar_label: post Start passwordless sign in/up -sidebar_position: 5 -description: 'POST `/{apiBasePath}/{tenantId}/signinup/code` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/session/_category_.json b/docs/references/fdi/session/_category_.json deleted file mode 100644 index 17d5425ed0..0000000000 --- a/docs/references/fdi/session/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Session", - "position": 6 -} diff --git a/docs/references/fdi/session/meta.ts b/docs/references/fdi/session/meta.ts new file mode 100644 index 0000000000..30f266a8ba --- /dev/null +++ b/docs/references/fdi/session/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Session", + "icon": "clock-3", + "order": 6 +}); diff --git a/docs/references/fdi/session/post-session-refresh.mdx b/docs/references/fdi/session/post-session-refresh.mdx deleted file mode 100644 index d63cfe24a7..0000000000 --- a/docs/references/fdi/session/post-session-refresh.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Refresh user session -sidebar_label: post Refresh user session -sidebar_position: 1 -description: 'POST `/{apiBasePath}/session/refresh` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/session/post-signout.mdx b/docs/references/fdi/session/post-signout.mdx deleted file mode 100644 index 9f70e1043e..0000000000 --- a/docs/references/fdi/session/post-signout.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Sign out user -sidebar_label: post Sign out user -sidebar_position: 2 -description: 'POST `/{apiBasePath}/signout` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/thirdparty/_category_.json b/docs/references/fdi/thirdparty/_category_.json deleted file mode 100644 index 50735dc4ae..0000000000 --- a/docs/references/fdi/thirdparty/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "ThirdParty", - "position": 7 -} diff --git a/docs/references/fdi/thirdparty/get-authorisationurl.mdx b/docs/references/fdi/thirdparty/get-authorisationurl.mdx deleted file mode 100644 index 65d334f143..0000000000 --- a/docs/references/fdi/thirdparty/get-authorisationurl.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Get third party auth URL -sidebar_label: get Get third party auth URL -sidebar_position: 1 -description: 'GET `/{apiBasePath}/{tenantId}/authorisationurl` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/thirdparty/meta.ts b/docs/references/fdi/thirdparty/meta.ts new file mode 100644 index 0000000000..52507f348a --- /dev/null +++ b/docs/references/fdi/thirdparty/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "ThirdParty", + "icon": "share-2", + "order": 7 +}); diff --git a/docs/references/fdi/thirdparty/post-callback-apple.mdx b/docs/references/fdi/thirdparty/post-callback-apple.mdx deleted file mode 100644 index 3154845695..0000000000 --- a/docs/references/fdi/thirdparty/post-callback-apple.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Handle Apple sign in -sidebar_label: post Handle Apple sign in -sidebar_position: 3 -description: 'POST `/{apiBasePath}/callback/apple` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/thirdparty/post-signinup.mdx b/docs/references/fdi/thirdparty/post-signinup.mdx deleted file mode 100644 index 99fb6d3403..0000000000 --- a/docs/references/fdi/thirdparty/post-signinup.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Sign in/up with third party -sidebar_label: post Sign in/up with third party -sidebar_position: 2 -description: 'POST `/{apiBasePath}/{tenantId}/signinup` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/webauthn/_category_.json b/docs/references/fdi/webauthn/_category_.json deleted file mode 100644 index bc41f2b916..0000000000 --- a/docs/references/fdi/webauthn/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "WebAuthn", - "position": 8 -} diff --git a/docs/references/fdi/webauthn/get-webauthn-email-exists.mdx b/docs/references/fdi/webauthn/get-webauthn-email-exists.mdx deleted file mode 100644 index 6ebf26ceab..0000000000 --- a/docs/references/fdi/webauthn/get-webauthn-email-exists.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Check WebAuthn email exists -sidebar_label: get Check WebAuthn email exists -sidebar_position: 1 -description: >- - GET /{apiBasePath}/{tenantId}/webauthn/email/exists endpoint exposed by the - FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/webauthn/meta.ts b/docs/references/fdi/webauthn/meta.ts new file mode 100644 index 0000000000..c6b4c4c208 --- /dev/null +++ b/docs/references/fdi/webauthn/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "WebAuthn", + "icon": "fingerprint", + "order": 8 +}); diff --git a/docs/references/fdi/webauthn/post-webauthn-credential.mdx b/docs/references/fdi/webauthn/post-webauthn-credential.mdx deleted file mode 100644 index 88c987bf9b..0000000000 --- a/docs/references/fdi/webauthn/post-webauthn-credential.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Register WebAuthn credential -sidebar_label: post Register WebAuthn credential -sidebar_position: 2 -description: >- - POST /{apiBasePath}/{tenantId}/webauthn/credential endpoint exposed by the FDI - API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/webauthn/post-webauthn-recover-account-token.mdx b/docs/references/fdi/webauthn/post-webauthn-recover-account-token.mdx deleted file mode 100644 index c7b99f8499..0000000000 --- a/docs/references/fdi/webauthn/post-webauthn-recover-account-token.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Generate WebAuthn recovery token -sidebar_label: post Generate WebAuthn recovery token -sidebar_position: 4 -description: >- - POST /{apiBasePath}/{tenantId}/webauthn/recover/account/token endpoint exposed - by the FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/webauthn/post-webauthn-recover-account.mdx b/docs/references/fdi/webauthn/post-webauthn-recover-account.mdx deleted file mode 100644 index b93f126e47..0000000000 --- a/docs/references/fdi/webauthn/post-webauthn-recover-account.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Recover WebAuthn account -sidebar_label: post Recover WebAuthn account -sidebar_position: 3 -description: >- - POST /{apiBasePath}/{tenantId}/webauthn/recover/account endpoint exposed by - the FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/webauthn/post-webauthn-register-options.mdx b/docs/references/fdi/webauthn/post-webauthn-register-options.mdx deleted file mode 100644 index 4f59ed4ca4..0000000000 --- a/docs/references/fdi/webauthn/post-webauthn-register-options.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get WebAuthn registration options -sidebar_label: post Get WebAuthn registration options -sidebar_position: 5 -description: >- - POST /{apiBasePath}/{tenantId}/webauthn/register/options endpoint exposed by - the FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/webauthn/post-webauthn-signin-options.mdx b/docs/references/fdi/webauthn/post-webauthn-signin-options.mdx deleted file mode 100644 index 432f34c02d..0000000000 --- a/docs/references/fdi/webauthn/post-webauthn-signin-options.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Get WebAuthn sign in options -sidebar_label: post Get WebAuthn sign in options -sidebar_position: 7 -description: >- - POST /{apiBasePath}/{tenantId}/webauthn/signin/options endpoint exposed by the - FDI API -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/webauthn/post-webauthn-signin.mdx b/docs/references/fdi/webauthn/post-webauthn-signin.mdx deleted file mode 100644 index 87258ce474..0000000000 --- a/docs/references/fdi/webauthn/post-webauthn-signin.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Sign in with WebAuthn -sidebar_label: post Sign in with WebAuthn -sidebar_position: 6 -description: 'POST `/{apiBasePath}/{tenantId}/webauthn/signin` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/fdi/webauthn/post-webauthn-signup.mdx b/docs/references/fdi/webauthn/post-webauthn-signup.mdx deleted file mode 100644 index 5c895b4ab2..0000000000 --- a/docs/references/fdi/webauthn/post-webauthn-signup.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Sign up with WebAuthn -sidebar_label: post Sign up with WebAuthn -sidebar_position: 8 -description: 'POST `/{apiBasePath}/{tenantId}/webauthn/signup` endpoint exposed by the FDI API' -page_type: api-reference -hide_title: true -category: fdi ---- - - diff --git a/docs/references/frontend-sdks/_category_.json b/docs/references/frontend-sdks/_category_.json deleted file mode 100644 index c9e8fa71c9..0000000000 --- a/docs/references/frontend-sdks/_category_.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "label": "Frontend SDKs", - "customProps": { - "isMainCategory": true - }, - "position": 3 -} diff --git a/docs/references/frontend-sdks/function-overrides.mdx b/docs/references/frontend-sdks/function-overrides.mdx index cc8b3e1fb7..2d93869770 100644 --- a/docs/references/frontend-sdks/function-overrides.mdx +++ b/docs/references/frontend-sdks/function-overrides.mdx @@ -1,15 +1,10 @@ --- title: Function Overrides -hide_title: true -sidebar_position: 2 description: Override frontend authentication functions to implement custom use cases. -page_type: sdk-reference -category: frontend-sdk +sidebar: + order: 2 --- - -# Function overrides - ## Overview **Function overrides** let you customize the behavior of the functions used internally, by the SDKs. @@ -32,16 +27,15 @@ If you are calling the backend SDK endpoints directly this code does not run in The code snippet shows the general flow of overriding a function. You inject your own custom logic while also calling the original implementation of the function. -:::info -The next examples include a couple of override samples. +:::info[The next examples include a couple of override samples.] See all the [functions that can be overridden here](https://supertokens.com/docs/auth-react/modules/recipe_thirdpartyemailpassword.html#RecipeInterface) ::: - - + + -```tsx +```tsx {14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69} import SuperTokens from "supertokens-auth-react"; import Session from "supertokens-auth-react/recipe/session"; import ThirdParty from "supertokens-auth-react/recipe/thirdparty"; @@ -55,7 +49,6 @@ SuperTokens.init({ }, recipeList: [ Session.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -72,10 +65,8 @@ SuperTokens.init({ } } } - // highlight-end }), EmailPassword.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -94,10 +85,8 @@ SuperTokens.init({ } } } - // highlight-end }), ThirdParty.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -116,25 +105,20 @@ SuperTokens.init({ } } } - // highlight-end }) ] }); ``` - + - + :::info See all the [functions that can be overridden here](https://supertokens.com/docs/auth-react/modules/recipe_thirdpartyemailpassword.html#RecipeInterface) ::: -```tsx +```tsx {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIThirdParty from "supertokens-auth-react-script/recipe/thirdparty"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; supertokensUIInit({ appInfo: { @@ -144,7 +128,6 @@ supertokensUIInit({ }, recipeList: [ supertokensUISession.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -161,10 +144,8 @@ supertokensUIInit({ } } } - // highlight-end }), supertokensUIEmailPassword.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -183,10 +164,8 @@ supertokensUIInit({ } } } - // highlight-end }), supertokensUIThirdParty.init({ - // highlight-start override: { functions: (originalImplementation) => { return { @@ -205,12 +184,10 @@ supertokensUIInit({ } } } - // highlight-end }) ] }); ``` - - - + + diff --git a/docs/references/frontend-sdks/hooks.mdx b/docs/references/frontend-sdks/hooks.mdx index 728a9fb064..bb31b8d703 100644 --- a/docs/references/frontend-sdks/hooks.mdx +++ b/docs/references/frontend-sdks/hooks.mdx @@ -1,37 +1,30 @@ --- title: Hooks -hide_title: true -sidebar_position: 3 -description: >- - Handle user actions for logging, analytics, or side effects using the Handle - Event Hook. -page_type: sdk-reference -category: frontend-sdk +description: Handle user actions for logging, analytics, or side effects using the Handle Event Hook. +sidebar: + order: 3 --- - -# Hooks - ## Overview Hooks are a way to trigger custom logic when certain actions happen in the authentication process. - + --- ## Handle event hook - + Each frontend recipe emits events when certain actions happen. You can use this hook to trigger side effects when something happens in the authentication process. This can address things like logging or analytics. - - + + ```tsx import ThirdParty from "supertokens-auth-react/recipe/thirdparty"; @@ -75,14 +68,12 @@ ThirdParty.init({ } }) ``` - + - + ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import supertokensUIThirdParty from "supertokens-auth-react-script/recipe/thirdparty"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; supertokensUIEmailPassword.init({ onHandleEvent: (context) => { @@ -122,19 +113,18 @@ supertokensUIThirdParty.init({ } }) ``` - - + + - + - + -:::caution -Not applicable since you need to build custom UI anyway. +:::warning[Not applicable since you need to build custom UI anyway.] When you call the functions from the SDK, or call the API directly, you can run custom logic in your own code. ::: - + --- @@ -144,10 +134,10 @@ This function calls the backend before any API call. You can use this to change the request properties. - + - - + + ```tsx import ThirdParty from "supertokens-auth-react/recipe/thirdparty"; @@ -207,14 +197,12 @@ EmailPassword.init({ }) ``` - + - + ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import supertokensUIThirdParty from "supertokens-auth-react-script/recipe/thirdparty"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; supertokensUIThirdParty.init({ preAPIHook: async (context) => { @@ -270,19 +258,19 @@ supertokensUIEmailPassword.init({ }) ``` - + - + - + - + - - + + - - + + ```tsx import ThirdParty from "supertokens-web-js/recipe/thirdparty" @@ -340,9 +328,9 @@ ThirdParty.init({ }) ``` - +
Alternatively you could also declare the pre-API hook when calling the function: - +
```tsx import EmailPassword from "supertokens-web-js/recipe/emailpassword" @@ -363,12 +351,10 @@ EmailPassword.doesEmailExist({ }); ``` -
- +
+ ```tsx -import supertokensThirdParty from "supertokens-web-js-script/recipe/thirdparty"; -import supertokensEmailPassword from "supertokens-web-js-script/recipe/emailpassword"; supertokensEmailPassword.init({ preAPIHook: async (context) => { let url = context.url; @@ -421,12 +407,11 @@ supertokensThirdParty.init({ }) ``` - +
Alternatively you could also declare the pre-API hook when calling the function: - +
```tsx -import supertokensEmailPassword from "supertokens-web-js-script/recipe/emailpassword" supertokensEmailPassword.doesEmailExist({ email: "...", options: { @@ -442,16 +427,16 @@ supertokensEmailPassword.doesEmailExist({ ``` - - +
+
-
+ - + - + - + ```tsx import SuperTokens from "supertokens-react-native"; @@ -482,9 +467,9 @@ SuperTokens.init({ ``` - + - + ```kotlin import android.app.Application @@ -511,9 +496,9 @@ class MainApplication : Application() { } ``` - + - + ```swift import UIKit @@ -553,9 +538,9 @@ fileprivate class MyApplicationDelegate: UIResponder, UIApplicationDelegate { } ``` - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -576,29 +561,29 @@ void main() { } ``` - + - + - + -
+ -
+ --- ## Redirection callback hook - + Use this function to change where the system redirects the user after certain actions. For example, you can use this to redirect a user to a specific URL post sign in or sign up. If you're embedding the UI components in a popup and wish to disable redirection entirely, return `null`. - - + + ```tsx import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; @@ -644,14 +629,12 @@ SuperTokens.init({ })] }); ``` - + - + ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; supertokensUIInit({ appInfo: { @@ -693,15 +676,14 @@ supertokensUIInit({ })] }); ``` - - + + - - + + -:::caution -Not applicable since you need to build custom UI anyway. +:::warning[Not applicable since you need to build custom UI anyway.] When you call the functions from the SDK, or call the API directly, you can run custom logic in your own code. ::: - + diff --git a/docs/references/frontend-sdks/meta.ts b/docs/references/frontend-sdks/meta.ts new file mode 100644 index 0000000000..b7a6a4e453 --- /dev/null +++ b/docs/references/frontend-sdks/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Frontend SDKs", + "icon": "monitor", + "order": 3 +}); diff --git a/docs/references/frontend-sdks/prebuilt-ui/_category_.json b/docs/references/frontend-sdks/prebuilt-ui/_category_.json deleted file mode 100644 index fe679ee0ed..0000000000 --- a/docs/references/frontend-sdks/prebuilt-ui/_category_.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "label": "User Interface", - "customProps": { - "isMainCategory": true - }, - "collapsed": true, - "position": 3 -} diff --git a/docs/references/frontend-sdks/prebuilt-ui/changing-colours.mdx b/docs/references/frontend-sdks/prebuilt-ui/changing-colours.mdx index 2d33b67188..22d19bb9c6 100644 --- a/docs/references/frontend-sdks/prebuilt-ui/changing-colours.mdx +++ b/docs/references/frontend-sdks/prebuilt-ui/changing-colours.mdx @@ -1,14 +1,10 @@ --- title: Change colours -sidebar_position: 2 -description: >- - Customize your authentication UI theme by defining CSS variables for color - palettes. -page_type: guide -category: frontend-sdk +description: Customize your authentication UI theme by defining CSS variables for color palettes. +sidebar: + order: 2 --- - ## Overview You can update the default theme with your colors to make it fit with your website. Define a few CSS variables in the `style` property to the `EmailPassword.init` call. @@ -19,16 +15,16 @@ For example, if your website uses a dark theme, here is how you can customize it ## Before you start -:::caution no-title +:::warning This example is relevant only if you use the prebuilt UI components. ::: ## Example - - + + -```tsx +```tsx {9,10,11,12,13,14,15,16,17,18,19,20,21,22} import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ @@ -37,7 +33,6 @@ SuperTokens.init({ appName: "...", websiteDomain: "..." }, - // highlight-start style: ` [data-supertokens~=container] { --palette-background: 51, 51, 51; @@ -52,17 +47,15 @@ SuperTokens.init({ --palette-textGray: 158, 158, 158; } `, - // highlight-end recipeList: [ /* ... */] }); ``` - + - + -```tsx +```tsx {9,10,11,12,13,14,15,16,17,18,19,20,21,22} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -70,7 +63,6 @@ supertokensUIInit({ appName: "...", websiteDomain: "..." }, - // highlight-start style: ` [data-supertokens~=container] { --palette-background: 51, 51, 51; @@ -85,16 +77,15 @@ supertokensUIInit({ --palette-textGray: 158, 158, 158; } `, - // highlight-end recipeList: [ /* ... */] }); ``` - - + + -Prebuilt form UI with custom color palette +Prebuilt form UI with custom color palette -:::important +:::note Changes to the palette apply to all the UI components provided. If you want to change a specific component, please see [this section](changing-style). ::: @@ -120,4 +111,3 @@ Changes to the palette apply to all the UI components provided. If you want to c | `buttonText` | Color of text in main buttons | `255, 255, 255` (white) | | `superTokensBrandingBackground` | Color of SuperTokens branding element | `242, 245, 246` (Alice blue) | | `superTokensBrandingText` | Color of "Powered by SuperTokens" text | `173, 189, 196` (heather grey) | - diff --git a/docs/references/frontend-sdks/prebuilt-ui/changing-style.mdx b/docs/references/frontend-sdks/prebuilt-ui/changing-style.mdx index 6b6a9cb757..10bc3f9ba2 100644 --- a/docs/references/frontend-sdks/prebuilt-ui/changing-style.mdx +++ b/docs/references/frontend-sdks/prebuilt-ui/changing-style.mdx @@ -1,12 +1,10 @@ --- title: Change styles via CSS -sidebar_position: 3 description: Change UI component styles using CSS. -page_type: guide -category: frontend-sdk +sidebar: + order: 3 --- - ## Overview Updating the CSS allows you to change the UI of the components to meet your needs. @@ -15,7 +13,7 @@ Note that the process can update any HTML tag from within SuperTokens components ## Before you start -:::caution no-title +:::warning This example is relevant only if you use the prebuilt UI components. ::: @@ -25,18 +23,18 @@ This example is relevant only if you use the prebuilt UI components. First, open the website at `/auth`. The Sign-in widget should show up. Use the browser console to find out the class name that you'd like to overwrite. -Inspecting submit button in prebuilt form +Inspecting submit button in prebuilt form -Highlighting attribute for customization +Highlighting attribute for customization Each stylable component contains `data-supertokens` attributes (in this example `data-supertokens="button"`). Let's customize elements with the `button` attribute. The syntax for styling is plain CSS. - - + + -```tsx +```tsx {9,10,11,12,13,14,15,16} import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ @@ -45,7 +43,6 @@ SuperTokens.init({ appName: "...", websiteDomain: "..." }, - // highlight-start style: ` [data-supertokens~=button] { background-color: #252571; @@ -54,17 +51,15 @@ SuperTokens.init({ margin: 0 auto; } `, - // highlight-end recipeList: [ /* ... */] }); ``` - + - + -```tsx +```tsx {9,10,11,12,13,14,15,16} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -72,7 +67,6 @@ supertokensUIInit({ appName: "...", websiteDomain: "..." }, - // highlight-start style: ` [data-supertokens~=button] { background-color: #252571; @@ -81,23 +75,22 @@ supertokensUIInit({ margin: 0 auto; } `, - // highlight-end recipeList: [ /* ... */] }); ``` - - + + The above results in: -Prebuilt form with custom submit button +Prebuilt form with custom submit button ### Changing fonts By default, SuperTokens uses the `Arial` font. The best way to override this is to add a `font-family` styling to the `container` component in the recipe configuration. - - + + ```tsx import SuperTokens from "supertokens-auth-react"; @@ -116,13 +109,12 @@ SuperTokens.init({ recipeList: [ /* ... */] }); ``` - + - + ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -138,15 +130,15 @@ supertokensUIInit({ recipeList: [ /* ... */] }); ``` - - + + ### Using media queries You may want to have different CSS for different `viewports`. This can happen via media queries like this: - - + + ```tsx import SuperTokens from "supertokens-auth-react"; @@ -174,13 +166,12 @@ SuperTokens.init({ recipeList: [ /* ... */], }); ``` - + - + ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -205,8 +196,8 @@ supertokensUIInit({ recipeList: [ /* ... */], }); ``` - - + + --- @@ -214,8 +205,8 @@ supertokensUIInit({ These are the screens shown when the user tries to log in or sign up for the application. - - + + ```tsx import SuperTokens from "supertokens-auth-react"; @@ -232,13 +223,12 @@ SuperTokens.init({ recipeList: [ /* ... */] }); ``` - + - + ```tsx // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -252,8 +242,8 @@ supertokensUIInit({ recipeList: [ /* ... */] }); ``` - - + + --- @@ -263,10 +253,10 @@ supertokensUIInit({ This form appears when the user clicks on "forgot password" in the sign in form. - - + + -```tsx +```tsx {13,14,15,16,17} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import Session from "supertokens-auth-react/recipe/session"; @@ -279,27 +269,22 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start resetPasswordUsingTokenFeature: { enterEmailForm: { style: ` ... ` } } - // highlight-end }), Session.init() ] }); ``` - + - + -```tsx +```tsx {11,12,13,14,15} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -309,29 +294,27 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailPassword.init({ - // highlight-start resetPasswordUsingTokenFeature: { enterEmailForm: { style: ` ... ` } } - // highlight-end }), supertokensUISession.init() ] }); ``` - - + + ### Submit new password form This screen appears when the user clicks the password reset link on their email - to enter their new password - - + + -```tsx +```tsx {13,14,15,16,17} import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import Session from "supertokens-auth-react/recipe/session"; @@ -344,27 +327,22 @@ SuperTokens.init({ }, recipeList: [ EmailPassword.init({ - // highlight-start resetPasswordUsingTokenFeature: { submitNewPasswordForm: { style: ` ... ` } } - // highlight-end }), Session.init() ] }); ``` - + - + -```tsx +```tsx {11,12,13,14,15} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; -import supertokensUIEmailPassword from "supertokens-auth-react-script/recipe/emailpassword"; -import supertokensUISession from "supertokens-auth-react-script/recipe/session"; supertokensUIInit({ appInfo: { @@ -374,18 +352,15 @@ supertokensUIInit({ }, recipeList: [ supertokensUIEmailPassword.init({ - // highlight-start resetPasswordUsingTokenFeature: { submitNewPasswordForm: { style: ` ... ` } } - // highlight-end }), supertokensUISession.init() ] }); ``` - - - + + diff --git a/docs/references/frontend-sdks/prebuilt-ui/embed-sign-in-up-form.mdx b/docs/references/frontend-sdks/prebuilt-ui/embed-sign-in-up-form.mdx index 6f370e9a1a..33ad8360af 100644 --- a/docs/references/frontend-sdks/prebuilt-ui/embed-sign-in-up-form.mdx +++ b/docs/references/frontend-sdks/prebuilt-ui/embed-sign-in-up-form.mdx @@ -1,19 +1,13 @@ --- title: Embed the authentication form in a page -sidebar_position: 4 -description: >- - Embed authentication forms in your page using SuperTokens with redirection and - popup options. -page_type: guide -category: frontend-sdk +description: Embed authentication forms in your page using SuperTokens with redirection and popup options. +sidebar: + order: 4 --- - - - ## Before you start -:::caution no-title +:::warning This example is relevant only if you use the React SDK with prebuilt UI components. ::: @@ -24,25 +18,20 @@ This example is relevant only if you use the React SDK with prebuilt UI componen The following example shows the scenario where you have a dedicated route, such as `/auth`, for rendering the Auth Widget. Upon a successful login, the user automatically redirects to the return value of `getRedirectionURL` (defaulting to `/`). - - + + - + - + -```tsx +```tsx {5,16,17,18,19,20,21,22,23,32} import React from "react"; import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui" -// highlight-start import { AuthPage } from 'supertokens-auth-react/ui'; -// highlight-end -// @ts-ignore import Header from "./header"; -// @ts-ignore import Footer from "./footer"; import { useNavigate } from "react-router-dom"; @@ -52,7 +41,6 @@ SuperTokens.init({ appName: "...", websiteDomain: "..." }, - // highlight-start getRedirectionURL: async (context) => { if (context.action === "TO_AUTH") { return "/auth"; // return the path where you are rendering the Auth UI @@ -61,7 +49,6 @@ SuperTokens.init({ }; }, disableAuthRoute: true, - // highlight-end recipeList: [ /* ... */], }); @@ -70,7 +57,6 @@ function MyAuthPage() { return (
- // highlight-next-line
@@ -78,21 +64,17 @@ function MyAuthPage() { } ``` -
+
- + -```tsx +```tsx {5,16,17,18,19,20,21,22,23,32} import React from "react"; import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui" -// highlight-start import { AuthPage } from 'supertokens-auth-react/ui'; -// highlight-end -// @ts-ignore import Header from "./header"; -// @ts-ignore import Footer from "./footer"; import { useHistory } from "react-router-dom5"; @@ -102,7 +84,6 @@ SuperTokens.init({ appName: "...", websiteDomain: "..." }, - // highlight-start getRedirectionURL: async (context) => { if (context.action === "TO_AUTH") { return "/auth"; // return the path where you are rendering the Auth UI @@ -111,7 +92,6 @@ SuperTokens.init({ }; }, disableAuthRoute: true, - // highlight-end recipeList: [ /* ... */], }); @@ -120,7 +100,6 @@ function MyAuthPage() { return (
- // highlight-next-line
@@ -128,24 +107,20 @@ function MyAuthPage() { } ``` -
+ - +
-
- + + -```tsx +```tsx {5,15,16,17,18,19,20,21,22,30} import React from "react"; import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui" -// highlight-start import { AuthPage } from 'supertokens-auth-react/ui'; -// highlight-end -// @ts-ignore import Header from "./header"; -// @ts-ignore import Footer from "./footer"; SuperTokens.init({ @@ -154,7 +129,6 @@ SuperTokens.init({ appName: "...", websiteDomain: "..." }, - // highlight-start getRedirectionURL: async (context) => { if (context.action === "TO_AUTH") { return "/auth"; // return the path where you are rendering the Auth UI @@ -163,7 +137,6 @@ SuperTokens.init({ }; }, disableAuthRoute: true, - // highlight-end recipeList: [ /* ... */], }); @@ -171,15 +144,14 @@ function MyAuthPage() { return (
- // highlight-next-line
) } ``` -
-
+ + In the above code snippet: @@ -188,8 +160,7 @@ In the above code snippet: Feel free to customize the redirection URLs as needed. -:::note -When the user visits the `/auth` page, they see the SignIn UI by default. To render the SignUp UI, append `show=signup` as a query parameter to the URL, like`/auth?show=signup`. +:::note[When the user visits the `/auth` page, they see the SignIn UI by default. To render the SignUp UI, append `show=signup` as a query parameter to the URL, like`/auth?show=signup`.] ::: --- @@ -198,27 +169,21 @@ When the user visits the `/auth` page, they see the SignIn UI by default. To ren The following example shows the scenario where you have a dedicated route, such as `/auth`, for rendering the Auth Widget. However, upon a successful login, the user sees a logged in UI instead of getting redirected. - - + + - + - + -```tsx +```tsx {4,5,19,20,21,22,23,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54} import React from "react"; import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; -// highlight-start import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui" -// highlight-start import { AuthPage } from 'supertokens-auth-react/ui'; -// highlight-end import Session from "supertokens-auth-react/recipe/session"; -// @ts-ignore import Header from "./header"; -// @ts-ignore import Footer from "./footer"; import { useNavigate } from "react-router-dom"; @@ -230,16 +195,13 @@ SuperTokens.init({ }, disableAuthRoute: true, recipeList: [ /* ... */], - // highlight-start getRedirectionURL: async (context) => { if (context.action === "SUCCESS") { return null; // this will not navigate the user away after successful login } }, - // highlight-end }); -// highlight-start function LandingPage() { let sessionContext = Session.useSessionContext(); const navigate = useNavigate(); @@ -263,33 +225,26 @@ function LandingPage() { return (
- // highlight-next-line
) } } -// highlight-end ``` -
+
- + -```tsx +```tsx {4,5,19,20,21,22,23,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54} import React from "react"; import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; -// highlight-start import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui" -// highlight-start import { AuthPage } from 'supertokens-auth-react/ui'; -// highlight-end import Session from "supertokens-auth-react/recipe/session"; -// @ts-ignore import Header from "./header"; -// @ts-ignore import Footer from "./footer"; import { useHistory } from "react-router-dom5"; @@ -301,16 +256,13 @@ SuperTokens.init({ }, disableAuthRoute: true, recipeList: [ /* ... */], - // highlight-start getRedirectionURL: async (context) => { if (context.action === "SUCCESS") { return null; // this will not navigate the user away after successful login } }, - // highlight-end }); -// highlight-start function LandingPage() { let sessionContext = Session.useSessionContext(); const history = useHistory(); @@ -334,36 +286,29 @@ function LandingPage() { return (
- // highlight-next-line
) } } -// highlight-end ``` -
+ - +
-
- + + -```tsx +```tsx {4,5,18,19,20,21,22,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52} import React from "react"; import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; -// highlight-start import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui" -// highlight-start import { AuthPage } from 'supertokens-auth-react/ui'; -// highlight-end import Session from "supertokens-auth-react/recipe/session"; -// @ts-ignore import Header from "./header"; -// @ts-ignore import Footer from "./footer"; SuperTokens.init({ @@ -374,16 +319,13 @@ SuperTokens.init({ }, disableAuthRoute: true, recipeList: [ /* ... */], - // highlight-start getRedirectionURL: async (context) => { if (context.action === "SUCCESS") { return null; // this will not navigate the user away after successful login } }, - // highlight-end }); -// highlight-start function LandingPage() { let sessionContext = Session.useSessionContext(); if (sessionContext.loading) { @@ -406,17 +348,15 @@ function LandingPage() { return (
- // highlight-next-line
) } } -// highlight-end ``` -
-
+ + In the above code snippet, `Session.SessionAuth` wraps the logged-in component to validate all claims before displaying the logged-in UI. For instance, with email verification enabled, if a user's email remains unverified, `Session.SessionAuth` redirects to the email verification page. @@ -430,24 +370,20 @@ In the above case, redirection may occur if a claim fails. For instance, in the The following example shows the scenario where you embed the Auth Widget in a popup, and upon successful login, you aim to close the popup. - - + + - + - + -```tsx +```tsx {5,6,18,19,20,21,22,67} import React, { useState, useEffect } from "react"; import Modal from "react-modal"; import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; -// highlight-start import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui" -// highlight-start import { AuthPage } from 'supertokens-auth-react/ui'; -// highlight-end import Session from "supertokens-auth-react/recipe/session"; import { useNavigate } from "react-router-dom"; @@ -459,13 +395,11 @@ SuperTokens.init({ }, disableAuthRoute: true, recipeList: [ /* ... */], - // highlight-start getRedirectionURL: async (context) => { if (context.action === "SUCCESS") { return null; // this will not navigate the user away after successful login } }, - // highlight-end }); function AuthPopup() { @@ -510,7 +444,6 @@ function AuthPopup() { isOpen={isModalOpen} contentLabel="Auth Modal" > - {/* highlight-next-line */}
@@ -518,20 +451,17 @@ function AuthPopup() { } ``` - + - + -```tsx +```tsx {5,6,18,19,20,21,22,67} import React, { useState, useEffect } from "react"; import Modal from "react-modal"; import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; -// highlight-start import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui" -// highlight-start import { AuthPage } from 'supertokens-auth-react/ui'; -// highlight-end import Session from "supertokens-auth-react/recipe/session"; import { useHistory } from "react-router-dom5"; @@ -543,13 +473,11 @@ SuperTokens.init({ }, disableAuthRoute: true, recipeList: [ /* ... */], - // highlight-start getRedirectionURL: async (context) => { if (context.action === "SUCCESS") { return null; // this will not navigate the user away after successful login } }, - // highlight-end }); function AuthPopup() { @@ -594,7 +522,6 @@ function AuthPopup() { isOpen={isModalOpen} contentLabel="Auth Modal" > - {/* highlight-next-line */} @@ -602,23 +529,20 @@ function AuthPopup() { } ``` - + - + - - + + -```tsx +```tsx {5,6,17,18,19,20,21,65} import React, { useState, useEffect } from "react"; import Modal from "react-modal"; import SuperTokens from "supertokens-auth-react"; import EmailPassword from "supertokens-auth-react/recipe/emailpassword"; -// highlight-start import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui" -// highlight-start import { AuthPage } from 'supertokens-auth-react/ui'; -// highlight-end import Session from "supertokens-auth-react/recipe/session"; SuperTokens.init({ @@ -629,13 +553,11 @@ SuperTokens.init({ }, disableAuthRoute: true, recipeList: [ /* ... */], - // highlight-start getRedirectionURL: async (context) => { if (context.action === "SUCCESS") { return null; // this will not navigate the user away after successful login } }, - // highlight-end }); function AuthPopup() { @@ -679,17 +601,15 @@ function AuthPopup() { isOpen={isModalOpen} contentLabel="Auth Modal" > - {/* highlight-next-line */} ); } ``` - - + + :::note In the above case, redirection may occur if a claim fails. For instance, in the case of an Email Verification claim, if the user's email is not verified, they redirect to the email verification page. To prevent redirection for failed claims, please contact [Discord](https://supertokens.com/discord) for assistance. ::: - diff --git a/docs/references/frontend-sdks/prebuilt-ui/meta.ts b/docs/references/frontend-sdks/prebuilt-ui/meta.ts new file mode 100644 index 0000000000..2f1eae33eb --- /dev/null +++ b/docs/references/frontend-sdks/prebuilt-ui/meta.ts @@ -0,0 +1,8 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "User Interface", + "icon": "palette", + "order": 3, + "collapsed": true +}); diff --git a/docs/references/frontend-sdks/prebuilt-ui/override-react-components.mdx b/docs/references/frontend-sdks/prebuilt-ui/override-react-components.mdx index be178ac055..7fbf4fa84c 100644 --- a/docs/references/frontend-sdks/prebuilt-ui/override-react-components.mdx +++ b/docs/references/frontend-sdks/prebuilt-ui/override-react-components.mdx @@ -1,15 +1,10 @@ --- title: Override React components -hide_title: true -sidebar_position: 3 description: Learn to replace and enhance specific components rendered by SuperTokens. -page_type: guide -category: frontend-sdk +sidebar: + order: 3 --- - -# Override react components - ## Overview SuperTokens allows you to customize the React components by overriding them. @@ -18,7 +13,7 @@ Each override should also render the original component to ensure the integrity ## Before you start -:::caution no-title +:::warning This feature is only applicable to React apps that use the prebuilt UI. ::: @@ -29,8 +24,7 @@ This feature is only applicable to React apps that use the prebuilt UI. Discover the name of the component that you need to override by using the React Developer Tools extension. Look for the names defined in component override configuration and/or components ending in `_Override` in the component tree. -Checking which component from the prebuilt UI is overridden using React Developer Tools extension - +Checking which component from the prebuilt UI is overridden using React Developer Tools extension ### 2. Add your override @@ -38,8 +32,8 @@ Look for the names defined in component override configuration and/or components Inside the `SuperTokensWrapper`, update the recipe specific override context with your next component. Make sure that it your override renders the SuperTokens components inside it. - - + + ```tsx import React from "react"; @@ -48,7 +42,6 @@ import { AuthRecipeComponentsOverrideContextProvider } from "supertokens-auth-re import { EmailPasswordComponentsOverrideProvider } from "supertokens-auth-react/recipe/emailpassword" import { ThirdpartyComponentsOverrideProvider } from "supertokens-auth-react/recipe/thirdparty"; -// @ts-ignore import octocat from "./octocat.png"; function App() { @@ -88,9 +81,9 @@ function App() { } export default App; ``` - + - + ```tsx import React from "react"; @@ -102,7 +95,6 @@ import { ThirdPartyPreBuiltUI } from "supertokens-auth-react/recipe/thirdparty/p import { EmailPasswordComponentsOverrideProvider } from "supertokens-auth-react/recipe/emailpassword" import { ThirdpartyComponentsOverrideProvider } from "supertokens-auth-react/recipe/thirdparty"; -// @ts-ignore import octocat from "./octocat.png"; function App() { @@ -148,12 +140,11 @@ function App() { export default App; ``` - + - + -Prebuilt sign in UI with custom image +Prebuilt sign in UI with custom image -:::important -Please make sure that you specify the configuration in a `.tsx` or ` .jsx` file type. +:::note[Please make sure that you specify the configuration in a `.tsx` or ` .jsx` file type.] ::: diff --git a/docs/references/frontend-sdks/prebuilt-ui/shadow-dom.mdx b/docs/references/frontend-sdks/prebuilt-ui/shadow-dom.mdx index 196b026054..d1eb61a134 100644 --- a/docs/references/frontend-sdks/prebuilt-ui/shadow-dom.mdx +++ b/docs/references/frontend-sdks/prebuilt-ui/shadow-dom.mdx @@ -1,15 +1,10 @@ --- -id: shadow-dom title: Disable use of shadow DOM -sidebar_position: 5 -description: >- - Disable Shadow DOM to customize CSS and improve password manager - compatibility. -page_type: guide -category: frontend-sdk +description: Disable Shadow DOM to customize CSS and improve password manager compatibility. +sidebar: + order: 5 --- - ## Overview SuperTokens uses [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) to prevent CSS clashes between your CSS and the ones provided by SuperTokens. @@ -22,7 +17,7 @@ You need to use JavaScript to achieve this. ## Before you start -:::caution no-title +:::warning This example is relevant only if you use the prebuilt UI components. ::: @@ -31,10 +26,10 @@ This example is relevant only if you use the prebuilt UI components. If you want to disable use of shadow dom, you can do this like: - - + + -```tsx +```tsx {9} import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ @@ -43,18 +38,16 @@ SuperTokens.init({ appName: "...", websiteDomain: "..." }, - // highlight-next-line useShadowDom: false, recipeList: [/* ... */] }); ``` - + - + -```tsx +```tsx {9} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -62,14 +55,12 @@ supertokensUIInit({ appName: "...", websiteDomain: "..." }, - // highlight-next-line useShadowDom: false, recipeList: [/* ... */] }); ``` - - + + -:::caution -If disabled, please be sure to check that the components render correctly - because your CSS might affect the components' UI (the other way around does not happen). +:::warning[If disabled, please be sure to check that the components render correctly - because your CSS might affect the components' UI (the other way around does not happen).] ::: diff --git a/docs/references/frontend-sdks/prebuilt-ui/toc-privacypolicy.mdx b/docs/references/frontend-sdks/prebuilt-ui/toc-privacypolicy.mdx index 6c98a12810..94763b6669 100644 --- a/docs/references/frontend-sdks/prebuilt-ui/toc-privacypolicy.mdx +++ b/docs/references/frontend-sdks/prebuilt-ui/toc-privacypolicy.mdx @@ -1,13 +1,10 @@ --- title: Terms of service & Privacy policy links -sidebar_position: 6 description: Add Terms of Service and Privacy Policy links to your sign-up page. -page_type: guide -category: frontend-sdk +sidebar: + order: 6 --- - - ## Overview You can provide a Privacy policy and Terms of service link which renders the following text on the sign up page: @@ -17,17 +14,17 @@ You can provide a Privacy policy and Terms of service link which renders the fol ## Before you start -:::caution no-title +:::warning This feature is only applicable to React apps that use the prebuilt UI. ::: ## Example - - + + -```tsx +```tsx {9,10} import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ @@ -36,20 +33,17 @@ SuperTokens.init({ appName: "...", websiteDomain: "..." }, - // highlight-start termsOfServiceLink: "https://example.com/terms-of-service", privacyPolicyLink: "https://example.com/privacy-policy", - // highlight-end recipeList: [/* ... */] }); ``` - + - + -```tsx +```tsx {9,10} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ appInfo: { @@ -57,14 +51,11 @@ supertokensUIInit({ appName: "...", websiteDomain: "..." }, - // highlight-start termsOfServiceLink: "https://example.com/terms-of-service", privacyPolicyLink: "https://example.com/privacy-policy", - // highlight-end recipeList: [/* ... */] }); ``` - - - + + diff --git a/docs/references/frontend-sdks/prebuilt-ui/translations.mdx b/docs/references/frontend-sdks/prebuilt-ui/translations.mdx index 655e0faa35..a2d51133a0 100644 --- a/docs/references/frontend-sdks/prebuilt-ui/translations.mdx +++ b/docs/references/frontend-sdks/prebuilt-ui/translations.mdx @@ -1,14 +1,10 @@ --- title: Language Translation for the UI -sidebar_position: 7 -description: >- - Translate your UI by providing custom translation strings or integrating with - an internationalization library. -page_type: guide -category: frontend-sdk +description: Translate your UI by providing custom translation strings or integrating with an internationalization library. +sidebar: + order: 7 --- - ## Overview You can translate the UI using two main methods: @@ -17,7 +13,7 @@ You can translate the UI using two main methods: ## Before you start -:::caution no-title +:::warning This feature is only applicable to React apps that use the prebuilt UI. ::: @@ -29,20 +25,19 @@ This feature is only applicable to React apps that use the prebuilt UI. You can provide translations for each segment displayed in the user interfaces. -:::info Important +:::info[Important] - You can find the auth page header / footer UI keys in the [GitHub repository](https://github.com/supertokens/supertokens-auth-react/blob/master/lib/ts/translation/translations.ts). - You can find the `emailpassword` login UI keys in the [GitHub repository](https://github.com/supertokens/supertokens-auth-react/blob/master/lib/ts/recipe/emailpassword/components/themes/translations.ts). ::: - - + + -```tsx +```tsx {5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28} import React from "react"; import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ - // highlight-start languageTranslations: { // This object contains all translation related options translations: { // These are the displayed translation strings for each language // The property names define the language code of the translations @@ -67,7 +62,6 @@ SuperTokens.init({ */ defaultLanguage: "hu", }, - // highlight-end appInfo: { appName: "...", apiDomain: "...", @@ -78,15 +72,13 @@ SuperTokens.init({ ], }); ``` - + - + -```tsx +```tsx {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ - // highlight-start languageTranslations: { // This object contains all translation related options translations: { // These are the displayed translation strings for each language // The property names define the language code of the translations @@ -111,7 +103,6 @@ supertokensUIInit({ */ defaultLanguage: "hu", }, - // highlight-end appInfo: { appName: "...", apiDomain: "...", @@ -122,16 +113,16 @@ supertokensUIInit({ ], }); ``` - + - + ### 2. Load translations After initialization, you can provide additional translation data by calling the `SuperTokens.loadTranslation`. This can be useful if you are loading them asynchronously. - - + + ```tsx import SuperTokens from "supertokens-auth-react"; @@ -144,11 +135,10 @@ SuperTokens.loadTranslation({ } }); ``` - - + + ```tsx -import supertokensUI from "supertokens-auth-react-script"; // This method takes an object as a parameter, which is structured the same as above. // This will be merged into the existing definitions, so any properties missing here won't remove them from the already loaded translations supertokensUI.loadTranslation({ @@ -157,30 +147,29 @@ supertokensUI.loadTranslation({ } }); ``` - - + + ### 3. Change the current language You can update which translations store displays by calling the `SuperTokens.changeLanguage`. - - + + ```tsx import SuperTokens from "supertokens-auth-react"; SuperTokens.changeLanguage("hu"); ``` - - + + ```tsx -import supertokensUI from "supertokens-auth-react-script"; supertokensUI.changeLanguage("hu"); ``` - - + + --- @@ -192,22 +181,20 @@ To do this you need to do two things: 1. Provide the translation function in `SuperTokens.init` - - + + -```tsx +```tsx {5,6,7,8,9,10} import React from "react"; import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ - // highlight-start languageTranslations: { translationFunc: (key: string) => { // The string returned by this function will be displayed return key + "!"; }, }, - // highlight-end appInfo: { appName: "...", apiDomain: "...", @@ -218,21 +205,18 @@ SuperTokens.init({ ], }); ``` - - + + -```tsx +```tsx {3,4,5,6,7,8} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ - // highlight-start languageTranslations: { translationFunc: (key: string) => { // The string returned by this function will be displayed return key + "!"; }, }, - // highlight-end appInfo: { appName: "...", apiDomain: "...", @@ -243,8 +227,8 @@ supertokensUIInit({ ], }); ``` - - + + 2. Call `SuperTokens.changeLanguage` or `SuperTokens.loadTranslation` to re-render the translated UI @@ -264,19 +248,17 @@ The raw translation key displays if it's also missing from the default store. Fo The system stores the chosen language in a cookie, allowing it to restore the language the next time the page loads. You can customize the domain of this cookie through the `currentLanguageCookieScope` option. This can be useful if you are running the SDK in multiple applications and want to share the language choice between sub-domains. - - + + -```tsx +```tsx {5,6,7} import React from "react"; import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ - // highlight-start languageTranslations: { currentLanguageCookieScope: ".example.com", }, - // highlight-end appInfo: { appName: "...", apiDomain: "...", @@ -287,18 +269,15 @@ SuperTokens.init({ ], }); ``` - - + + -```tsx +```tsx {3,4,5} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ - // highlight-start languageTranslations: { currentLanguageCookieScope: ".example.com", }, - // highlight-end appInfo: { appName: "...", apiDomain: "...", @@ -309,8 +288,8 @@ supertokensUIInit({ ], }); ``` - - + + --- @@ -318,8 +297,8 @@ supertokensUIInit({ The SDK also exports the `useTranslation` React hook you can use while overriding components. It returns a function that takes a translation segment key and returns it translated to the selected language. For more information on what translation keys you should use and the exact syntax, please see the original source code of the component you are overriding. - - + + ```tsx import React from "react"; @@ -337,13 +316,12 @@ export const HeaderOverride = () => { }; ``` - - + + -:::info Caution +:::info[Caution] Not applicable for non react apps. ::: - - - + + diff --git a/docs/references/frontend-sdks/prebuilt-ui/ui-showcase.mdx b/docs/references/frontend-sdks/prebuilt-ui/ui-showcase.mdx index aa11b338c7..567b555b5b 100644 --- a/docs/references/frontend-sdks/prebuilt-ui/ui-showcase.mdx +++ b/docs/references/frontend-sdks/prebuilt-ui/ui-showcase.mdx @@ -1,15 +1,8 @@ --- title: UI showcase -hide_title: true -description: >- - Discover the UI exposed by the pre-built UI for each authentication flow and - recipe. -page_type: guide -category: frontend-sdk +description: Discover the UI exposed by the pre-built UI for each authentication flow and recipe. --- -# UI showcase - ## Overview The following page shows the interfaces exposed the pre-built UI for each authentication flow and recipe. @@ -20,57 +13,49 @@ The following page shows the interfaces exposed the pre-built UI for each authen You can see the default UI when you visit the `websiteBasePath` (`/auth` by default) on your website. The form includes a sign in and a sign up form, and by default, the sign in form appears. - - -## Default sign in form - -Sign in form UI for email password login - -## Default sign up form - -Sign up form UI for email password login - -## Field validation error UI - + + +Sign in form UI for email password login + + +Sign up form UI for email password login + + The sign up form checks if the email is unique and if not, shows an error to the user saying that the email already exists. Likewise, if any of the form field's validation fails, the user sees an error like below. -Sign up form field error UI - - -## Incorrect email / password UI +Sign up form field error UI + + In the sign in form, if the user enters an email that doesn't exist, or is an incorrect email & password combination, they see the following error. -Sign in form wrong credentials UI - -## General error UI +Sign in form wrong credentials UI + + If there are network related errors, or the backend sends a status code >= 300, then the following UI appears. -Sign in form general error - +Sign in form general error + --- ## Email verification - - -## Email sent screen UI - + + Once the user visits the email verification screen, this is what they see. -Email verification email sent +Email verification email sent On screen load, SuperTokens automatically sends an email to the user. This way, the user doesn't have to do any interaction before they get an email. Customizing this behavior is possible via the overrides feature. -The email verification link is of the format: `^{appInfo.websiteDomain}/^{appInfo.websiteBasePath}/verify-email?token=...&tenantId=....` - -## Post link clicked screen - +The email verification link is of the format: `//auth/verify-email?token=...&tenantId=....` + + ### If a session exists In this case, the API automatically consumes the email verification link and shows the following UI. -Email verification success +Email verification success Clicking on the continue button takes the user to the post sign in / up page (`/` by default). @@ -79,7 +64,7 @@ In this case, the user must do an interaction before calling the API to consume The user first sees this screen -Email verification no session prompt +Email verification no session prompt And then after they click on continue, they see the same screen as when a session did exist. @@ -87,140 +72,131 @@ And then after they click on continue, they see the same screen as when a sessio If the user clicks on an email link that has expired, they see the following UI. -Email verification no session prompt +Email verification no session prompt After clicking continue, they return to the email sent screen (if a session exists), or to the sign in page (if a session doesn't exist). - -## General error UI + + If there are network related errors, or the backend sends a status code >= 300, then the following UI appears. -Email verification generic error +Email verification generic error The below appears if something went wrong when the user clicked on the email verification link. To try again, they have to reload the page. -Email verification link clicked generic error - -## Default email UI +Email verification link clicked generic error + + The default email sent for email verification appears below. The backend SDK sends it, which calls `https://api.supertokens.com` (the API infrastructure). Follow the link at the end of this page to see how you can change the email content or delivery method. -Email UI for email verification email - +Email UI for email verification email + --- ## Password reset - - -## Enter email form + + This appears when the user clicks on the "Forgot password" button in the sign in form. You can view it if you visit `/${websiteBasePath}/reset-password` path of your website (default is `/auth/reset-password`). -Enter email in reset password form +Enter email in reset password form Once the user enters their email and clicks on the "Email" button, SuperTokens sends them an email only if that email belongs to an account. Regardless, the user always sees a success state: -Email sent in reset password form - -## Enter new password form - +Email sent in reset password form + + This form appears when the user clicks on the password reset link sent to their email. To view this form, you can navigate to `/${websiteBasePath}/reset-password?token=test` path of your website (default is `/auth/reset-password?token=test`). Notice that the URL path is the same as that of the enter email form. However, there is an extra query parameter `token` which tells SuperTokens to show the enter new password form. If you try and submit a new password with the `test` token value, it fails since it's not a valid password reset token. -Enter new password form +Enter new password form If the reset token has expired or is invalid, the user sees the following message. -Enter new password for invalid token +Enter new password for invalid token Once the user has successfully changed their password, they see the following success screen -Password change successful +Password change successful -:::info Multi tenancy +:::info[Multi tenancy] For multi tenant use case, the password reset token also includes a `tenantId` query parameter which identifies the tenant for which the system created the password reset token. ::: - -## General error UI + + If there are network related errors, or the backend sends a status code >= 300, then the following UI appears. -Enter email general error - -Enter new password general error - -## Password reset email UI +Enter email general error +Enter new password general error + + The default email sent for password reset appears below. The backend SDK sends it, which calls `https://api.supertokens.com` (the API infrastructure). See the links at the end of this page to change the email content or delivery method. -Email UI for password reset email - - +Email UI for password reset email + --- ## Passwordless login - - -## Email or phone input UI - + + If the `contactMethod` is `EMAIL_OR_PHONE`, the user sees the following UI when they visit the login page. -Email and phone passwordless login +Email and phone passwordless login If the user decides to use their phone number and enters a valid phone number with their country code extension, they proceed to the next step. Otherwise, they see an error message asking them to also enter their country code. The UI also changes to show a dropdown containing a list of all countries (equal to the "Only phone input UI" shown below). - -## Only email input UI + + If the `contactMethod` is `EMAIL`, the user sees the following UI when they visit the login page. -Email only passwordless login - -## Only phone input UI +Email only passwordless login + + If the `contactMethod` is `PHONE`, the user sees the following UI when they visit the login page. -Phone only passwordless login - -## Invalid email or phone input UI +Phone only passwordless login + + If the user enters an invalid phone or email, they see the following message -Invalid phone or email - -## Magic link sent screen - +Invalid phone or email + + If the value of `flowType` on the backend is `MAGIC_LINK`, then after the user has submitted their phone or email, they see the following UI. -Magic link sent UI +Magic link sent UI As you can see, a timer makes the user wait for a certain time (15 seconds by default) before they can resend the SMS / email. A button below the input allows them to change the email / SMS (the text on the button changes based on if the user entered an email or phone number). - -## Magic link clicked screens - -The magic link is of the format: `^{appInfo.websiteDomain}/^{appInfo.websiteBasePath}/verify?tenantId=...&preAuthSessionId=#`. + + +The magic link is of the format: `//auth/verify?tenantId=...&preAuthSessionId=#`. ### On same device When the user clicks the magic link and opens it on the same device on which they initiated the flow, they see the following UI before redirecting to the sign in success page (`/` by default). On this screen, SuperTokens automatically extracts the two tokens from the magic link URL. It tries to consume them on the backend to log the user in. -Magic link consumed +Magic link consumed ### On different device If the user opens the magic link on a different device, they must take an action before consuming tokens from the link. This prevents email clients from automatically consuming the tokens if they crawl links in the email. -Magic link consumed on different device +Magic link consumed on different device ### Invalid / expired magic link UI If the user clicks on an invalid magic link or if the token in the magic link has expired, they see the login screen with the following message -Invalid magic link - -## Enter OTP screen - +Invalid magic link + + If login via OTP is active, then the user sees this screen immediately after their enter their phone number / email. -Enter OTP screen +Enter OTP screen As you can see, a timer makes the user wait for a certain time (15 seconds by default) before they can resend the SMS / email. A button below the input allows them to change the email / SMS (the text on the button changes based on if the user entered an email or phone number). @@ -228,36 +204,34 @@ As you can see, a timer makes the user wait for a certain time (15 seconds by de If the user enters an incorrect OTP, this is what they see. -Invalid OTP +Invalid OTP Entering an incorrect OTP too many times results in the user navigating back to the login screen with the following message. -Entered invalid OTP too many times +Entered invalid OTP too many times ### Logging in via OTP and Magic link simultaneously An edge case occurs wherein the end user gets both an OTP and a magic link. Whilst viewing the enter OTP screen, they also click on the magic link. The magic link click opens a new tab and consumes the link to log the user in. The enter OTP screen continues to show the enter OTP UI until the user refreshes the page. After the refresh, it redirects to the post login screen. - -## Default email and SMS template - + + You can find the email and SMS templates along with their UI [in one of the GitHub repositories](https://github.com/supertokens/email-sms-templates). You can change the content of the email & SMSs and / or how they send. For more information on this, please see the links at the end of this page. - -## General errors - + + If there are network related errors, or the backend sends a status code >= 300, then the following UI shows. This UI also appears if there is a similar error in the callback page. -Login screen general error +Login screen general error -Enter OTP screen general error +Enter OTP screen general error -Magic link sent screen general error +Magic link sent screen general error The error below appears if something went wrong after the user clicks on the magic link. Reloading the page should result in a reattempt -Email verification link clicked generic error - +Email verification link clicked generic error + --- @@ -266,28 +240,23 @@ The error below appears if something went wrong after the user clicks on the mag You can see the default UI when you visit the `websiteBasePath` (`/auth` by default) on your website. - - -## Default social login button UI - -Sign in form UI for social login - -## Callback page UI + + +Sign in form UI for social login + + When the user navigates back to your application from the third party provider, they see the following UI. On this screen, SuperTokens takes the authorisation code from the URL (sent by the provider) and sends it to the backend. The backend exchanges that for the user's access token and information. -Callback screen from third party provider. - - -## Sign in / up unsuccessful UI - +Callback screen from third party provider. + + SuperTokens requires that the third party provider gives an email for the user. If that's not the case for a certain provider, the user sees the following UI. -No email UI for provider - -## General error UI - +No email UI for provider + + If there are network related errors, or the backend sends a status code >= 300, then the following UI shows. This UI also appears if there is a similar error in the callback page. -Sign in form general error - +Sign in form general error + diff --git a/docs/references/frontend-sdks/reference.mdx b/docs/references/frontend-sdks/reference.mdx index 2cdfebabaf..e7fe08d69c 100644 --- a/docs/references/frontend-sdks/reference.mdx +++ b/docs/references/frontend-sdks/reference.mdx @@ -1,18 +1,10 @@ --- title: Reference -hide_title: true -sidebar_position: 1 -description: >- - Override frontend authentication functions using SuperTokens for custom - session and user sign-up logic. -page_type: overview -category: frontend-sdk +description: Override frontend authentication functions using SuperTokens for custom session and user sign-up logic. +sidebar: + order: 1 --- - -# Frontend SDKs - - ## Overview SuperTokens exposes SDKs for frontend frameworks. @@ -20,93 +12,62 @@ Use this page to find references to each of them and about specific functionalit ## Customization - - - - Function overrides - - + + + + + + - - - Hooks - - + - - - Component override - - + - - - Prebuilt UI styling - - + - - - Prebuilt UI theming - - + - - - Translations - - + + - + + + + + + + ## SDK references - - - - - ReactJS - - - - - - - Vanilla JS - - - - - - - React Native - - - - - - - iOS - - - - - - - Android - - - - - - - Flutter - - - + + + + + + + + + + + + + + + + + + + + + + + + + ## SDK configuration @@ -124,18 +85,15 @@ let appInfo: { } ``` - - -## `appName` - + + This is the name of your application. Use it when sending password reset or email verification emails (in the default email design). An example of this is `appName: "GitHub"`. -
- -## `websiteDomain` - +
+
+ This is the domain part of your website. This is where the login UI appears. For example: @@ -148,10 +106,9 @@ By default, the login UI appears on `{websiteDomain}/auth/*`. This configuration On the frontend, the domain serves routing purposes, and on the backend, it generates correct email verification and password reset links. -
- -## `apiDomain` - +
+
+ This is the domain part of your API endpoint that the frontend talks to. For example: - For local development, you are likely using `localhost` with some port (ex `9000`). Then the value of this should be `"http://localhost:9000"`. - If your frontend queries `https://api.example.com/*`, then the value of this should be `"https://api.example.com"` @@ -159,25 +116,21 @@ This is the domain part of your API endpoint that the frontend talks to. For exa By default, the login widgets query `{apiDomain}/auth/*`. This configuration can change by using the `apiBasePath` configuration. -
- -## `websiteBasePath` - +
+
+ By default, the login UI appears on `{websiteDomain}/auth`. Other authentication-related user interfaces appear on `{websiteDomain}/auth/*`. If you want to change the `/auth` to something else, then you must set this value. For example: - If you want the login UI to show on `{websiteDomain}/user/*`, then the value of this should be `"/user"`. - If you are using a dedicated sub domain for auth, like `https://auth.example.com`, then you probably want the login UI to show up on `https://auth.example.com`. In this case, set this value to `"/"`. -:::important -Remember to set the same value for this parameter on the backend and the frontend. +:::note[Remember to set the same value for this parameter on the backend and the frontend.] ::: -
- - -## `apiBasePath` - +
+
+ By default, the frontend SDK queries `{apiDomain}/auth/*`. If you want to change the `/auth` to something else, then you must set this value. For example: @@ -185,22 +138,18 @@ If you want to change the `/auth` to something else, then you must set this valu - If you want to scope the APIs not via `/auth` but via some other string like `/supertokens`, then you can set the value of this to `"/supertokens"`. This means, the APIs appear on `{apiDomain}/supertokens/*`. - If you do not want to scope the APIs at all, then you can set the values of this to be `"/"`. This means the APIs are available on `{apiDomain}/*` -:::important -Remember to set the same value for this parameter on the backend and the frontend. +:::note[Remember to set the same value for this parameter on the backend and the frontend.] ::: -:::caution -Note that setting a custom `apiBasePath` updates the refresh API path, this can cause an issue where previously issued refresh tokens no longer get sent to the new API endpoint and the user logs out. +:::warning[Note that setting a custom `apiBasePath` updates the refresh API path, this can cause an issue where previously issued refresh tokens no longer get sent to the new API endpoint and the user logs out.] For example, the default `apiBasePath` value is `/auth`, if it changes to `/supertokens`, then your refresh endpoint updates from `/auth/session/refresh` to `/supertokens/session/refresh`. Previously issued refresh tokens do not get sent to the new API endpoint and the user logs out. ::: -
- -## `apiGatewayPath` - -:::note -Most relevant if you are using an API gateway or reverse proxy +
+
+ +:::note[Most relevant if you are using an API gateway or reverse proxy] ::: If you are using an API gateway (like the one provided by AWS) or a reverse proxy (like Nginx), it may add a path to your API endpoints to scope them for different development environments. @@ -215,8 +164,6 @@ For these situations, you should set the `apiGatewayPath` to `/dev` or `/prod`. The reason for this distinction between `apiGatewayPath` and `apiBasePath` is that when routing, the backend SDK does not see the `apiGatewayPath` path from the request as the gateway removes them. Taking the above example, whilst the frontend queries `{apiDomain}/development/supertokens/*`, the backend SDK sees `{apiDomain}/supertokens/*`. -
- +
+
- - diff --git a/docs/references/frontend-sdks/supertokens-auth-react/_category_.json b/docs/references/frontend-sdks/supertokens-auth-react/_category_.json deleted file mode 100644 index 10cdca488a..0000000000 --- a/docs/references/frontend-sdks/supertokens-auth-react/_category_.json +++ /dev/null @@ -1 +0,0 @@ -{"label":"React SDK Reference","position":3} \ No newline at end of file diff --git a/docs/references/frontend-sdks/supertokens-auth-react/meta.ts b/docs/references/frontend-sdks/supertokens-auth-react/meta.ts new file mode 100644 index 0000000000..d1f36b014e --- /dev/null +++ b/docs/references/frontend-sdks/supertokens-auth-react/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "React SDK Reference", + "icon": "/img/logos/react.svg", + "order": 3 +}); diff --git a/docs/references/frontend-sdks/supertokens-auth-react/package.mdx b/docs/references/frontend-sdks/supertokens-auth-react/package.mdx index fb166e9e52..d77e415814 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/package.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/package.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react -page_title: SuperTokens React -sidebar_position: 1 description: References documentation for the supertokens-auth-react package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 1 --- -# SuperTokens React - - ## Classes ### default @@ -71,7 +64,7 @@ Defined in: [index.ts:36](https://github.com/supertokens/supertokens-auth-react/ | Parameter | Type | | ------ | ------ | -| `config` | [`SuperTokensConfig`](types.mdx#supertokensconfig) | +| `config` | [`SuperTokensConfig`](types#supertokensconfig) | ###### Returns @@ -125,12 +118,12 @@ Defined in: [index.ts:48](https://github.com/supertokens/supertokens-auth-react/ | Parameter | Type | | ------ | ------ | -| `options?` | \{ `navigate?`: [`Navigate`](types.mdx#navigate-1); `queryParams?`: `any`; `redirectBack?`: `boolean`; `show?`: `"signin"` \| `"signup"`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `options.navigate?` | [`Navigate`](types.mdx#navigate-1) | +| `options?` | \{ `navigate?`: [`Navigate`](types#navigate-1); `queryParams?`: `any`; `redirectBack?`: `boolean`; `show?`: `"signin"` \| `"signup"`; `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `options.navigate?` | [`Navigate`](types#navigate-1) | | `options.queryParams?` | `any` | | `options.redirectBack?` | `boolean` | | `options.show?` | `"signin"` \| `"signup"` | -| `options.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `options.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -180,7 +173,7 @@ Defined in: [index.ts:75](https://github.com/supertokens/supertokens-auth-react/ | Parameter | Type | | ------ | ------ | -| `config` | [`SuperTokensConfig`](types.mdx#supertokensconfig) | +| `config` | [`SuperTokensConfig`](types#supertokensconfig) | #### Returns @@ -240,12 +233,12 @@ Defined in: [index.ts:78](https://github.com/supertokens/supertokens-auth-react/ | Parameter | Type | | ------ | ------ | -| `options?` | \{ `navigate?`: [`Navigate`](types.mdx#navigate-1); `queryParams?`: `any`; `redirectBack?`: `boolean`; `show?`: `"signin"` \| `"signup"`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `options.navigate?` | [`Navigate`](types.mdx#navigate-1) | +| `options?` | \{ `navigate?`: [`Navigate`](types#navigate-1); `queryParams?`: `any`; `redirectBack?`: `boolean`; `show?`: `"signin"` \| `"signup"`; `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `options.navigate?` | [`Navigate`](types#navigate-1) | | `options.queryParams?` | `any` | | `options.redirectBack?` | `boolean` | | `options.show?` | `"signin"` \| `"signup"` | -| `options.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `options.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -302,25 +295,25 @@ Defined in: [translation/translationHelpers.ts:77](https://github.com/supertoken ### SuperTokensConfig -Re-exports [SuperTokensConfig](types.mdx#supertokensconfig) +Re-exports [SuperTokensConfig](types#supertokensconfig) *** ### SuperTokensPlugin -Re-exports [SuperTokensPlugin](types.mdx#supertokensplugin) +Re-exports [SuperTokensPlugin](types#supertokensplugin) *** ### SuperTokensPublicConfig -Re-exports [SuperTokensPublicConfig](types.mdx#supertokenspublicconfig) +Re-exports [SuperTokensPublicConfig](types#supertokenspublicconfig) *** ### SuperTokensPublicPlugin -Re-exports [SuperTokensPublicPlugin](types.mdx#supertokenspublicplugin) +Re-exports [SuperTokensPublicPlugin](types#supertokenspublicplugin) *** diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword-types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword-types.mdx index bf95a554f8..959d15530b 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword-types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/emailpassword/types -page_title: EmailPassword Types -sidebar_position: 2 description: References documentation for the supertokens-auth-react/recipe/emailpassword/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 2 --- -# EmailPassword Types - - ## Type Aliases ### ComponentOverrideMap @@ -26,10 +19,10 @@ Defined in: [recipe/emailpassword/types.ts:43](https://github.com/supertokens/su | Property | Type | Defined in | | ------ | ------ | ------ | -| `EmailPasswordResetPasswordEmail_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/emailpassword/types.ts:46](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L46) | -| `EmailPasswordSignInForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/emailpassword/types.ts:44](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L44) | -| `EmailPasswordSignUpForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/emailpassword/types.ts:45](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L45) | -| `EmailPasswordSubmitNewPassword_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/emailpassword/types.ts:47](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L47) | +| `EmailPasswordResetPasswordEmail_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/emailpassword/types.ts:46](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L46) | +| `EmailPasswordSignInForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/emailpassword/types.ts:44](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L44) | +| `EmailPasswordSignUpForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/emailpassword/types.ts:45](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L45) | +| `EmailPasswordSubmitNewPassword_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/emailpassword/types.ts:47](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L47) | *** @@ -60,7 +53,7 @@ Defined in: [recipe/emailpassword/types.ts:308](https://github.com/supertokens/s | `error` | `string` \| `undefined` | [recipe/emailpassword/types.ts:310](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L310) | | `onBackButtonClicked()` | () => `void` | [recipe/emailpassword/types.ts:314](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L314) | | `onError()` | (`error`) => `void` | [recipe/emailpassword/types.ts:312](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L312) | -| `recipeImplementation` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/emailpassword/types.ts:309](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L309) | +| `recipeImplementation` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/emailpassword/types.ts:309](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L309) | *** @@ -198,7 +191,7 @@ Defined in: [recipe/emailpassword/types.ts:64](https://github.com/supertokens/su | Name | Type | Defined in | | ------ | ------ | ------ | | `override` | `object` | [recipe/emailpassword/types.ts:67](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L67) | -| `override.functions()` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/emailpassword/types.ts:68](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L68) | +| `override.functions()` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/emailpassword/types.ts:68](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L68) | | `resetPasswordUsingTokenFeature` | [`NormalisedResetPasswordUsingTokenFeatureConfig`](#normalisedresetpasswordusingtokenfeatureconfig) | [recipe/emailpassword/types.ts:66](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L66) | | `signInAndUpFeature` | [`NormalisedSignInAndUpFeatureConfig`](#normalisedsigninandupfeatureconfig) | [recipe/emailpassword/types.ts:65](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L65) | @@ -216,7 +209,7 @@ Defined in: [recipe/emailpassword/types.ts:173](https://github.com/supertokens/s | Name | Type | Defined in | | ------ | ------ | ------ | -| `formFields` | [`NormalisedFormField`](types.mdx#normalisedformfield)[] | [recipe/emailpassword/types.ts:174](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L174) | +| `formFields` | [`NormalisedFormField`](types#normalisedformfield)[] | [recipe/emailpassword/types.ts:174](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L174) | *** @@ -267,7 +260,7 @@ Defined in: [recipe/emailpassword/types.ts:126](https://github.com/supertokens/s | Name | Type | Defined in | | ------ | ------ | ------ | -| `formFields` | [`NormalisedFormField`](types.mdx#normalisedformfield)[] | [recipe/emailpassword/types.ts:130](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L130) | +| `formFields` | [`NormalisedFormField`](types#normalisedformfield)[] | [recipe/emailpassword/types.ts:130](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L130) | *** @@ -283,7 +276,7 @@ Defined in: [recipe/emailpassword/types.ts:110](https://github.com/supertokens/s | Name | Type | Defined in | | ------ | ------ | ------ | -| `formFields` | [`NormalisedFormField`](types.mdx#normalisedformfield) & `object`[] | [recipe/emailpassword/types.ts:114](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L114) | +| `formFields` | [`NormalisedFormField`](types#normalisedformfield) & `object`[] | [recipe/emailpassword/types.ts:114](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L114) | *** @@ -299,7 +292,7 @@ Defined in: [recipe/emailpassword/types.ts:169](https://github.com/supertokens/s | Name | Type | Defined in | | ------ | ------ | ------ | -| `formFields` | [`NormalisedFormField`](types.mdx#normalisedformfield)[] | [recipe/emailpassword/types.ts:170](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L170) | +| `formFields` | [`NormalisedFormField`](types#normalisedformfield)[] | [recipe/emailpassword/types.ts:170](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L170) | *** @@ -360,7 +353,7 @@ Defined in: [recipe/emailpassword/types.ts:251](https://github.com/supertokens/s | `action` | [`PreAndPostAPIHookAction`](#preandpostapihookaction) | [recipe/emailpassword/types.ts:255](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L255) | | `requestInit` | `RequestInit` | [recipe/emailpassword/types.ts:260](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L260) | | `url` | `string` | [recipe/emailpassword/types.ts:265](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L265) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/emailpassword/types.ts:266](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L266) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/emailpassword/types.ts:266](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L266) | *** @@ -379,7 +372,7 @@ Defined in: [recipe/emailpassword/types.ts:301](https://github.com/supertokens/s | `config` | [`NormalisedConfig`](#normalisedconfig) | [recipe/emailpassword/types.ts:304](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L304) | | `enterEmailForm` | [`EnterEmailProps`](#enteremailprops) | [recipe/emailpassword/types.ts:302](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L302) | | `submitNewPasswordForm` | [`SubmitNewPasswordProps`](#submitnewpasswordprops) \| `undefined` | [recipe/emailpassword/types.ts:303](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L303) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/emailpassword/types.ts:305](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L305) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/emailpassword/types.ts:305](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L305) | *** @@ -396,8 +389,8 @@ Defined in: [recipe/emailpassword/types.ts:135](https://github.com/supertokens/s | Property | Type | Defined in | | ------ | ------ | ------ | | `disableDefaultUI?` | `boolean` | [recipe/emailpassword/types.ts:139](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L139) | -| `enterEmailForm?` | [`FeatureBaseConfig`](types.mdx#featurebaseconfig) | [recipe/emailpassword/types.ts:149](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L149) | -| `submitNewPasswordForm?` | [`FeatureBaseConfig`](types.mdx#featurebaseconfig) | [recipe/emailpassword/types.ts:144](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L144) | +| `enterEmailForm?` | [`FeatureBaseConfig`](types#featurebaseconfig) | [recipe/emailpassword/types.ts:149](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L149) | +| `submitNewPasswordForm?` | [`FeatureBaseConfig`](types#featurebaseconfig) | [recipe/emailpassword/types.ts:144](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L144) | *** @@ -452,8 +445,8 @@ Defined in: [recipe/emailpassword/types.ts:186](https://github.com/supertokens/s | `onFetchError()` | (`error`) => `void` | [recipe/emailpassword/types.ts:189](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L189) | | `onForgotPasswordClick()` | () => `void` | [recipe/emailpassword/types.ts:192](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L192) | | `onSuccess()` | (`result`) => `void` | [recipe/emailpassword/types.ts:193](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L193) | -| `recipeImplementation` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/emailpassword/types.ts:187](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L187) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/emailpassword/types.ts:194](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L194) | +| `recipeImplementation` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/emailpassword/types.ts:187](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L187) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/emailpassword/types.ts:194](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L194) | *** @@ -469,7 +462,7 @@ Defined in: [recipe/emailpassword/types.ts:101](https://github.com/supertokens/s | Name | Type | Defined in | | ------ | ------ | ------ | -| `formFields?` | [`FormField`](types.mdx#formfield) & `object`[] | [recipe/emailpassword/types.ts:105](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L105) | +| `formFields?` | [`FormField`](types#formfield) & `object`[] | [recipe/emailpassword/types.ts:105](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L105) | *** @@ -492,9 +485,9 @@ Defined in: [recipe/emailpassword/types.ts:197](https://github.com/supertokens/s | `onError()` | (`error`) => `void` | [recipe/emailpassword/types.ts:201](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L201) | | `onFetchError()` | (`error`) => `void` | [recipe/emailpassword/types.ts:200](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L200) | | `onSuccess()` | (`result`) => `void` | [recipe/emailpassword/types.ts:204](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L204) | -| `recipeImplementation` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/emailpassword/types.ts:198](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L198) | +| `recipeImplementation` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/emailpassword/types.ts:198](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L198) | | `signInClicked()?` | () => `void` | [recipe/emailpassword/types.ts:203](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L203) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/emailpassword/types.ts:207](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L207) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/emailpassword/types.ts:207](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L207) | *** @@ -515,7 +508,7 @@ Defined in: [recipe/emailpassword/types.ts:317](https://github.com/supertokens/s | `error` | `string` \| `undefined` | [recipe/emailpassword/types.ts:319](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L319) | | `onError()` | (`error`) => `void` | [recipe/emailpassword/types.ts:321](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L321) | | `onSignInClicked()` | () => `void` | [recipe/emailpassword/types.ts:323](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L323) | -| `recipeImplementation` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/emailpassword/types.ts:318](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L318) | +| `recipeImplementation` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/emailpassword/types.ts:318](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L318) | | `token` | `string` | [recipe/emailpassword/types.ts:324](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L324) | *** @@ -543,6 +536,6 @@ Defined in: [recipe/emailpassword/types.ts:50](https://github.com/supertokens/su | Name | Type | Defined in | | ------ | ------ | ------ | | `override?` | `object` | [recipe/emailpassword/types.ts:53](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L53) | -| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/emailpassword/types.ts:54](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L54) | +| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/emailpassword/types.ts:54](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L54) | | `resetPasswordUsingTokenFeature?` | [`ResetPasswordUsingTokenUserInput`](#resetpasswordusingtokenuserinput) | [recipe/emailpassword/types.ts:52](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L52) | | `signInAndUpFeature?` | [`SignInAndUpFeatureUserInput`](#signinandupfeatureuserinput) | [recipe/emailpassword/types.ts:51](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailpassword/types.ts#L51) | diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword.mdx index cd089b9efe..873e016ffc 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/emailpassword -page_title: EmailPassword -sidebar_position: 2 description: References documentation for the supertokens-auth-react/recipe/emailpassword package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 2 --- -# EmailPassword - - ## Classes ### default @@ -54,10 +47,10 @@ Defined in: [recipe/emailpassword/index.ts:170](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.email` | `string` | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -79,8 +72,8 @@ Defined in: [recipe/emailpassword/index.ts:185](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -98,7 +91,7 @@ Defined in: [recipe/emailpassword/index.ts:30](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-emailpassword-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-emailpassword-types#userinput) | ###### Returns @@ -125,10 +118,10 @@ Defined in: [recipe/emailpassword/index.ts:71](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.formFields` | `object`[] | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -174,11 +167,11 @@ Defined in: [recipe/emailpassword/index.ts:132](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.formFields` | `object`[] | | `input.options?` | `RecipeFunctionOptions` | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -215,8 +208,8 @@ Defined in: [recipe/emailpassword/index.ts:34](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -249,11 +242,11 @@ Defined in: [recipe/emailpassword/index.ts:98](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.formFields` | `object`[] | | `input.options?` | `RecipeFunctionOptions` | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -299,10 +292,10 @@ Defined in: [recipe/emailpassword/index.ts:40](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.formFields` | `object`[] | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -339,10 +332,10 @@ Defined in: [recipe/emailpassword/index.ts:201](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.email` | `string` | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -376,8 +369,8 @@ Defined in: [recipe/emailpassword/index.ts:202](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -397,7 +390,7 @@ Defined in: [recipe/emailpassword/index.ts:195](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-emailpassword-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-emailpassword-types#userinput) | #### Returns @@ -426,10 +419,10 @@ Defined in: [recipe/emailpassword/index.ts:198](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.formFields` | `object`[] | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -477,11 +470,11 @@ Defined in: [recipe/emailpassword/index.ts:200](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.formFields` | `object`[] | | `input.options?` | `RecipeFunctionOptions` | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -520,8 +513,8 @@ Defined in: [recipe/emailpassword/index.ts:196](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -556,11 +549,11 @@ Defined in: [recipe/emailpassword/index.ts:199](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.formFields` | `object`[] | | `input.options?` | `RecipeFunctionOptions` | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -608,10 +601,10 @@ Defined in: [recipe/emailpassword/index.ts:197](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `formFields`: `object`[]; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.formFields` | `object`[] | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -634,28 +627,28 @@ Defined in: [recipe/emailpassword/index.ts:197](https://github.com/supertokens/s ### GetRedirectionURLContext -Re-exports [GetRedirectionURLContext](recipe-emailpassword-types.mdx#getredirectionurlcontext) +Re-exports [GetRedirectionURLContext](recipe-emailpassword-types#getredirectionurlcontext) *** ### OnHandleEventContext -Re-exports [OnHandleEventContext](recipe-emailpassword-types.mdx#onhandleeventcontext) +Re-exports [OnHandleEventContext](recipe-emailpassword-types#onhandleeventcontext) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-emailpassword-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-emailpassword-types#preapihookcontext) *** ### RecipeInterface -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### UserInput -Re-exports [UserInput](recipe-emailpassword-types.mdx#userinput) +Re-exports [UserInput](recipe-emailpassword-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification-types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification-types.mdx index d55ec1fa04..1d5fdda774 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification-types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/emailverification/types -page_title: EmailVerification Types -sidebar_position: 3 description: References documentation for the supertokens-auth-react/recipe/emailverification/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 3 --- -# EmailVerification Types - - ## Type Aliases ### ComponentOverrideMap @@ -26,8 +19,8 @@ Defined in: [recipe/emailverification/types.ts:27](https://github.com/supertoken | Property | Type | Defined in | | ------ | ------ | ------ | -| `EmailVerificationSendVerifyEmail_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/emailverification/types.ts:28](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L28) | -| `EmailVerificationVerifyEmailLinkClicked_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/emailverification/types.ts:29](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L29) | +| `EmailVerificationSendVerifyEmail_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/emailverification/types.ts:28](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L28) | +| `EmailVerificationVerifyEmailLinkClicked_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/emailverification/types.ts:29](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L29) | *** @@ -55,7 +48,7 @@ Defined in: [recipe/emailverification/types.ts:82](https://github.com/supertoken | ------ | ------ | ------ | | `config` | [`NormalisedConfig`](#normalisedconfig) | [recipe/emailverification/types.ts:85](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L85) | | `sendVerifyEmailScreen` | [`SendVerifyEmailThemeProps`](#sendverifyemailthemeprops) | [recipe/emailverification/types.ts:83](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L83) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/emailverification/types.ts:86](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L86) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/emailverification/types.ts:86](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L86) | | `verifyEmailLinkClickedScreen?` | [`VerifyEmailLinkClickedThemeProps`](#verifyemaillinkclickedthemeprops) | [recipe/emailverification/types.ts:84](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L84) | *** @@ -87,9 +80,9 @@ Defined in: [recipe/emailverification/types.ts:51](https://github.com/supertoken | `disableDefaultUI` | `boolean` | [recipe/emailverification/types.ts:53](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L53) | | `mode` | `"OPTIONAL"` \| `"REQUIRED"` | [recipe/emailverification/types.ts:52](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L52) | | `override` | `object` | [recipe/emailverification/types.ts:56](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L56) | -| `override.functions()` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/emailverification/types.ts:57](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L57) | -| `sendVerifyEmailScreen` | [`FeatureBaseConfig`](types.mdx#featurebaseconfig) | [recipe/emailverification/types.ts:54](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L54) | -| `verifyEmailLinkClickedScreen` | [`FeatureBaseConfig`](types.mdx#featurebaseconfig) | [recipe/emailverification/types.ts:55](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L55) | +| `override.functions()` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/emailverification/types.ts:57](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L57) | +| `sendVerifyEmailScreen` | [`FeatureBaseConfig`](types#featurebaseconfig) | [recipe/emailverification/types.ts:54](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L54) | +| `verifyEmailLinkClickedScreen` | [`FeatureBaseConfig`](types#featurebaseconfig) | [recipe/emailverification/types.ts:55](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L55) | *** @@ -106,7 +99,7 @@ Defined in: [recipe/emailverification/types.ts:77](https://github.com/supertoken | Property | Type | Defined in | | ------ | ------ | ------ | | `action` | `"VERIFY_EMAIL_SENT"` \| `"EMAIL_VERIFIED_SUCCESSFUL"` | [recipe/emailverification/types.ts:78](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L78) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/emailverification/types.ts:79](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L79) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/emailverification/types.ts:79](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L79) | *** @@ -135,7 +128,7 @@ Defined in: [recipe/emailverification/types.ts:70](https://github.com/supertoken | `action` | [`PreAndPostAPIHookAction`](#preandpostapihookaction) | [recipe/emailverification/types.ts:71](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L71) | | `requestInit` | `RequestInit` | [recipe/emailverification/types.ts:72](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L72) | | `url` | `string` | [recipe/emailverification/types.ts:73](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L73) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/emailverification/types.ts:74](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L74) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/emailverification/types.ts:74](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L74) | *** @@ -153,7 +146,7 @@ Defined in: [recipe/emailverification/types.ts:89](https://github.com/supertoken | ------ | ------ | ------ | | `config` | [`NormalisedConfig`](#normalisedconfig) | [recipe/emailverification/types.ts:91](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L91) | | `onEmailAlreadyVerified()` | () => `Promise`\<`void`\> | [recipe/emailverification/types.ts:93](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L93) | -| `recipeImplementation` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/emailverification/types.ts:90](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L90) | +| `recipeImplementation` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/emailverification/types.ts:90](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L90) | | `redirectToAuth()` | () => `Promise`\<`void`\> | [recipe/emailverification/types.ts:94](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L94) | | `signOut()` | () => `Promise`\<`void`\> | [recipe/emailverification/types.ts:92](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L92) | @@ -174,9 +167,9 @@ Defined in: [recipe/emailverification/types.ts:33](https://github.com/supertoken | `disableDefaultUI?` | `boolean` | [recipe/emailverification/types.ts:35](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L35) | | `mode?` | `"OPTIONAL"` \| `"REQUIRED"` | [recipe/emailverification/types.ts:34](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L34) | | `override?` | `object` | [recipe/emailverification/types.ts:39](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L39) | -| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/emailverification/types.ts:40](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L40) | -| `sendVerifyEmailScreen?` | [`FeatureBaseConfig`](types.mdx#featurebaseconfig) | [recipe/emailverification/types.ts:36](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L36) | -| `verifyEmailLinkClickedScreen?` | [`FeatureBaseConfig`](types.mdx#featurebaseconfig) | [recipe/emailverification/types.ts:37](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L37) | +| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/emailverification/types.ts:40](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L40) | +| `sendVerifyEmailScreen?` | [`FeatureBaseConfig`](types#featurebaseconfig) | [recipe/emailverification/types.ts:36](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L36) | +| `verifyEmailLinkClickedScreen?` | [`FeatureBaseConfig`](types#featurebaseconfig) | [recipe/emailverification/types.ts:37](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L37) | *** @@ -195,5 +188,5 @@ Defined in: [recipe/emailverification/types.ts:97](https://github.com/supertoken | `config` | [`NormalisedConfig`](#normalisedconfig) | [recipe/emailverification/types.ts:99](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L99) | | `onSuccess()` | () => `Promise`\<`void`\> | [recipe/emailverification/types.ts:100](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L100) | | `onTokenInvalidRedirect()` | () => `Promise`\<`void`\> | [recipe/emailverification/types.ts:101](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L101) | -| `recipeImplementation` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/emailverification/types.ts:98](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L98) | +| `recipeImplementation` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/emailverification/types.ts:98](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L98) | | `token` | `string` | [recipe/emailverification/types.ts:102](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/emailverification/types.ts#L102) | diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification.mdx index e94dfd1bbf..c09ddc69a0 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/emailverification -page_title: EmailVerification -sidebar_position: 3 description: References documentation for the supertokens-auth-react/recipe/emailverification package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 3 --- -# EmailVerification - - ## Classes ### default @@ -51,8 +44,8 @@ Defined in: [recipe/emailverification/index.ts:72](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -70,7 +63,7 @@ Defined in: [recipe/emailverification/index.ts:34](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-emailverification-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-emailverification-types#userinput) | ###### Returns @@ -92,9 +85,9 @@ Defined in: [recipe/emailverification/index.ts:38](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -119,9 +112,9 @@ Defined in: [recipe/emailverification/index.ts:59](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -145,9 +138,9 @@ Defined in: [recipe/emailverification/index.ts:49](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -190,8 +183,8 @@ Defined in: [recipe/emailverification/index.ts:86](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -211,7 +204,7 @@ Defined in: [recipe/emailverification/index.ts:82](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-emailverification-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-emailverification-types#userinput) | #### Returns @@ -235,9 +228,9 @@ Defined in: [recipe/emailverification/index.ts:83](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -264,9 +257,9 @@ Defined in: [recipe/emailverification/index.ts:85](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -292,9 +285,9 @@ Defined in: [recipe/emailverification/index.ts:84](https://github.com/supertoken | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -307,28 +300,28 @@ Defined in: [recipe/emailverification/index.ts:84](https://github.com/supertoken ### GetRedirectionURLContext -Re-exports [GetRedirectionURLContext](recipe-emailverification-types.mdx#getredirectionurlcontext) +Re-exports [GetRedirectionURLContext](recipe-emailverification-types#getredirectionurlcontext) *** ### OnHandleEventContext -Re-exports [OnHandleEventContext](recipe-emailverification-types.mdx#onhandleeventcontext) +Re-exports [OnHandleEventContext](recipe-emailverification-types#onhandleeventcontext) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-emailverification-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-emailverification-types#preapihookcontext) *** ### RecipeInterface -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### UserInput -Re-exports [UserInput](recipe-emailverification-types.mdx#userinput) +Re-exports [UserInput](recipe-emailverification-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth-types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth-types.mdx index 97fb28c93a..2ca2b18f54 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth-types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/multifactorauth/types -page_title: MFA Types -sidebar_position: 4 description: References documentation for the supertokens-auth-react/recipe/multifactorauth/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 4 --- -# MFA Types - - ## Type Aliases ### ComponentOverrideMap @@ -26,10 +19,10 @@ Defined in: [recipe/multifactorauth/types.ts:32](https://github.com/supertokens/ | Property | Type | Defined in | | ------ | ------ | ------ | -| `MFAFactorChooserFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/multifactorauth/types.ts:33](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L33) | -| `MFAFactorChooserHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/multifactorauth/types.ts:34](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L34) | -| `MFAFactorList_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/multifactorauth/types.ts:35](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L35) | -| `MFAFactorOption_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/multifactorauth/types.ts:36](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L36) | +| `MFAFactorChooserFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/multifactorauth/types.ts:33](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L33) | +| `MFAFactorChooserHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/multifactorauth/types.ts:34](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L34) | +| `MFAFactorList_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/multifactorauth/types.ts:35](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L35) | +| `MFAFactorOption_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/multifactorauth/types.ts:36](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L36) | *** @@ -62,7 +55,7 @@ Defined in: [recipe/multifactorauth/types.ts:112](https://github.com/supertokens | `onBackButtonClicked` | () => `void` | [recipe/multifactorauth/types.ts:116](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L116) | | `onLogoutClicked` | () => `void` | [recipe/multifactorauth/types.ts:118](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L118) | | `showBackButton` | `boolean` | [recipe/multifactorauth/types.ts:115](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L115) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/multifactorauth/types.ts:120](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L120) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/multifactorauth/types.ts:120](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L120) | *** @@ -100,7 +93,7 @@ Defined in: [recipe/multifactorauth/types.ts:106](https://github.com/supertokens | Property | Type | Defined in | | ------ | ------ | ------ | | `emails` | `Record`\<`string`, `string`[] \| `undefined`\> | [recipe/multifactorauth/types.ts:108](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L108) | -| `factors` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/multifactorauth/types.ts:107](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L107) | +| `factors` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/multifactorauth/types.ts:107](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L107) | | `phoneNumbers` | `Record`\<`string`, `string`[] \| `undefined`\> | [recipe/multifactorauth/types.ts:109](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L109) | *** @@ -118,11 +111,11 @@ Defined in: [recipe/multifactorauth/types.ts:61](https://github.com/supertokens/ | Name | Type | Defined in | | ------ | ------ | ------ | | `disableDefaultUI` | `boolean` | [recipe/multifactorauth/types.ts:67](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L67) | -| `factorChooserScreen` | [`FeatureBaseConfig`](types.mdx#featurebaseconfig) | [recipe/multifactorauth/types.ts:68](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L68) | +| `factorChooserScreen` | [`FeatureBaseConfig`](types#featurebaseconfig) | [recipe/multifactorauth/types.ts:68](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L68) | | `firstFactors?` | `string`[] | [recipe/multifactorauth/types.ts:62](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L62) | | `getSecondaryFactorInfo()` | (`builtInFactors`, `userContext`) => [`SecondaryFactorRedirectionInfo`](#secondaryfactorredirectioninfo)[] | [recipe/multifactorauth/types.ts:63](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L63) | | `override` | `object` | [recipe/multifactorauth/types.ts:70](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L70) | -| `override.functions()` | (`originalImplementation`, `builder?`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/multifactorauth/types.ts:71](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L71) | +| `override.functions()` | (`originalImplementation`, `builder?`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/multifactorauth/types.ts:71](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L71) | *** @@ -168,7 +161,7 @@ Defined in: [recipe/multifactorauth/types.ts:94](https://github.com/supertokens/ | `action` | [`PreAndPostAPIHookAction`](#preandpostapihookaction) | [recipe/multifactorauth/types.ts:95](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L95) | | `requestInit` | `RequestInit` | [recipe/multifactorauth/types.ts:96](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L96) | | `url` | `string` | [recipe/multifactorauth/types.ts:97](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L97) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/multifactorauth/types.ts:98](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L98) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/multifactorauth/types.ts:98](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L98) | *** @@ -205,11 +198,11 @@ Defined in: [recipe/multifactorauth/types.ts:40](https://github.com/supertokens/ | Name | Type | Defined in | | ------ | ------ | ------ | | `disableDefaultUI?` | `boolean` | [recipe/multifactorauth/types.ts:46](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L46) | -| `factorChooserScreen?` | [`FeatureBaseConfig`](types.mdx#featurebaseconfig) | [recipe/multifactorauth/types.ts:47](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L47) | +| `factorChooserScreen?` | [`FeatureBaseConfig`](types#featurebaseconfig) | [recipe/multifactorauth/types.ts:47](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L47) | | `firstFactors?` | `string`[] | [recipe/multifactorauth/types.ts:41](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L41) | | `getSecondaryFactorInfo()?` | (`builtInFactors`, `userContext`) => [`SecondaryFactorRedirectionInfo`](#secondaryfactorredirectioninfo)[] | [recipe/multifactorauth/types.ts:42](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L42) | | `override?` | `object` | [recipe/multifactorauth/types.ts:49](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L49) | -| `override.functions()?` | (`originalImplementation`, `builder?`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/multifactorauth/types.ts:50](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L50) | +| `override.functions()?` | (`originalImplementation`, `builder?`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/multifactorauth/types.ts:50](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multifactorauth/types.ts#L50) | ## Variables diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth.mdx index cdf9d99983..09926c1a42 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/multifactorauth -page_title: MFA -sidebar_position: 4 description: References documentation for the supertokens-auth-react/recipe/multifactorauth package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 4 --- -# MFA - - ## Classes ### default @@ -60,8 +53,8 @@ Defined in: [recipe/multifactorauth/index.ts:90](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -79,7 +72,7 @@ Defined in: [recipe/multifactorauth/index.ts:36](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-multifactorauth-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-multifactorauth-types#userinput) | ###### Returns @@ -97,13 +90,13 @@ Defined in: [recipe/multifactorauth/index.ts:56](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `factorId`: `string`; `forceSetup?`: `boolean`; `navigate?`: [`Navigate`](types.mdx#navigate-1); `redirectBack?`: `boolean`; `stepUp?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `factorId`: `string`; `forceSetup?`: `boolean`; `navigate?`: [`Navigate`](types#navigate-1); `redirectBack?`: `boolean`; `stepUp?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.factorId` | `string` | | `input.forceSetup?` | `boolean` | -| `input.navigate?` | [`Navigate`](types.mdx#navigate-1) | +| `input.navigate?` | [`Navigate`](types#navigate-1) | | `input.redirectBack?` | `boolean` | | `input.stepUp?` | `boolean` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -121,12 +114,12 @@ Defined in: [recipe/multifactorauth/index.ts:74](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input` | \{ `navigate?`: [`Navigate`](types.mdx#navigate-1); `nextFactorOptions?`: `string`[]; `redirectBack?`: `boolean`; `stepUp?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.navigate?` | [`Navigate`](types.mdx#navigate-1) | +| `input` | \{ `navigate?`: [`Navigate`](types#navigate-1); `nextFactorOptions?`: `string`[]; `redirectBack?`: `boolean`; `stepUp?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.navigate?` | [`Navigate`](types#navigate-1) | | `input.nextFactorOptions?` | `string`[] | | `input.redirectBack?` | `boolean` | | `input.stepUp?` | `boolean` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -150,9 +143,9 @@ Defined in: [recipe/multifactorauth/index.ts:40](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -178,8 +171,8 @@ Defined in: [recipe/multifactorauth/index.ts:103](https://github.com/supertokens | Parameter | Type | | ------ | ------ | -| `input` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -199,7 +192,7 @@ Defined in: [recipe/multifactorauth/index.ts:99](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-multifactorauth-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-multifactorauth-types#userinput) | #### Returns @@ -239,13 +232,13 @@ Defined in: [recipe/multifactorauth/index.ts:101](https://github.com/supertokens | Parameter | Type | | ------ | ------ | -| `input` | \{ `factorId`: `string`; `forceSetup?`: `boolean`; `navigate?`: [`Navigate`](types.mdx#navigate-1); `redirectBack?`: `boolean`; `stepUp?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `factorId`: `string`; `forceSetup?`: `boolean`; `navigate?`: [`Navigate`](types#navigate-1); `redirectBack?`: `boolean`; `stepUp?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.factorId` | `string` | | `input.forceSetup?` | `boolean` | -| `input.navigate?` | [`Navigate`](types.mdx#navigate-1) | +| `input.navigate?` | [`Navigate`](types#navigate-1) | | `input.redirectBack?` | `boolean` | | `input.stepUp?` | `boolean` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -265,12 +258,12 @@ Defined in: [recipe/multifactorauth/index.ts:102](https://github.com/supertokens | Parameter | Type | | ------ | ------ | -| `input` | \{ `navigate?`: [`Navigate`](types.mdx#navigate-1); `nextFactorOptions?`: `string`[]; `redirectBack?`: `boolean`; `stepUp?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.navigate?` | [`Navigate`](types.mdx#navigate-1) | +| `input` | \{ `navigate?`: [`Navigate`](types#navigate-1); `nextFactorOptions?`: `string`[]; `redirectBack?`: `boolean`; `stepUp?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.navigate?` | [`Navigate`](types#navigate-1) | | `input.nextFactorOptions?` | `string`[] | | `input.redirectBack?` | `boolean` | | `input.stepUp?` | `boolean` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -296,9 +289,9 @@ Defined in: [recipe/multifactorauth/index.ts:100](https://github.com/supertokens | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -314,34 +307,34 @@ Defined in: [recipe/multifactorauth/index.ts:100](https://github.com/supertokens ### FactorIds -Re-exports [FactorIds](recipe-multifactorauth-types.mdx#factorids) +Re-exports [FactorIds](recipe-multifactorauth-types#factorids) *** ### GetRedirectionURLContext -Re-exports [GetRedirectionURLContext](recipe-multifactorauth-types.mdx#getredirectionurlcontext) +Re-exports [GetRedirectionURLContext](recipe-multifactorauth-types#getredirectionurlcontext) *** ### OnHandleEventContext -Re-exports [OnHandleEventContext](recipe-multifactorauth-types.mdx#onhandleeventcontext) +Re-exports [OnHandleEventContext](recipe-multifactorauth-types#onhandleeventcontext) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-multifactorauth-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-multifactorauth-types#preapihookcontext) *** ### RecipeInterface -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### UserInput -Re-exports [UserInput](recipe-multifactorauth-types.mdx#userinput) +Re-exports [UserInput](recipe-multifactorauth-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy-types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy-types.mdx index 41aa7b4031..121661aab6 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy-types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/multitenancy/types -page_title: MultiTenancy Types -sidebar_position: 5 description: References documentation for the supertokens-auth-react/recipe/multitenancy/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 5 --- -# MultiTenancy Types - - ## Type Aliases ### ComponentOverrideMap @@ -26,7 +19,7 @@ Defined in: [recipe/multitenancy/types.ts:40](https://github.com/supertokens/sup | Property | Type | Defined in | | ------ | ------ | ------ | -| `MultitenancyDynamicLoginMethodsSpinnerTheme_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/multitenancy/types.ts:41](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multitenancy/types.ts#L41) | +| `MultitenancyDynamicLoginMethodsSpinnerTheme_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/multitenancy/types.ts:41](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multitenancy/types.ts#L41) | *** @@ -61,7 +54,7 @@ Defined in: [recipe/multitenancy/types.ts:21](https://github.com/supertokens/sup | Name | Type | Defined in | | ------ | ------ | ------ | | `override` | `object` | [recipe/multitenancy/types.ts:22](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multitenancy/types.ts#L22) | -| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/multitenancy/types.ts:23](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multitenancy/types.ts#L23) | +| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/multitenancy/types.ts:23](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multitenancy/types.ts#L23) | *** @@ -88,4 +81,4 @@ Defined in: [recipe/multitenancy/types.ts:12](https://github.com/supertokens/sup | Name | Type | Defined in | | ------ | ------ | ------ | | `override?` | `object` | [recipe/multitenancy/types.ts:13](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multitenancy/types.ts#L13) | -| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/multitenancy/types.ts:14](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multitenancy/types.ts#L14) | +| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/multitenancy/types.ts:14](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/multitenancy/types.ts#L14) | diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy.mdx index c0588853c9..965c469e3f 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/multitenancy -page_title: MultiTenancy -sidebar_position: 5 description: References documentation for the supertokens-auth-react/recipe/multitenancy package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 5 --- -# MultiTenancy - - ## Classes ### default @@ -51,11 +44,11 @@ Defined in: [recipe/multitenancy/index.ts:25](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-multitenancy-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-multitenancy-types#userinput) | ###### Returns -[`RecipeInitResult`](types.mdx#recipeinitresult)\<`any`, `any`, `any`, `any`\> +[`RecipeInitResult`](types#recipeinitresult)\<`any`, `any`, `any`, `any`\> ## Variables @@ -71,11 +64,11 @@ Defined in: [recipe/multitenancy/index.ts:34](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-multitenancy-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-multitenancy-types#userinput) | #### Returns -[`RecipeInitResult`](types.mdx#recipeinitresult)\<`any`, `any`, `any`, `any`\> +[`RecipeInitResult`](types#recipeinitresult)\<`any`, `any`, `any`, `any`\> *** @@ -91,16 +84,16 @@ Defined in: [recipe/multitenancy/index.ts:35](https://github.com/supertokens/sup ### AllowedDomainsClaim -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### RecipeInterface -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### UserInput -Re-exports [UserInput](recipe-multitenancy-types.mdx#userinput) +Re-exports [UserInput](recipe-multitenancy-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider-types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider-types.mdx index c1bbb60b97..986b214f95 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider-types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/oauth2provider/types -page_title: OAuth Provider Types -sidebar_position: 6 description: References documentation for the supertokens-auth-react/recipe/oauth2provider/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 6 --- -# OAuth Provider Types - - ## Type Aliases ### ComponentOverrideMap @@ -26,7 +19,7 @@ Defined in: [recipe/oauth2provider/types.ts:97](https://github.com/supertokens/s | Property | Type | Defined in | | ------ | ------ | ------ | -| `OAuth2LogoutScreenInner_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/oauth2provider/types.ts:98](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L98) | +| `OAuth2LogoutScreenInner_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/oauth2provider/types.ts:98](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L98) | *** @@ -76,7 +69,7 @@ Defined in: [recipe/oauth2provider/types.ts:40](https://github.com/supertokens/s | `disableDefaultUI` | `boolean` | [recipe/oauth2provider/types.ts:45](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L45) | | `oauth2LogoutScreen` | [`OAuth2LogoutScreenConfig`](#oauth2logoutscreenconfig) | [recipe/oauth2provider/types.ts:46](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L46) | | `override` | `object` | [recipe/oauth2provider/types.ts:48](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L48) | -| `override.functions()` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/oauth2provider/types.ts:49](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L49) | +| `override.functions()` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/oauth2provider/types.ts:49](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L49) | | `tryRefreshPage` | [`OAuth2TryRefreshPageConfig`](#oauth2tryrefreshpageconfig) | [recipe/oauth2provider/types.ts:47](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L47) | *** @@ -199,7 +192,7 @@ Defined in: [recipe/oauth2provider/types.ts:21](https://github.com/supertokens/s | `action` | [`PreAndPostAPIHookAction`](#preandpostapihookaction) | [recipe/oauth2provider/types.ts:22](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L22) | | `requestInit` | `RequestInit` | [recipe/oauth2provider/types.ts:23](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L23) | | `url` | `string` | [recipe/oauth2provider/types.ts:24](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L24) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/oauth2provider/types.ts:25](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L25) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/oauth2provider/types.ts:25](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L25) | *** @@ -218,5 +211,5 @@ Defined in: [recipe/oauth2provider/types.ts:28](https://github.com/supertokens/s | `disableDefaultUI?` | `boolean` | [recipe/oauth2provider/types.ts:29](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L29) | | `oauth2LogoutScreen?` | `Partial`\<[`OAuth2LogoutScreenConfig`](#oauth2logoutscreenconfig)\> | [recipe/oauth2provider/types.ts:30](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L30) | | `override?` | `object` | [recipe/oauth2provider/types.ts:32](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L32) | -| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/oauth2provider/types.ts:33](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L33) | +| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/oauth2provider/types.ts:33](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L33) | | `tryRefreshPage?` | `Partial`\<[`OAuth2TryRefreshPageConfig`](#oauth2tryrefreshpageconfig)\> | [recipe/oauth2provider/types.ts:31](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/oauth2provider/types.ts#L31) | diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider.mdx index 79d2993716..c53a044c7f 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/oauth2provider -page_title: OAuth Provider -sidebar_position: 6 description: References documentation for the supertokens-auth-react/recipe/oauth2provider package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 6 --- -# OAuth Provider - - ## Classes ### default @@ -124,11 +117,11 @@ Defined in: [recipe/oauth2provider/index.ts:24](https://github.com/supertokens/s | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-oauth2provider-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-oauth2provider-types#userinput) | ###### Returns -[`RecipeInitResult`](types.mdx#recipeinitresult)\<[`GetRedirectionURLContext`](recipe-oauth2provider-types.mdx#getredirectionurlcontext), [`PreAndPostAPIHookAction`](recipe-oauth2provider-types.mdx#preandpostapihookaction), [`OnHandleEventContext`](recipe-oauth2provider-types.mdx#onhandleeventcontext), [`NormalisedConfig`](recipe-oauth2provider-types.mdx#normalisedconfig)\> +[`RecipeInitResult`](types#recipeinitresult)\<[`GetRedirectionURLContext`](recipe-oauth2provider-types#getredirectionurlcontext), [`PreAndPostAPIHookAction`](recipe-oauth2provider-types#preandpostapihookaction), [`OnHandleEventContext`](recipe-oauth2provider-types#onhandleeventcontext), [`NormalisedConfig`](recipe-oauth2provider-types#normalisedconfig)\> ##### logOut() @@ -220,11 +213,11 @@ Defined in: [recipe/oauth2provider/index.ts:102](https://github.com/supertokens/ | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-oauth2provider-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-oauth2provider-types#userinput) | #### Returns -[`RecipeInitResult`](types.mdx#recipeinitresult)\<[`GetRedirectionURLContext`](recipe-oauth2provider-types.mdx#getredirectionurlcontext), [`PreAndPostAPIHookAction`](recipe-oauth2provider-types.mdx#preandpostapihookaction), [`OnHandleEventContext`](recipe-oauth2provider-types.mdx#onhandleeventcontext), [`NormalisedConfig`](recipe-oauth2provider-types.mdx#normalisedconfig)\> +[`RecipeInitResult`](types#recipeinitresult)\<[`GetRedirectionURLContext`](recipe-oauth2provider-types#getredirectionurlcontext), [`PreAndPostAPIHookAction`](recipe-oauth2provider-types#preandpostapihookaction), [`OnHandleEventContext`](recipe-oauth2provider-types#onhandleeventcontext), [`NormalisedConfig`](recipe-oauth2provider-types#normalisedconfig)\> *** @@ -269,34 +262,34 @@ STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ ### GetRedirectionURLContext -Re-exports [GetRedirectionURLContext](recipe-oauth2provider-types.mdx#getredirectionurlcontext) +Re-exports [GetRedirectionURLContext](recipe-oauth2provider-types#getredirectionurlcontext) *** ### OnHandleEventContext -Re-exports [OnHandleEventContext](recipe-oauth2provider-types.mdx#onhandleeventcontext) +Re-exports [OnHandleEventContext](recipe-oauth2provider-types#onhandleeventcontext) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-oauth2provider-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-oauth2provider-types#preapihookcontext) *** ### RecipeComponentsOverrideContextProvider -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### RecipeInterface -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### UserInput -Re-exports [UserInput](recipe-oauth2provider-types.mdx#userinput) +Re-exports [UserInput](recipe-oauth2provider-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless-types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless-types.mdx index 4608701345..3f7f8d3ad4 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless-types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/passwordless/types -page_title: Passwordless Types -sidebar_position: 7 description: References documentation for the supertokens-auth-react/recipe/passwordless/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 7 --- -# Passwordless Types - - ## Type Aliases ### AdditionalLoginAttemptInfoProperties @@ -51,22 +44,22 @@ Defined in: [recipe/passwordless/types.ts:445](https://github.com/supertokens/su | Property | Type | Defined in | | ------ | ------ | ------ | -| `PasswordlessContinueWithPasswordless_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:459](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L459) | -| `PasswordlessEmailForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:446](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L446) | -| `PasswordlessEmailOrPhoneForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:448](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L448) | -| `PasswordlessEPComboEmailForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:449](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L449) | -| `PasswordlessEPComboEmailOrPhoneForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:450](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L450) | -| `PasswordlessLinkClickedScreen_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:458](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L458) | -| `PasswordlessLinkSent_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:456](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L456) | -| `PasswordlessMFAFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:462](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L462) | -| `PasswordlessMFAHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:461](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L461) | -| `PasswordlessMFAOTPFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:464](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L464) | -| `PasswordlessMFAOTPHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:463](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L463) | -| `PasswordlessMFAOTPLoadingScreen_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:465](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L465) | -| `PasswordlessPhoneForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:447](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L447) | -| `PasswordlessUserInputCodeForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:454](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L454) | -| `PasswordlessUserInputCodeFormFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:453](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L453) | -| `PasswordlessUserInputCodeFormHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:452](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L452) | +| `PasswordlessContinueWithPasswordless_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:459](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L459) | +| `PasswordlessEmailForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:446](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L446) | +| `PasswordlessEmailOrPhoneForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:448](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L448) | +| `PasswordlessEPComboEmailForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:449](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L449) | +| `PasswordlessEPComboEmailOrPhoneForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:450](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L450) | +| `PasswordlessLinkClickedScreen_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:458](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L458) | +| `PasswordlessLinkSent_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:456](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L456) | +| `PasswordlessMFAFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:462](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L462) | +| `PasswordlessMFAHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:461](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L461) | +| `PasswordlessMFAOTPFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:464](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L464) | +| `PasswordlessMFAOTPHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:463](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L463) | +| `PasswordlessMFAOTPLoadingScreen_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:465](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L465) | +| `PasswordlessPhoneForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:447](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L447) | +| `PasswordlessUserInputCodeForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:454](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L454) | +| `PasswordlessUserInputCodeFormFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:453](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L453) | +| `PasswordlessUserInputCodeFormHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/passwordless/types.ts:452](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L452) | *** @@ -316,7 +309,7 @@ Defined in: [recipe/passwordless/types.ts:182](https://github.com/supertokens/su | `onSignOutClicked` | () => `void` | [recipe/passwordless/types.ts:187](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L187) | | `onSuccess?` | () => `void` | [recipe/passwordless/types.ts:188](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L188) | | `recipeImplementation` | [`RecipeImplementation`](#recipeimplementation-7) | [recipe/passwordless/types.ts:183](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L183) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/passwordless/types.ts:200](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L200) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/passwordless/types.ts:200](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L200) | | `validatePhoneNumber` | (`phoneNumber`) => `Promise`\<`string` \| `undefined`\> \| `string` \| `undefined` | [recipe/passwordless/types.ts:199](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L199) | *** @@ -358,7 +351,7 @@ Defined in: [recipe/passwordless/types.ts:100](https://github.com/supertokens/su | `linkClickedScreenFeature` | [`PasswordlessNormalisedBaseConfig`](#passwordlessnormalisedbaseconfig) | [recipe/passwordless/types.ts:115](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L115) | | `mfaFeature` | [`PasswordlessNormalisedBaseConfig`](#passwordlessnormalisedbaseconfig) | [recipe/passwordless/types.ts:116](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L116) | | `override` | `object` | [recipe/passwordless/types.ts:120](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L120) | -| `override.functions()` | (`originalImplementation`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/passwordless/types.ts:121](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L121) | +| `override.functions()` | (`originalImplementation`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/passwordless/types.ts:121](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L121) | | `signInUpFeature` | `object` | [recipe/passwordless/types.ts:106](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L106) | | `signInUpFeature.defaultCountry?` | `string` | [recipe/passwordless/types.ts:108](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L108) | | `signInUpFeature.defaultToEmail` | `boolean` | [recipe/passwordless/types.ts:110](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L110) | @@ -538,10 +531,10 @@ Defined in: [recipe/passwordless/types.ts:373](https://github.com/supertokens/su | Name | Type | Defined in | | ------ | ------ | ------ | | `isPhoneNumber` | `boolean` | [recipe/passwordless/types.ts:374](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L374) | -| `navigate` | [`Navigate`](types.mdx#navigate-1) \| `undefined` | [recipe/passwordless/types.ts:387](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L387) | -| `onContactInfoSubmit()` | (`contactInfo`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types.mdx#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:378](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L378) | +| `navigate` | [`Navigate`](types#navigate-1) \| `undefined` | [recipe/passwordless/types.ts:387](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L387) | +| `onContactInfoSubmit()` | (`contactInfo`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:378](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L378) | | `onContinueWithPasswordlessClick()` | (`contactInfo`) => `Promise`\<`void`\> | [recipe/passwordless/types.ts:380](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L380) | -| `onPasswordSubmit()` | (`formFields`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types.mdx#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:379](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L379) | +| `onPasswordSubmit()` | (`formFields`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:379](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L379) | | `onSuccess()` | (`result`) => `void` | [recipe/passwordless/types.ts:381](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L381) | | `setIsPhoneNumber()` | (`isPhone`) => `void` | [recipe/passwordless/types.ts:375](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L375) | | `showContinueWithPasswordlessLink` | `boolean` | [recipe/passwordless/types.ts:377](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L377) | @@ -565,12 +558,12 @@ Defined in: [recipe/passwordless/types.ts:314](https://github.com/supertokens/su | `clearError` | () => `void` | [recipe/passwordless/types.ts:317](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L317) | | `config` | [`NormalisedConfig`](#normalisedconfig) | [recipe/passwordless/types.ts:331](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L331) | | `error` | `string` \| `undefined` | [recipe/passwordless/types.ts:328](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L328) | -| `navigate` | [`Navigate`](types.mdx#navigate-1) \| `undefined` | [recipe/passwordless/types.ts:332](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L332) | -| `onContactInfoSubmit` | (`contactInfo`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types.mdx#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:318](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L318) | +| `navigate` | [`Navigate`](types#navigate-1) \| `undefined` | [recipe/passwordless/types.ts:332](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L332) | +| `onContactInfoSubmit` | (`contactInfo`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:318](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L318) | | `onContinueWithPasswordlessClick` | (`contactInfo`) => `Promise`\<`void`\> | [recipe/passwordless/types.ts:320](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L320) | | `onError` | (`error`) => `void` | [recipe/passwordless/types.ts:326](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L326) | | `onFetchError` | (`error`) => `void` | [recipe/passwordless/types.ts:327](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L327) | -| `onPasswordSubmit` | (`formFields`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types.mdx#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:319](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L319) | +| `onPasswordSubmit` | (`formFields`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:319](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L319) | | `onSuccess` | (`result`) => `void` | [recipe/passwordless/types.ts:321](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L321) | | `recipeImplementation` | [`RecipeImplementation`](#recipeimplementation-7) | [recipe/passwordless/types.ts:329](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L329) | | `showContinueWithPasswordlessLink` | `boolean` | [recipe/passwordless/types.ts:316](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L316) | @@ -595,12 +588,12 @@ Defined in: [recipe/passwordless/types.ts:291](https://github.com/supertokens/su | `config` | [`NormalisedConfig`](#normalisedconfig) | [recipe/passwordless/types.ts:309](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L309) | | `error` | `string` \| `undefined` | [recipe/passwordless/types.ts:307](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L307) | | `isPhoneNumber` | `boolean` | [recipe/passwordless/types.ts:295](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L295) | -| `navigate` | [`Navigate`](types.mdx#navigate-1) \| `undefined` | [recipe/passwordless/types.ts:311](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L311) | -| `onContactInfoSubmit` | (`contactInfo`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types.mdx#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:297](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L297) | +| `navigate` | [`Navigate`](types#navigate-1) \| `undefined` | [recipe/passwordless/types.ts:311](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L311) | +| `onContactInfoSubmit` | (`contactInfo`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:297](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L297) | | `onContinueWithPasswordlessClick` | (`contactInfo`) => `Promise`\<`void`\> | [recipe/passwordless/types.ts:299](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L299) | | `onError` | (`error`) => `void` | [recipe/passwordless/types.ts:305](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L305) | | `onFetchError` | (`error`) => `void` | [recipe/passwordless/types.ts:306](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L306) | -| `onPasswordSubmit` | (`formFields`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types.mdx#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:298](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L298) | +| `onPasswordSubmit` | (`formFields`) => `Promise`\<[`FormBaseAPIResponse`](recipe-emailpassword-types#formbaseapiresponse)\<`unknown`\>\> | [recipe/passwordless/types.ts:298](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L298) | | `onSuccess` | (`result`) => `void` | [recipe/passwordless/types.ts:300](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L300) | | `recipeImplementation` | [`RecipeImplementation`](#recipeimplementation-7) | [recipe/passwordless/types.ts:308](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L308) | | `setIsPhoneNumber` | (`isPhone`) => `void` | [recipe/passwordless/types.ts:296](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L296) | @@ -672,7 +665,7 @@ Defined in: [recipe/passwordless/types.ts:202](https://github.com/supertokens/su | `onFetchError` | (`err`) => `void` | [recipe/passwordless/types.ts:207](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L207) | | `onSuccess?` | (`result`) => `void` | [recipe/passwordless/types.ts:206](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L206) | | `recipeImplementation` | [`RecipeImplementation`](#recipeimplementation-7) | [recipe/passwordless/types.ts:203](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L203) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/passwordless/types.ts:211](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L211) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/passwordless/types.ts:211](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L211) | | `validatePhoneNumber` | (`phoneNumber`) => `Promise`\<`string` \| `undefined`\> \| `string` \| `undefined` | [recipe/passwordless/types.ts:212](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L212) | *** @@ -731,7 +724,7 @@ Defined in: [recipe/passwordless/types.ts:140](https://github.com/supertokens/su | `linkClickedScreenFeature?` | [`PasswordlessFeatureBaseConfig`](#passwordlessfeaturebaseconfig) | [recipe/passwordless/types.ts:178](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L178) | | `mfaFeature?` | [`PasswordlessFeatureBaseConfig`](#passwordlessfeaturebaseconfig) | [recipe/passwordless/types.ts:179](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L179) | | `override?` | `object` | [recipe/passwordless/types.ts:175](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L175) | -| `override.functions()?` | (`originalImplementation`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/passwordless/types.ts:176](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L176) | +| `override.functions()?` | (`originalImplementation`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/passwordless/types.ts:176](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/passwordless/types.ts#L176) | *** diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless.mdx index ab5216491c..1c60dbdfe2 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/passwordless -page_title: Passwordless -sidebar_position: 7 description: References documentation for the supertokens-auth-react/recipe/passwordless package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 7 --- -# Passwordless - - ## Classes ### default @@ -50,8 +43,8 @@ Defined in: [recipe/passwordless/index.ts:189](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -90,7 +83,7 @@ Defined in: [recipe/passwordless/index.ts:84](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | -| `input?` | \| \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); `userInputCode`: `string`; \} \| \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \| \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); `userInputCode`: `string`; \} \| \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | ###### Returns @@ -140,7 +133,7 @@ Defined in: [recipe/passwordless/index.ts:41](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | -| `input` | \| \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} \| \{ `options?`: `RecipeFunctionOptions`; `phoneNumber`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \| \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} \| \{ `options?`: `RecipeFunctionOptions`; `phoneNumber`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} | ###### Returns @@ -173,10 +166,10 @@ Defined in: [recipe/passwordless/index.ts:131](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.email` | `string` | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -202,10 +195,10 @@ Defined in: [recipe/passwordless/index.ts:146](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: `RecipeFunctionOptions`; `phoneNumber`: `string`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `options?`: `RecipeFunctionOptions`; `phoneNumber`: `string`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | | `input.phoneNumber` | `string` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -227,8 +220,8 @@ Defined in: [recipe/passwordless/index.ts:117](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -252,8 +245,8 @@ Defined in: [recipe/passwordless/index.ts:161](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -271,8 +264,8 @@ Defined in: [recipe/passwordless/index.ts:124](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -290,7 +283,7 @@ Defined in: [recipe/passwordless/index.ts:31](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | -| `config` | [`UserInput`](recipe-passwordless-types.mdx#userinput) | +| `config` | [`UserInput`](recipe-passwordless-types#userinput) | ###### Returns @@ -311,9 +304,9 @@ Defined in: [recipe/passwordless/index.ts:74](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -340,9 +333,9 @@ Defined in: [recipe/passwordless/index.ts:175](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `attemptInfo`: `object` & `CustomStateProperties`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `attemptInfo`: `object` & `CustomStateProperties`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.attemptInfo` | `object` & `CustomStateProperties` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -360,8 +353,8 @@ Defined in: [recipe/passwordless/index.ts:35](https://github.com/supertokens/sup | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -381,8 +374,8 @@ Defined in: [recipe/passwordless/index.ts:209](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -423,7 +416,7 @@ Defined in: [recipe/passwordless/index.ts:202](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \| \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); `userInputCode`: `string`; \} \| \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \| \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); `userInputCode`: `string`; \} \| \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | #### Returns @@ -475,7 +468,7 @@ Defined in: [recipe/passwordless/index.ts:200](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \| \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} \| \{ `options?`: `RecipeFunctionOptions`; `phoneNumber`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \| \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} \| \{ `options?`: `RecipeFunctionOptions`; `phoneNumber`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: [`UserContext`](types#usercontext-1); \} | #### Returns @@ -510,10 +503,10 @@ Defined in: [recipe/passwordless/index.ts:205](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `email`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.email` | `string` | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -541,10 +534,10 @@ Defined in: [recipe/passwordless/index.ts:206](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: `RecipeFunctionOptions`; `phoneNumber`: `string`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `options?`: `RecipeFunctionOptions`; `phoneNumber`: `string`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | | `input.phoneNumber` | `string` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -568,8 +561,8 @@ Defined in: [recipe/passwordless/index.ts:203](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -595,8 +588,8 @@ Defined in: [recipe/passwordless/index.ts:207](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -616,8 +609,8 @@ Defined in: [recipe/passwordless/index.ts:204](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -637,7 +630,7 @@ Defined in: [recipe/passwordless/index.ts:199](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `config` | [`UserInput`](recipe-passwordless-types.mdx#userinput) | +| `config` | [`UserInput`](recipe-passwordless-types#userinput) | #### Returns @@ -670,9 +663,9 @@ Defined in: [recipe/passwordless/index.ts:201](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -701,9 +694,9 @@ Defined in: [recipe/passwordless/index.ts:208](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input` | \{ `attemptInfo`: `object` & `CustomStateProperties`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `attemptInfo`: `object` & `CustomStateProperties`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.attemptInfo` | `object` & `CustomStateProperties` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -723,8 +716,8 @@ Defined in: [recipe/passwordless/index.ts:210](https://github.com/supertokens/su | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -734,28 +727,28 @@ Defined in: [recipe/passwordless/index.ts:210](https://github.com/supertokens/su ### GetRedirectionURLContext -Re-exports [GetRedirectionURLContext](recipe-passwordless-types.mdx#getredirectionurlcontext) +Re-exports [GetRedirectionURLContext](recipe-passwordless-types#getredirectionurlcontext) *** ### OnHandleEventContext -Re-exports [OnHandleEventContext](recipe-passwordless-types.mdx#onhandleeventcontext) +Re-exports [OnHandleEventContext](recipe-passwordless-types#onhandleeventcontext) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-passwordless-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-passwordless-types#preapihookcontext) *** ### RecipeInterface -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### UserInput -Re-exports [UserInput](recipe-passwordless-types.mdx#userinput) +Re-exports [UserInput](recipe-passwordless-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-session-types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-session-types.mdx index ef5aaa578c..a7ff6d9edc 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-session-types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-session-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/session/types -page_title: Session Types -sidebar_position: 8 description: References documentation for the supertokens-auth-react/recipe/session/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 8 --- -# Session Types - - ## Type Aliases ### AccessDeniedThemeProps @@ -28,8 +21,8 @@ Defined in: [recipe/session/types.ts:65](https://github.com/supertokens/supertok | ------ | ------ | ------ | | `config` | [`NormalisedSessionConfig`](#normalisedsessionconfig) | [recipe/session/types.ts:72](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L72) | | `error?` | `string` | [recipe/session/types.ts:70](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L70) | -| `navigate` | [`Navigate`](types.mdx#navigate-1) | [recipe/session/types.ts:71](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L71) | -| `recipe` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/session/types.ts:66](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L66) | +| `navigate` | [`Navigate`](types#navigate-1) | [recipe/session/types.ts:71](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L71) | +| `recipe` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/session/types.ts:66](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L66) | *** @@ -45,7 +38,7 @@ Defined in: [recipe/session/types.ts:75](https://github.com/supertokens/supertok | Property | Type | Defined in | | ------ | ------ | ------ | -| `SessionAccessDenied_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/session/types.ts:76](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L76) | +| `SessionAccessDenied_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/session/types.ts:76](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L76) | *** @@ -79,8 +72,8 @@ Defined in: [recipe/session/types.ts:53](https://github.com/supertokens/supertok | Name | Type | Defined in | | ------ | ------ | ------ | -| `accessDeniedValidatorError?` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/session/types.ts:56](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L56) | -| `invalidClaims` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)[] | [recipe/session/types.ts:55](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L55) | +| `accessDeniedValidatorError?` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/session/types.ts:56](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L56) | +| `invalidClaims` | [`SuperTokensWrapper`](index#supertokenswrapper-1)[] | [recipe/session/types.ts:55](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L55) | | `loading` | `false` | [recipe/session/types.ts:54](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L54) | *** @@ -97,10 +90,10 @@ Defined in: [recipe/session/types.ts:34](https://github.com/supertokens/supertok | Name | Type | Defined in | | ------ | ------ | ------ | -| `accessDeniedScreen` | [`NormalisedBaseConfig`](types.mdx#normalisedbaseconfig) | [recipe/session/types.ts:36](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L36) | +| `accessDeniedScreen` | [`NormalisedBaseConfig`](types#normalisedbaseconfig) | [recipe/session/types.ts:36](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L36) | | `invalidClaimStatusCode` | `number` | [recipe/session/types.ts:35](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L35) | | `override` | `object` | [recipe/session/types.ts:37](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L37) | -| `override.functions()` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/session/types.ts:38](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L38) | +| `override.functions()` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/session/types.ts:38](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/types.ts#L38) | *** diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-session.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-session.mdx index 6bbe884315..8993b11d35 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-session.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-session.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/session -page_title: Session -sidebar_position: 8 description: References documentation for the supertokens-auth-react/recipe/session package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 8 --- -# Session - - ## Classes ### BooleanClaim @@ -20,7 +13,7 @@ Defined in: [claims/booleanClaim.ts:6](https://github.com/supertokens/supertoken #### Extends -- [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) +- [`SuperTokensWrapper`](index#supertokenswrapper-1) #### Constructors @@ -73,7 +66,7 @@ new default(): default; | `ComponentsOverrideProvider` | `static` | `any` | `RecipeComponentsOverrideContextProvider` | [recipe/session/index.ts:112](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/index.ts#L112) | | `SessionAuth` | `static` | `any` | `SessionAuthWrapper` | [recipe/session/index.ts:38](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/index.ts#L38) | | `useClaimValue` | `static` | \<`T`\>(`claim`) => \| \{ `loading`: `true`; \} \| \{ `doesSessionExist`: `boolean`; `loading`: `false`; `value`: `T`; \} | `useClaimValueFunc` | [recipe/session/index.ts:36](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/index.ts#L36) | -| `useSessionContext` | `static` | () => [`SessionContextType`](recipe-session-types.mdx#sessioncontexttype) | `useSessionContextFunc` | [recipe/session/index.ts:35](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/index.ts#L35) | +| `useSessionContext` | `static` | () => [`SessionContextType`](recipe-session-types#sessioncontexttype) | `useSessionContextFunc` | [recipe/session/index.ts:35](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/session/index.ts#L35) | #### Methods @@ -90,7 +83,7 @@ Defined in: [recipe/session/index.ts:75](https://github.com/supertokens/supertok | Parameter | Type | | ------ | ------ | | `axiosInstance` | `any` | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -122,8 +115,8 @@ Defined in: [recipe/session/index.ts:66](https://github.com/supertokens/supertok | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -141,8 +134,8 @@ Defined in: [recipe/session/index.ts:50](https://github.com/supertokens/supertok | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -160,8 +153,8 @@ Defined in: [recipe/session/index.ts:56](https://github.com/supertokens/supertok | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -185,9 +178,9 @@ Defined in: [recipe/session/index.ts:105](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input` | \{ `claim`: `SessionClaim`\<`T`\>; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `claim`: `SessionClaim`\<`T`\>; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.claim` | `SessionClaim`\<`T`\> | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -205,9 +198,9 @@ Defined in: [recipe/session/index.ts:98](https://github.com/supertokens/supertok | Parameter | Type | | ------ | ------ | -| `input` | \{ `response`: \| `Response` \| \{ `data`: `any`; \}; `userContext`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `response`: \| `Response` \| \{ `data`: `any`; \}; `userContext`: [`UserContext`](types#usercontext-1); \} | | `input.response` | \| `Response` \| \{ `data`: `any`; \} | -| `input.userContext` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -225,8 +218,8 @@ Defined in: [recipe/session/index.ts:44](https://github.com/supertokens/supertok | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -262,8 +255,8 @@ Defined in: [recipe/session/index.ts:79](https://github.com/supertokens/supertok | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -281,9 +274,9 @@ Defined in: [recipe/session/index.ts:85](https://github.com/supertokens/supertok | Parameter | Type | | ------ | ------ | -| `input?` | \{ `overrideGlobalClaimValidators?`: (`globalClaimValidators`, `userContext`) => `SessionClaimValidator`[]; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `overrideGlobalClaimValidators?`: (`globalClaimValidators`, `userContext`) => `SessionClaimValidator`[]; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.overrideGlobalClaimValidators?` | (`globalClaimValidators`, `userContext`) => `SessionClaimValidator`[] | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -297,7 +290,7 @@ Defined in: [claims/primitiveArrayClaim.ts:6](https://github.com/supertokens/sup #### Extends -- [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\<`T`\> +- [`SuperTokensWrapper`](index#supertokenswrapper-1)\<`T`\> #### Type Parameters @@ -339,7 +332,7 @@ Defined in: [claims/primitiveClaim.ts:6](https://github.com/supertokens/supertok #### Extends -- [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\<`T`\> +- [`SuperTokensWrapper`](index#supertokenswrapper-1)\<`T`\> #### Type Parameters @@ -388,7 +381,7 @@ Defined in: [recipe/session/index.ts:127](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | | `axiosInstance` | `any` | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -426,8 +419,8 @@ Defined in: [recipe/session/index.ts:123](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -447,8 +440,8 @@ Defined in: [recipe/session/index.ts:120](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -468,8 +461,8 @@ Defined in: [recipe/session/index.ts:121](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -495,9 +488,9 @@ Defined in: [recipe/session/index.ts:131](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input` | \{ `claim`: `SessionClaim`\<`T`\>; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `claim`: `SessionClaim`\<`T`\>; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.claim` | `SessionClaim`\<`T`\> | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -517,9 +510,9 @@ Defined in: [recipe/session/index.ts:130](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input` | \{ `response`: \| `Response` \| \{ `data`: `any`; \}; `userContext`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `response`: \| `Response` \| \{ `data`: `any`; \}; `userContext`: [`UserContext`](types#usercontext-1); \} | | `input.response` | \| `Response` \| \{ `data`: `any`; \} | -| `input.userContext` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext` | [`UserContext`](types#usercontext-1) | #### Returns @@ -539,8 +532,8 @@ Defined in: [recipe/session/index.ts:119](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -610,8 +603,8 @@ Defined in: [recipe/session/index.ts:128](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -670,7 +663,7 @@ Defined in: [recipe/session/index.ts:115](https://github.com/supertokens/superto #### Returns -[`SessionContextType`](recipe-session-types.mdx#sessioncontexttype) +[`SessionContextType`](recipe-session-types#sessioncontexttype) *** @@ -686,9 +679,9 @@ Defined in: [recipe/session/index.ts:129](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `input?` | \{ `overrideGlobalClaimValidators?`: (`globalClaimValidators`, `userContext`) => `SessionClaimValidator`[]; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `overrideGlobalClaimValidators?`: (`globalClaimValidators`, `userContext`) => `SessionClaimValidator`[]; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.overrideGlobalClaimValidators?` | (`globalClaimValidators`, `userContext`) => `SessionClaimValidator`[] | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -698,40 +691,40 @@ Defined in: [recipe/session/index.ts:129](https://github.com/supertokens/superto ### ClaimValidationError -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### ClaimValidationResult -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### InputType -Re-exports [InputType](recipe-session-types.mdx#inputtype) +Re-exports [InputType](recipe-session-types#inputtype) *** ### RecipeInterface -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### SessionClaim -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### SessionClaimValidator -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### SessionContextType -Re-exports [SessionContextType](recipe-session-types.mdx#sessioncontexttype) +Re-exports [SessionContextType](recipe-session-types#sessioncontexttype) diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty-types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty-types.mdx index f0693a5e49..ca3c6c149b 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty-types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/thirdparty/types -page_title: ThirdParty Types -sidebar_position: 9 description: References documentation for the supertokens-auth-react/recipe/thirdparty/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 9 --- -# ThirdParty Types - - ## Type Aliases ### ComponentOverrideMap @@ -26,8 +19,8 @@ Defined in: [recipe/thirdparty/types.ts:39](https://github.com/supertokens/super | Property | Type | Defined in | | ------ | ------ | ------ | -| `ThirdPartySignInAndUpCallbackTheme_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/thirdparty/types.ts:41](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L41) | -| `ThirdPartySignInAndUpProvidersForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/thirdparty/types.ts:40](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L40) | +| `ThirdPartySignInAndUpCallbackTheme_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/thirdparty/types.ts:41](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L41) | +| `ThirdPartySignInAndUpProvidersForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/thirdparty/types.ts:40](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L40) | *** @@ -81,9 +74,9 @@ Defined in: [recipe/thirdparty/types.ts:58](https://github.com/supertokens/super | Name | Type | Defined in | | ------ | ------ | ------ | -| `oAuthCallbackScreen` | [`FeatureBaseConfig`](types.mdx#featurebaseconfig) | [recipe/thirdparty/types.ts:60](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L60) | +| `oAuthCallbackScreen` | [`FeatureBaseConfig`](types#featurebaseconfig) | [recipe/thirdparty/types.ts:60](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L60) | | `override` | `object` | [recipe/thirdparty/types.ts:61](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L61) | -| `override.functions()` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/thirdparty/types.ts:62](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L62) | +| `override.functions()` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/thirdparty/types.ts:62](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L62) | | `signInAndUpFeature` | [`NormalisedSignInAndUpFeatureConfig`](#normalisedsigninandupfeatureconfig) | [recipe/thirdparty/types.ts:59](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L59) | *** @@ -100,7 +93,7 @@ Defined in: [recipe/thirdparty/types.ts:76](https://github.com/supertokens/super | Name | Type | Defined in | | ------ | ------ | ------ | -| `providers` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)[] | [recipe/thirdparty/types.ts:80](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L80) | +| `providers` | [`SuperTokensWrapper`](index#supertokenswrapper-1)[] | [recipe/thirdparty/types.ts:80](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L80) | *** @@ -147,7 +140,7 @@ Defined in: [recipe/thirdparty/types.ts:88](https://github.com/supertokens/super | `action` | [`PreAndPostAPIHookAction`](#preandpostapihookaction) | [recipe/thirdparty/types.ts:89](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L89) | | `requestInit` | `RequestInit` | [recipe/thirdparty/types.ts:90](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L90) | | `url` | `string` | [recipe/thirdparty/types.ts:91](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L91) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/thirdparty/types.ts:92](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L92) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/thirdparty/types.ts:92](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L92) | *** @@ -163,7 +156,7 @@ Defined in: [recipe/thirdparty/types.ts:69](https://github.com/supertokens/super | Name | Type | Defined in | | ------ | ------ | ------ | -| `providers?` | ( \| [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) \| `CustomProviderConfig`)[] | [recipe/thirdparty/types.ts:73](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L73) | +| `providers?` | ( \| [`SuperTokensWrapper`](index#supertokenswrapper-1) \| `CustomProviderConfig`)[] | [recipe/thirdparty/types.ts:73](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L73) | *** @@ -180,8 +173,8 @@ Defined in: [recipe/thirdparty/types.ts:105](https://github.com/supertokens/supe | Name | Type | Defined in | | ------ | ------ | ------ | | `config` | [`NormalisedConfig`](#normalisedconfig) | [recipe/thirdparty/types.ts:108](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L108) | -| `providers` | `Pick`\<[`SuperTokensWrapper`](index.mdx#supertokenswrapper-1), `"id"` \| `"getButton"`\>[] | [recipe/thirdparty/types.ts:106](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L106) | -| `recipeImplementation` | [`WebJSRecipeInterface`](types.mdx#webjsrecipeinterface)\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/thirdparty/types.ts:107](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L107) | +| `providers` | `Pick`\<[`SuperTokensWrapper`](index#supertokenswrapper-1), `"id"` \| `"getButton"`\>[] | [recipe/thirdparty/types.ts:106](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L106) | +| `recipeImplementation` | [`WebJSRecipeInterface`](types#webjsrecipeinterface)\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/thirdparty/types.ts:107](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L107) | *** @@ -214,7 +207,7 @@ Defined in: [recipe/thirdparty/types.ts:44](https://github.com/supertokens/super | Name | Type | Defined in | | ------ | ------ | ------ | -| `oAuthCallbackScreen?` | [`FeatureBaseConfig`](types.mdx#featurebaseconfig) | [recipe/thirdparty/types.ts:46](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L46) | +| `oAuthCallbackScreen?` | [`FeatureBaseConfig`](types#featurebaseconfig) | [recipe/thirdparty/types.ts:46](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L46) | | `override?` | `object` | [recipe/thirdparty/types.ts:47](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L47) | -| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/thirdparty/types.ts:48](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L48) | +| `override.functions()?` | (`originalImplementation`, `builder`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/thirdparty/types.ts:48](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L48) | | `signInAndUpFeature?` | [`SignInAndUpFeatureUserInput`](#signinandupfeatureuserinput) | [recipe/thirdparty/types.ts:45](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/thirdparty/types.ts#L45) | diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty.mdx index e757f0424d..06cafe950a 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/thirdparty -page_title: ThirdParty -sidebar_position: 9 description: References documentation for the supertokens-auth-react/recipe/thirdparty package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 9 --- -# ThirdParty - - ## Classes ### default @@ -63,13 +56,13 @@ Defined in: [recipe/thirdparty/index.ts:87](https://github.com/supertokens/super | Parameter | Type | | ------ | ------ | -| `input` | \{ `frontendRedirectURI`: `string`; `options?`: `RecipeFunctionOptions`; `redirectURIOnProviderDashboard?`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `frontendRedirectURI`: `string`; `options?`: `RecipeFunctionOptions`; `redirectURIOnProviderDashboard?`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.frontendRedirectURI` | `string` | | `input.options?` | `RecipeFunctionOptions` | | `input.redirectURIOnProviderDashboard?` | `string` | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.thirdPartyId` | `string` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -105,8 +98,8 @@ Defined in: [recipe/thirdparty/index.ts:78](https://github.com/supertokens/super | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -124,7 +117,7 @@ Defined in: [recipe/thirdparty/index.ts:52](https://github.com/supertokens/super | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-thirdparty-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-thirdparty-types#userinput) | ###### Returns @@ -144,10 +137,10 @@ Defined in: [recipe/thirdparty/index.ts:62](https://github.com/supertokens/super | Parameter | Type | | ------ | ------ | -| `input` | \{ `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.thirdPartyId` | `string` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -182,9 +175,9 @@ Defined in: [recipe/thirdparty/index.ts:101](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -217,8 +210,8 @@ Defined in: [recipe/thirdparty/index.ts:56](https://github.com/supertokens/super | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -238,13 +231,13 @@ Defined in: [recipe/thirdparty/index.ts:154](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `input` | \{ `frontendRedirectURI`: `string`; `options?`: `RecipeFunctionOptions`; `redirectURIOnProviderDashboard?`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `frontendRedirectURI`: `string`; `options?`: `RecipeFunctionOptions`; `redirectURIOnProviderDashboard?`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.frontendRedirectURI` | `string` | | `input.options?` | `RecipeFunctionOptions` | | `input.redirectURIOnProviderDashboard?` | `string` | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.thirdPartyId` | `string` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -284,8 +277,8 @@ Defined in: [recipe/thirdparty/index.ts:153](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -305,7 +298,7 @@ Defined in: [recipe/thirdparty/index.ts:150](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-thirdparty-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-thirdparty-types#userinput) | #### Returns @@ -327,10 +320,10 @@ Defined in: [recipe/thirdparty/index.ts:152](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `input` | \{ `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.thirdPartyId` | `string` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -367,9 +360,9 @@ Defined in: [recipe/thirdparty/index.ts:155](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -404,8 +397,8 @@ Defined in: [recipe/thirdparty/index.ts:151](https://github.com/supertokens/supe | Parameter | Type | | ------ | ------ | -| `input?` | \{ `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input?` | \{ `userContext?`: [`UserContext`](types#usercontext-1); \} | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -425,106 +418,106 @@ Defined in: [recipe/thirdparty/index.ts:157](https://github.com/supertokens/supe ### ActiveDirectory -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### Apple -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### Bitbucket -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### BoxySAML -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### Discord -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### Facebook -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### GetRedirectionURLContext -Re-exports [GetRedirectionURLContext](recipe-thirdparty-types.mdx#getredirectionurlcontext) +Re-exports [GetRedirectionURLContext](recipe-thirdparty-types#getredirectionurlcontext) *** ### Github -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### Gitlab -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### Google -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### GoogleWorkspaces -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### LinkedIn -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### Okta -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### OnHandleEventContext -Re-exports [OnHandleEventContext](recipe-thirdparty-types.mdx#onhandleeventcontext) +Re-exports [OnHandleEventContext](recipe-thirdparty-types#onhandleeventcontext) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-thirdparty-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-thirdparty-types#preapihookcontext) *** ### RecipeInterface -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### Twitter -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### UserInput -Re-exports [UserInput](recipe-thirdparty-types.mdx#userinput) +Re-exports [UserInput](recipe-thirdparty-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-totp-types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-totp-types.mdx index dd41c2fee7..0ba51bfc9d 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-totp-types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-totp-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/totp/types -page_title: TOTP Types -sidebar_position: 10 description: References documentation for the supertokens-auth-react/recipe/totp/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 10 --- -# TOTP Types - - ## Type Aliases ### ComponentOverrideMap @@ -26,14 +19,14 @@ Defined in: [recipe/totp/types.ts:35](https://github.com/supertokens/supertokens | Property | Type | Defined in | | ------ | ------ | ------ | -| `TOTPBlockedScreen_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/totp/types.ts:36](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L36) | -| `TOTPCodeForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/totp/types.ts:38](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L38) | -| `TOTPCodeVerificationFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/totp/types.ts:39](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L39) | -| `TOTPCodeVerificationHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/totp/types.ts:40](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L40) | -| `TOTPDeviceInfoSection_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/totp/types.ts:43](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L43) | -| `TOTPDeviceSetupFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/totp/types.ts:41](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L41) | -| `TOTPDeviceSetupHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/totp/types.ts:42](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L42) | -| `TOTPLoadingScreen_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/totp/types.ts:37](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L37) | +| `TOTPBlockedScreen_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/totp/types.ts:36](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L36) | +| `TOTPCodeForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/totp/types.ts:38](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L38) | +| `TOTPCodeVerificationFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/totp/types.ts:39](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L39) | +| `TOTPCodeVerificationHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/totp/types.ts:40](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L40) | +| `TOTPDeviceInfoSection_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/totp/types.ts:43](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L43) | +| `TOTPDeviceSetupFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/totp/types.ts:41](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L41) | +| `TOTPDeviceSetupHeader_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/totp/types.ts:42](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L42) | +| `TOTPLoadingScreen_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/totp/types.ts:37](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L37) | *** @@ -70,7 +63,7 @@ Defined in: [recipe/totp/types.ts:145](https://github.com/supertokens/supertoken | Name | Type | Defined in | | ------ | ------ | ------ | | `override` | `object` | [recipe/totp/types.ts:148](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L148) | -| `override.functions()` | (`originalImplementation`, `builder?`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/totp/types.ts:149](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L149) | +| `override.functions()` | (`originalImplementation`, `builder?`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/totp/types.ts:149](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L149) | | `totpMFAScreen` | [`TOTPMFAScreenConfig`](#totpmfascreenconfig) | [recipe/totp/types.ts:146](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L146) | *** @@ -130,7 +123,7 @@ Defined in: [recipe/totp/types.ts:166](https://github.com/supertokens/supertoken | `action` | [`PreAndPostAPIHookAction`](#preandpostapihookaction) | [recipe/totp/types.ts:167](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L167) | | `requestInit` | `RequestInit` | [recipe/totp/types.ts:168](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L168) | | `url` | `string` | [recipe/totp/types.ts:169](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L169) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/totp/types.ts:170](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L170) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/totp/types.ts:170](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L170) | *** @@ -221,8 +214,8 @@ Defined in: [recipe/totp/types.ts:102](https://github.com/supertokens/supertoken | ------ | ------ | ------ | | `config` | [`NormalisedConfig`](#normalisedconfig) | [recipe/totp/types.ts:105](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L105) | | `featureState` | [`TOTPMFAState`](#totpmfastate) | [recipe/totp/types.ts:103](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L103) | -| `recipeImplementation` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/totp/types.ts:104](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L104) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/totp/types.ts:106](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L106) | +| `recipeImplementation` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/totp/types.ts:104](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L104) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/totp/types.ts:106](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L106) | *** @@ -246,8 +239,8 @@ Defined in: [recipe/totp/types.ts:109](https://github.com/supertokens/supertoken | `onShowSecretClicked` | () => `void` | [recipe/totp/types.ts:113](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L113) | | `onSignOutClicked` | () => `void` | [recipe/totp/types.ts:116](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L116) | | `onSuccess` | () => `void` | [recipe/totp/types.ts:112](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L112) | -| `recipeImplementation` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/totp/types.ts:110](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L110) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/totp/types.ts:119](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L119) | +| `recipeImplementation` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/totp/types.ts:110](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L110) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/totp/types.ts:119](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L119) | *** @@ -309,5 +302,5 @@ Defined in: [recipe/totp/types.ts:131](https://github.com/supertokens/supertoken | Name | Type | Defined in | | ------ | ------ | ------ | | `override?` | `object` | [recipe/totp/types.ts:134](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L134) | -| `override.functions()?` | (`originalImplementation`, `builder?`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/totp/types.ts:135](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L135) | +| `override.functions()?` | (`originalImplementation`, `builder?`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/totp/types.ts:135](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L135) | | `totpMFAScreen?` | `Partial`\<[`TOTPMFAScreenConfig`](#totpmfascreenconfig)\> | [recipe/totp/types.ts:132](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/totp/types.ts#L132) | diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-totp.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-totp.mdx index 18ee556d50..0b566ba284 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-totp.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-totp.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/totp -page_title: TOTP -sidebar_position: 10 description: References documentation for the supertokens-auth-react/recipe/totp package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 10 --- -# TOTP - - ## Classes ### default @@ -50,10 +43,10 @@ Defined in: [recipe/totp/index.ts:35](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `input?` | \{ `deviceName?`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `deviceName?`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.deviceName?` | `string` | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -71,7 +64,7 @@ Defined in: [recipe/totp/index.ts:32](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-totp-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-totp-types#userinput) | ###### Returns @@ -89,9 +82,9 @@ Defined in: [recipe/totp/index.ts:64](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -109,10 +102,10 @@ Defined in: [recipe/totp/index.ts:58](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `input` | \{ `deviceName`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `deviceName`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.deviceName` | `string` | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -130,10 +123,10 @@ Defined in: [recipe/totp/index.ts:41](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: `RecipeFunctionOptions`; `totp`: `string`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `options?`: `RecipeFunctionOptions`; `totp`: `string`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | | `input.totp` | `string` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -151,11 +144,11 @@ Defined in: [recipe/totp/index.ts:47](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `input` | \{ `deviceName`: `string`; `options?`: `any`; `totp`: `string`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `deviceName`: `string`; `options?`: `any`; `totp`: `string`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.deviceName` | `string` | | `input.options?` | `any` | | `input.totp` | `string` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | ###### Returns @@ -175,10 +168,10 @@ Defined in: [recipe/totp/index.ts:75](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `input?` | \{ `deviceName?`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `deviceName?`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.deviceName?` | `string` | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -198,7 +191,7 @@ Defined in: [recipe/totp/index.ts:74](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-totp-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-totp-types#userinput) | #### Returns @@ -218,9 +211,9 @@ Defined in: [recipe/totp/index.ts:79](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input?` | \{ `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -240,10 +233,10 @@ Defined in: [recipe/totp/index.ts:78](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `input` | \{ `deviceName`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `deviceName`: `string`; `options?`: `RecipeFunctionOptions`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.deviceName` | `string` | | `input.options?` | `RecipeFunctionOptions` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -273,10 +266,10 @@ Defined in: [recipe/totp/index.ts:76](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: `RecipeFunctionOptions`; `totp`: `string`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `options?`: `RecipeFunctionOptions`; `totp`: `string`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.options?` | `RecipeFunctionOptions` | | `input.totp` | `string` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -296,11 +289,11 @@ Defined in: [recipe/totp/index.ts:77](https://github.com/supertokens/supertokens | Parameter | Type | | ------ | ------ | -| `input` | \{ `deviceName`: `string`; `options?`: `any`; `totp`: `string`; `userContext?`: [`UserContext`](types.mdx#usercontext-1); \} | +| `input` | \{ `deviceName`: `string`; `options?`: `any`; `totp`: `string`; `userContext?`: [`UserContext`](types#usercontext-1); \} | | `input.deviceName` | `string` | | `input.options?` | `any` | | `input.totp` | `string` | -| `input.userContext?` | [`UserContext`](types.mdx#usercontext-1) | +| `input.userContext?` | [`UserContext`](types#usercontext-1) | #### Returns @@ -310,28 +303,28 @@ Defined in: [recipe/totp/index.ts:77](https://github.com/supertokens/supertokens ### GetRedirectionURLContext -Re-exports [GetRedirectionURLContext](recipe-totp-types.mdx#getredirectionurlcontext) +Re-exports [GetRedirectionURLContext](recipe-totp-types#getredirectionurlcontext) *** ### OnHandleEventContext -Re-exports [OnHandleEventContext](recipe-totp-types.mdx#onhandleeventcontext) +Re-exports [OnHandleEventContext](recipe-totp-types#onhandleeventcontext) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-totp-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-totp-types#preapihookcontext) *** ### RecipeInterface -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### UserInput -Re-exports [UserInput](recipe-totp-types.mdx#userinput) +Re-exports [UserInput](recipe-totp-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-userroles.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-userroles.mdx index 0a371fd935..1e8b41a9b0 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-userroles.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-userroles.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/userroles -page_title: UserRoles -sidebar_position: 11 description: References documentation for the supertokens-auth-react/recipe/userroles package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 11 --- -# UserRoles - - ## Classes ### default @@ -41,10 +34,10 @@ new default(): default; ### PermissionClaim -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) *** ### UserRoleClaim -Renames and re-exports [SuperTokensWrapper](index.mdx#supertokenswrapper-1) +Renames and re-exports [SuperTokensWrapper](index#supertokenswrapper-1) diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn-types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn-types.mdx index f37c585f3a..ef86bd7a08 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn-types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/webauthn/types -page_title: WebAuthn Types -sidebar_position: 12 description: References documentation for the supertokens-auth-react/recipe/webauthn/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 12 --- -# WebAuthn Types - - ## Enumerations ### RecoverAccountScreen @@ -52,21 +45,21 @@ Defined in: [recipe/webauthn/types.ts:125](https://github.com/supertokens/supert | Property | Type | Defined in | | ------ | ------ | ------ | -| `WebauthnContinueWithoutPasskey_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:133](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L133) | -| `WebauthnContinueWithPasskey_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:126](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L126) | -| `WebauthnMFAFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:140](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L140) | -| `WebauthnMFALoadingScreen_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:137](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L137) | -| `WebauthnMFASignIn_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:136](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L136) | -| `WebauthnMFASignUp_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:138](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L138) | -| `WebauthnMFASignUpConfirmation_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:139](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L139) | -| `WebauthnPasskeyConfirmation_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:131](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L131) | -| `WebauthnPasskeyFeatureBlock_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:132](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L132) | -| `WebauthnPasskeyNotSupportedError_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:127](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L127) | -| `WebauthnPasskeyRecoveryEmailSent_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:128](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L128) | -| `WebauthnPasskeySignUpForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:134](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L134) | -| `WebauthnPasskeySignUpSomethingWentWrong_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:135](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L135) | -| `WebauthnRecoverAccount_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:130](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L130) | -| `WebauthnRecoverAccountForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:129](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L129) | +| `WebauthnContinueWithoutPasskey_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:133](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L133) | +| `WebauthnContinueWithPasskey_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:126](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L126) | +| `WebauthnMFAFooter_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:140](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L140) | +| `WebauthnMFALoadingScreen_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:137](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L137) | +| `WebauthnMFASignIn_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:136](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L136) | +| `WebauthnMFASignUp_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:138](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L138) | +| `WebauthnMFASignUpConfirmation_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:139](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L139) | +| `WebauthnPasskeyConfirmation_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:131](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L131) | +| `WebauthnPasskeyFeatureBlock_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:132](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L132) | +| `WebauthnPasskeyNotSupportedError_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:127](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L127) | +| `WebauthnPasskeyRecoveryEmailSent_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:128](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L128) | +| `WebauthnPasskeySignUpForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:134](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L134) | +| `WebauthnPasskeySignUpSomethingWentWrong_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:135](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L135) | +| `WebauthnRecoverAccount_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:130](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L130) | +| `WebauthnRecoverAccountForm_Override?` | `ComponentOverride`\<*typeof* [`SuperTokensWrapper`](index#supertokenswrapper-1)\> | [recipe/webauthn/types.ts:129](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L129) | *** @@ -177,7 +170,7 @@ Defined in: [recipe/webauthn/types.ts:113](https://github.com/supertokens/supert | ------ | ------ | ------ | | `disableDefaultUI?` | `boolean` | [recipe/webauthn/types.ts:116](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L116) | | `override` | `object` | [recipe/webauthn/types.ts:118](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L118) | -| `override.functions()` | (`originalImplementation`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/webauthn/types.ts:119](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L119) | +| `override.functions()` | (`originalImplementation`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/webauthn/types.ts:119](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L119) | | `recoveryFeature` | [`NormalisedRecoveryFeatureConfig`](#normalisedrecoveryfeatureconfig) | [recipe/webauthn/types.ts:115](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L115) | | `signInAndUpFeature` | [`NormalisedSignInAndUpFormFeatureConfig`](#normalisedsigninandupformfeatureconfig) | [recipe/webauthn/types.ts:114](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L114) | @@ -282,9 +275,9 @@ Defined in: [recipe/webauthn/types.ts:178](https://github.com/supertokens/supert | Property | Type | Defined in | | ------ | ------ | ------ | | `children?` | `React.ReactNode` | [recipe/webauthn/types.ts:182](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L182) | -| `recipe` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/webauthn/types.ts:180](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L180) | +| `recipe` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/webauthn/types.ts:180](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L180) | | `useComponentOverrides` | () => [`ComponentOverrideMap`](#componentoverridemap) | [recipe/webauthn/types.ts:181](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L181) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/webauthn/types.ts:179](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L179) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/webauthn/types.ts:179](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L179) | *** @@ -311,7 +304,7 @@ Defined in: [recipe/webauthn/types.ts:195](https://github.com/supertokens/supert | `recipeImplementation` | [`RecipeImplementation`](#recipeimplementation-1) | [recipe/webauthn/types.ts:198](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L198) | | `registerOptions` | [`RegisterOptions`](#registeroptions-1) \| `null` | [recipe/webauthn/types.ts:203](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L203) | | `token` | `string` \| `null` | [recipe/webauthn/types.ts:202](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L202) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/webauthn/types.ts:197](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L197) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/webauthn/types.ts:197](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L197) | *** @@ -358,9 +351,9 @@ Defined in: [recipe/webauthn/types.ts:210](https://github.com/supertokens/supert | Property | Type | Defined in | | ------ | ------ | ------ | | `children?` | `React.ReactNode` | [recipe/webauthn/types.ts:214](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L214) | -| `recipe` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/webauthn/types.ts:212](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L212) | +| `recipe` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/webauthn/types.ts:212](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L212) | | `useComponentOverrides` | () => [`ComponentOverrideMap`](#componentoverridemap) | [recipe/webauthn/types.ts:213](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L213) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/webauthn/types.ts:211](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L211) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/webauthn/types.ts:211](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L211) | *** @@ -387,7 +380,7 @@ Defined in: [recipe/webauthn/types.ts:222](https://github.com/supertokens/supert | `recipeImplementation` | [`RecipeImplementation`](#recipeimplementation-1) | [recipe/webauthn/types.ts:225](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L225) | | `recoverAccountEmail` | `string` | [recipe/webauthn/types.ts:229](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L229) | | `setActiveScreen` | `React.Dispatch`\<`React.SetStateAction`\<[`SendRecoveryEmailScreen`](#sendrecoveryemailscreen)\>\> | [recipe/webauthn/types.ts:231](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L231) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/webauthn/types.ts:224](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L224) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/webauthn/types.ts:224](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L224) | *** @@ -454,7 +447,7 @@ Defined in: [recipe/webauthn/types.ts:143](https://github.com/supertokens/supert | `recipeImplementation` | [`RecipeImplementation`](#recipeimplementation-1) | [recipe/webauthn/types.ts:145](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L145) | | `resetFactorList` | () => `void` | [recipe/webauthn/types.ts:153](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L153) | | `showBackButton` | `boolean` | [recipe/webauthn/types.ts:155](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L155) | -| `userContext` | [`UserContext`](types.mdx#usercontext-1) | [recipe/webauthn/types.ts:152](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L152) | +| `userContext` | [`UserContext`](types#usercontext-1) | [recipe/webauthn/types.ts:152](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L152) | *** @@ -487,7 +480,7 @@ Defined in: [recipe/webauthn/types.ts:96](https://github.com/supertokens/superto | Name | Type | Defined in | | ------ | ------ | ------ | | `override?` | `object` | [recipe/webauthn/types.ts:97](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L97) | -| `override.functions()?` | (`originalImplementation`) => [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [recipe/webauthn/types.ts:98](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L98) | +| `override.functions()?` | (`originalImplementation`) => [`SuperTokensWrapper`](index#supertokenswrapper-1) | [recipe/webauthn/types.ts:98](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L98) | | `recoveryFeature?` | [`NormalisedRecoveryFeatureConfig`](#normalisedrecoveryfeatureconfig) | [recipe/webauthn/types.ts:101](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L101) | | `signInAndUpFeature?` | [`NormalisedSignInAndUpFormFeatureConfig`](#normalisedsigninandupformfeatureconfig) | [recipe/webauthn/types.ts:100](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L100) | @@ -538,7 +531,7 @@ Defined in: [recipe/webauthn/types.ts:307](https://github.com/supertokens/supert | `onSignOutClicked` | () => `void` | [recipe/webauthn/types.ts:311](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L311) | | `onSignUp` | (`email`) => `Promise`\<`void`\> | [recipe/webauthn/types.ts:313](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L313) | | `recipeImplementation` | [`RecipeImplementation`](#recipeimplementation-1) | [recipe/webauthn/types.ts:308](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L308) | -| `userContext?` | [`UserContext`](types.mdx#usercontext-1) | [recipe/webauthn/types.ts:315](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L315) | +| `userContext?` | [`UserContext`](types#usercontext-1) | [recipe/webauthn/types.ts:315](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/recipe/webauthn/types.ts#L315) | *** diff --git a/docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn.mdx b/docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn.mdx index 995370a19d..a066f91539 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/recipe/webauthn -page_title: WebAuthn -sidebar_position: 12 description: References documentation for the supertokens-auth-react/recipe/webauthn package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 12 --- -# WebAuthn - - ## Classes ### default @@ -62,8 +55,8 @@ Defined in: [recipe/webauthn/index.ts:275](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `authenticationOptions`: `Omit`\<[`SuperTokensWrapper`](index.mdx#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | -| `input.authenticationOptions` | `Omit`\<[`SuperTokensWrapper`](index.mdx#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\> | +| `input` | \{ `authenticationOptions`: `Omit`\<[`SuperTokensWrapper`](index#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | +| `input.authenticationOptions` | `Omit`\<[`SuperTokensWrapper`](index#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\> | | `input.userContext` | `any` | ###### Returns @@ -152,8 +145,8 @@ Defined in: [recipe/webauthn/index.ts:252](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `registrationOptions`: `Omit`\<[`SuperTokensWrapper`](index.mdx#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | -| `input.registrationOptions` | `Omit`\<[`SuperTokensWrapper`](index.mdx#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\> | +| `input` | \{ `registrationOptions`: `Omit`\<[`SuperTokensWrapper`](index#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | +| `input.registrationOptions` | `Omit`\<[`SuperTokensWrapper`](index#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\> | | `input.userContext` | `any` | ###### Returns @@ -382,7 +375,7 @@ Defined in: [recipe/webauthn/index.ts:29](https://github.com/supertokens/superto | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-webauthn-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-webauthn-types#userinput) | ###### Returns @@ -589,8 +582,8 @@ Defined in: [recipe/webauthn/index.ts:538](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `authenticationOptions`: `Omit`\<[`SuperTokensWrapper`](index.mdx#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | -| `input.authenticationOptions` | `Omit`\<[`SuperTokensWrapper`](index.mdx#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\> | +| `input` | \{ `authenticationOptions`: `Omit`\<[`SuperTokensWrapper`](index#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | +| `input.authenticationOptions` | `Omit`\<[`SuperTokensWrapper`](index#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\> | | `input.userContext` | `any` | #### Returns @@ -685,8 +678,8 @@ Defined in: [recipe/webauthn/index.ts:537](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `input` | \{ `registrationOptions`: `Omit`\<[`SuperTokensWrapper`](index.mdx#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | -| `input.registrationOptions` | `Omit`\<[`SuperTokensWrapper`](index.mdx#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\> | +| `input` | \{ `registrationOptions`: `Omit`\<[`SuperTokensWrapper`](index#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | +| `input.registrationOptions` | `Omit`\<[`SuperTokensWrapper`](index#supertokenswrapper-1), `"fetchResponse"` \| `"status"`\> | | `input.userContext` | `any` | #### Returns @@ -927,7 +920,7 @@ Defined in: [recipe/webauthn/index.ts:529](https://github.com/supertokens/supert | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-webauthn-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-webauthn-types#userinput) | #### Returns diff --git a/docs/references/frontend-sdks/supertokens-auth-react/types.mdx b/docs/references/frontend-sdks/supertokens-auth-react/types.mdx index f857169437..a48d7ddd92 100644 --- a/docs/references/frontend-sdks/supertokens-auth-react/types.mdx +++ b/docs/references/frontend-sdks/supertokens-auth-react/types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-auth-react/types -page_title: SuperTokens React Types -sidebar_position: 1 description: References documentation for the supertokens-auth-react/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 1 --- -# SuperTokens React Types - - ## Type Aliases ### AllRecipeComponentOverrides @@ -27,16 +20,16 @@ Defined in: [types.ts:509](https://github.com/supertokens/supertokens-auth-react | Property | Type | Defined in | | ------ | ------ | ------ | | `authRecipe` | `AuthRecipeComponentOverrideMap` | [types.ts:519](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L519) | -| `emailpassword` | [`ComponentOverrideMap`](recipe-emailpassword-types.mdx#componentoverridemap) | [types.ts:510](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L510) | -| `emailverification` | [`ComponentOverrideMap`](recipe-emailverification-types.mdx#componentoverridemap) | [types.ts:511](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L511) | -| `multifactorauth` | [`ComponentOverrideMap`](recipe-multifactorauth-types.mdx#componentoverridemap) | [types.ts:512](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L512) | -| `multitenancy` | [`ComponentOverrideMap`](recipe-multitenancy-types.mdx#componentoverridemap) | [types.ts:513](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L513) | -| `oauth2provider` | [`ComponentOverrideMap`](recipe-oauth2provider-types.mdx#componentoverridemap) | [types.ts:514](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L514) | -| `passwordless` | [`ComponentOverrideMap`](recipe-passwordless-types.mdx#componentoverridemap) | [types.ts:515](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L515) | -| `session` | [`ComponentOverrideMap`](recipe-session-types.mdx#componentoverridemap) | [types.ts:516](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L516) | -| `thirdparty` | [`ComponentOverrideMap`](recipe-thirdparty-types.mdx#componentoverridemap) | [types.ts:517](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L517) | -| `totp` | [`ComponentOverrideMap`](recipe-totp-types.mdx#componentoverridemap) | [types.ts:518](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L518) | -| `webauthn` | [`ComponentOverrideMap`](recipe-webauthn-types.mdx#componentoverridemap) | [types.ts:520](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L520) | +| `emailpassword` | [`ComponentOverrideMap`](recipe-emailpassword-types#componentoverridemap) | [types.ts:510](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L510) | +| `emailverification` | [`ComponentOverrideMap`](recipe-emailverification-types#componentoverridemap) | [types.ts:511](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L511) | +| `multifactorauth` | [`ComponentOverrideMap`](recipe-multifactorauth-types#componentoverridemap) | [types.ts:512](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L512) | +| `multitenancy` | [`ComponentOverrideMap`](recipe-multitenancy-types#componentoverridemap) | [types.ts:513](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L513) | +| `oauth2provider` | [`ComponentOverrideMap`](recipe-oauth2provider-types#componentoverridemap) | [types.ts:514](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L514) | +| `passwordless` | [`ComponentOverrideMap`](recipe-passwordless-types#componentoverridemap) | [types.ts:515](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L515) | +| `session` | [`ComponentOverrideMap`](recipe-session-types#componentoverridemap) | [types.ts:516](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L516) | +| `thirdparty` | [`ComponentOverrideMap`](recipe-thirdparty-types#componentoverridemap) | [types.ts:517](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L517) | +| `totp` | [`ComponentOverrideMap`](recipe-totp-types#componentoverridemap) | [types.ts:518](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L518) | +| `webauthn` | [`ComponentOverrideMap`](recipe-webauthn-types#componentoverridemap) | [types.ts:520](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L520) | *** @@ -52,16 +45,16 @@ Defined in: [types.ts:496](https://github.com/supertokens/supertokens-auth-react | Property | Type | Defined in | | ------ | ------ | ------ | -| `emailpassword` | [`Config`](recipe-emailpassword-types.mdx#config) | [types.ts:497](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L497) | -| `emailverification` | [`Config`](recipe-emailverification-types.mdx#config) | [types.ts:498](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L498) | -| `multifactorauth` | [`Config`](recipe-multifactorauth-types.mdx#config) | [types.ts:499](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L499) | -| `multitenancy` | [`UserInput`](recipe-multitenancy-types.mdx#userinput) | [types.ts:500](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L500) | -| `oauth2provider` | [`UserInput`](recipe-oauth2provider-types.mdx#userinput) | [types.ts:501](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L501) | -| `passwordless` | [`Config`](recipe-passwordless-types.mdx#config) | [types.ts:502](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L502) | -| `session` | [`InputType`](recipe-session-types.mdx#inputtype) | [types.ts:503](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L503) | -| `thirdparty` | [`Config`](recipe-thirdparty-types.mdx#config) | [types.ts:504](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L504) | -| `totp` | [`Config`](recipe-totp-types.mdx#config) | [types.ts:505](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L505) | -| `webauthn` | [`Config`](recipe-webauthn-types.mdx#config) | [types.ts:506](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L506) | +| `emailpassword` | [`Config`](recipe-emailpassword-types#config) | [types.ts:497](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L497) | +| `emailverification` | [`Config`](recipe-emailverification-types#config) | [types.ts:498](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L498) | +| `multifactorauth` | [`Config`](recipe-multifactorauth-types#config) | [types.ts:499](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L499) | +| `multitenancy` | [`UserInput`](recipe-multitenancy-types#userinput) | [types.ts:500](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L500) | +| `oauth2provider` | [`UserInput`](recipe-oauth2provider-types#userinput) | [types.ts:501](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L501) | +| `passwordless` | [`Config`](recipe-passwordless-types#config) | [types.ts:502](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L502) | +| `session` | [`InputType`](recipe-session-types#inputtype) | [types.ts:503](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L503) | +| `thirdparty` | [`Config`](recipe-thirdparty-types#config) | [types.ts:504](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L504) | +| `totp` | [`Config`](recipe-totp-types#config) | [types.ts:505](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L505) | +| `webauthn` | [`Config`](recipe-webauthn-types#config) | [types.ts:506](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L506) | *** @@ -389,11 +382,11 @@ Defined in: [types.ts:248](https://github.com/supertokens/supertokens-auth-react | Property | Type | Defined in | | ------ | ------ | ------ | -| `apiBasePath` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [types.ts:268](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L268) | -| `apiDomain` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [types.ts:257](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L257) | +| `apiBasePath` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [types.ts:268](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L268) | +| `apiDomain` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [types.ts:257](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L257) | | `appName` | `string` | [types.ts:252](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L252) | -| `websiteBasePath` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [types.ts:274](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L274) | -| `websiteDomain` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | [types.ts:262](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L262) | +| `websiteBasePath` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [types.ts:274](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L274) | +| `websiteDomain` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | [types.ts:262](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L262) | *** @@ -578,7 +571,7 @@ Defined in: [types.ts:237](https://github.com/supertokens/supertokens-auth-react | ------ | ------ | ------ | | `authReact` | [`CreateRecipeFunction`](#createrecipefunction)\<`T`, `Action`, `R`, `P`\> | [types.ts:239](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L239) | | `recipeID` | `string` | [types.ts:238](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L238) | -| `webJS` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1)\<`Action`\> | [types.ts:240](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L240) | +| `webJS` | [`SuperTokensWrapper`](index#supertokenswrapper-1)\<`Action`\> | [types.ts:240](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L240) | *** @@ -683,8 +676,8 @@ Defined in: [types.ts:99](https://github.com/supertokens/supertokens-auth-react/ | ------ | ------ | ------ | ------ | | `appInfo` | [`AppInfoUserInput`](#appinfouserinput) | - | [types.ts:103](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L103) | | `clientType?` | `string` | Identifier for the client, such as `web`, `ios`, etc. to be used with thirdparty, multitenancy recipes. | [types.ts:108](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L108) | -| `cookieHandler?` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | - | [types.ts:119](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L119) | -| `dateProvider?` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | - | [types.ts:123](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L123) | +| `cookieHandler?` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | - | [types.ts:119](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L119) | +| `dateProvider?` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | - | [types.ts:123](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L123) | | `defaultToSignUp?` | `boolean` | - | [types.ts:169](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L169) | | `disableAuthRoute?` | `boolean` | - | [types.ts:164](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L164) | | `enableDebugLogs?` | `boolean` | - | [types.ts:156](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L156) | @@ -695,14 +688,14 @@ Defined in: [types.ts:99](https://github.com/supertokens/supertokens-auth-react/ | `languageTranslations.currentLanguageCookieScope?` | `string` | - | [types.ts:137](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L137) | | `languageTranslations.defaultLanguage?` | `string` | - | [types.ts:131](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L131) | | `languageTranslations.translationFunc?` | `TranslationFunc` | - | [types.ts:154](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L154) | -| `languageTranslations.translations?` | [`TranslationStore`](index.mdx#translationstore) | - | [types.ts:149](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L149) | +| `languageTranslations.translations?` | [`TranslationStore`](index#translationstore) | - | [types.ts:149](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L149) | | `privacyPolicyLink?` | `string` | - | [types.ts:174](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L174) | | `recipeList` | `object`[] | - | [types.ts:113](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L113) | | `style?` | `string` | - | [types.ts:162](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L162) | | `termsOfServiceLink?` | `string` | - | [types.ts:179](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L179) | | `usesDynamicLoginMethods?` | `boolean` | - | [types.ts:125](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L125) | | `useShadowDom?` | `boolean` | - | [types.ts:163](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L163) | -| `windowHandler?` | [`SuperTokensWrapper`](index.mdx#supertokenswrapper-1) | - | [types.ts:121](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L121) | +| `windowHandler?` | [`SuperTokensWrapper`](index#supertokenswrapper-1) | - | [types.ts:121](https://github.com/supertokens/supertokens-auth-react/blob/b337b23722adfbe2906b193ea5fcf98f9c98c8b0/lib/ts/types.ts#L121) | *** diff --git a/docs/references/frontend-sdks/supertokens-web-js/_category_.json b/docs/references/frontend-sdks/supertokens-web-js/_category_.json deleted file mode 100644 index b3dc94b317..0000000000 --- a/docs/references/frontend-sdks/supertokens-web-js/_category_.json +++ /dev/null @@ -1 +0,0 @@ -{"label":"Javascript SDK Reference","position":4} \ No newline at end of file diff --git a/docs/references/frontend-sdks/supertokens-web-js/meta.ts b/docs/references/frontend-sdks/supertokens-web-js/meta.ts new file mode 100644 index 0000000000..eeefdc80ba --- /dev/null +++ b/docs/references/frontend-sdks/supertokens-web-js/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Javascript SDK Reference", + "icon": "/img/logos/js.svg", + "order": 4 +}); diff --git a/docs/references/frontend-sdks/supertokens-web-js/package.mdx b/docs/references/frontend-sdks/supertokens-web-js/package.mdx index 847fe4f0b8..e889237c9a 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/package.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/package.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js -page_title: SuperTokens Web JS -sidebar_position: 1 description: References documentation for the supertokens-web-js package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 1 --- -# SuperTokens Web JS - - ## Classes ### default @@ -44,7 +37,7 @@ Defined in: [tmp/supertokens-web-js/lib/ts/index.ts:21](https://github.com/super | Parameter | Type | | ------ | ------ | -| `config` | [`SuperTokensConfig`](types.mdx#supertokensconfig) | +| `config` | [`SuperTokensConfig`](types#supertokensconfig) | ###### Returns @@ -64,7 +57,7 @@ Defined in: [tmp/supertokens-web-js/lib/ts/index.ts:26](https://github.com/super | Parameter | Type | | ------ | ------ | -| `config` | [`SuperTokensConfig`](types.mdx#supertokensconfig) | +| `config` | [`SuperTokensConfig`](types#supertokensconfig) | #### Returns @@ -74,22 +67,22 @@ Defined in: [tmp/supertokens-web-js/lib/ts/index.ts:26](https://github.com/super ### SuperTokensConfig -Re-exports [SuperTokensConfig](types.mdx#supertokensconfig) +Re-exports [SuperTokensConfig](types#supertokensconfig) *** ### SuperTokensPlugin -Re-exports [SuperTokensPlugin](types.mdx#supertokensplugin) +Re-exports [SuperTokensPlugin](types#supertokensplugin) *** ### SuperTokensPublicConfig -Re-exports [SuperTokensPublicConfig](types.mdx#supertokenspublicconfig) +Re-exports [SuperTokensPublicConfig](types#supertokenspublicconfig) *** ### SuperTokensPublicPlugin -Re-exports [SuperTokensPublicPlugin](types.mdx#supertokenspublicplugin) +Re-exports [SuperTokensPublicPlugin](types#supertokenspublicplugin) diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword-types.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword-types.mdx index 8e353edb50..fc0e03dc8f 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword-types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/emailpassword/types -page_title: EmailPassword Types -sidebar_position: 2 description: References documentation for the supertokens-web-js/recipe/emailpassword/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 2 --- -# EmailPassword Types - - ## Type Aliases ### InputType @@ -92,8 +85,8 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/types.ts:62](htt | `getResetPasswordTokenFromURL` | (`input`) => `string` | Reads and returns the reset password token from the current URL | [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/types.ts:272](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/emailpassword/types.ts#L272) | | `getTenantIdFromURL` | (`input`) => `string` \| `undefined` | Reads and returns the tenant id from the current URL | [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/types.ts:281](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/emailpassword/types.ts#L281) | | `sendPasswordResetEmail` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"PASSWORD_RESET_NOT_ALLOWED"`; \} \| \{ `fetchResponse`: `Response`; `formFields`: `object`[]; `status`: `"FIELD_ERROR"`; \}\> | Send an email to the user for password reset **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/types.ts:121](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/emailpassword/types.ts#L121) | -| `signIn` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `fetchResponse`: `Response`; `formFields`: `object`[]; `status`: `"FIELD_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"WRONG_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_NOT_ALLOWED"`; \}\> | Sign in a user with email and password **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/types.ts:213](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/emailpassword/types.ts#L213) | -| `signUp` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `fetchResponse`: `Response`; `formFields`: `object`[]; `status`: `"FIELD_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_UP_NOT_ALLOWED"`; \}\> | Sign up a user with email and password **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/types.ts:165](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/emailpassword/types.ts#L165) | +| `signIn` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; `formFields`: `object`[]; `status`: `"FIELD_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"WRONG_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_NOT_ALLOWED"`; \}\> | Sign in a user with email and password **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/types.ts:213](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/emailpassword/types.ts#L213) | +| `signUp` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; `formFields`: `object`[]; `status`: `"FIELD_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_UP_NOT_ALLOWED"`; \}\> | Sign up a user with email and password **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/types.ts:165](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/emailpassword/types.ts#L165) | | `submitNewPassword` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"RESET_PASSWORD_INVALID_TOKEN_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `formFields`: `object`[]; `status`: `"FIELD_ERROR"`; \}\> | Submit a new password for the user **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/types.ts:80](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/emailpassword/types.ts#L80) | *** diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword.mdx index cda3b7d126..1f5414b656 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/emailpassword -page_title: EmailPassword -sidebar_position: 2 description: References documentation for the supertokens-web-js/recipe/emailpassword package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 2 --- -# EmailPassword - - ## Classes ### default @@ -127,11 +120,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/index.ts:22](htt | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-emailpassword-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-emailpassword-types#userinput) | ###### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-emailpassword-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-emailpassword-types#preandpostapihookaction)\> ##### sendPasswordResetEmail() @@ -235,7 +228,7 @@ Sign in a user with email and password \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -318,7 +311,7 @@ Sign up a user with email and password \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -517,11 +510,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/emailpassword/index.ts:294](ht | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-emailpassword-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-emailpassword-types#userinput) | #### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-emailpassword-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-emailpassword-types#preandpostapihookaction)\> *** @@ -629,7 +622,7 @@ Sign in a user with email and password \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -716,7 +709,7 @@ Sign up a user with email and password \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -796,22 +789,22 @@ STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ ### PostAPIHookContext -Re-exports [PostAPIHookContext](recipe-emailpassword-types.mdx#postapihookcontext) +Re-exports [PostAPIHookContext](recipe-emailpassword-types#postapihookcontext) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-emailpassword-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-emailpassword-types#preapihookcontext) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-emailpassword-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-emailpassword-types#recipeinterface) *** ### UserInput -Re-exports [UserInput](recipe-emailpassword-types.mdx#userinput) +Re-exports [UserInput](recipe-emailpassword-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification-types.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification-types.mdx index 6cd7320e81..5d959ff861 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification-types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/emailverification/types -page_title: EmailVerification Types -sidebar_position: 3 description: References documentation for the supertokens-web-js/recipe/emailverification/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 3 --- -# EmailVerification Types - - ## Type Aliases ### InputType diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification.mdx index dce0282015..b28aad5b44 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/emailverification -page_title: EmailVerification -sidebar_position: 3 description: References documentation for the supertokens-web-js/recipe/emailverification package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 3 --- -# EmailVerification - - ## Classes ### default @@ -92,11 +85,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/emailverification/index.ts:24] | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-emailverification-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-emailverification-types#userinput) | ###### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-emailverification-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-emailverification-types#preandpostapihookaction)\> ##### isEmailVerified() @@ -116,8 +109,8 @@ Check if an email has been verified | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -151,8 +144,8 @@ Send an email to the user for verification. | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -185,8 +178,8 @@ Verify an email | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -212,7 +205,7 @@ We include "Class" in the class name, because it makes it easier to import/use t #### Extends -- [`BooleanClaim`](recipe-session.mdx#booleanclaim) +- [`BooleanClaim`](recipe-session#booleanclaim) #### Constructors @@ -228,7 +221,7 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/emailverification/emailVerific | Parameter | Type | | ------ | ------ | -| `getRecipeImpl` | () => [`RecipeInterface`](recipe-emailverification-types.mdx#recipeinterface) | +| `getRecipeImpl` | () => [`RecipeInterface`](recipe-emailverification-types#recipeinterface) | ###### Returns @@ -236,16 +229,16 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/emailverification/emailVerific ###### Overrides -[`BooleanClaim`](recipe-session.mdx#booleanclaim).[`constructor`](recipe-session.mdx#constructor) +[`BooleanClaim`](recipe-session#booleanclaim).[`constructor`](recipe-session#constructor) #### Properties | Property | Modifier | Type | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | -| `defaultMaxAgeInSeconds` | `readonly` | `number` | - | [`PrimitiveClaim`](recipe-session.mdx#primitiveclaim).[`defaultMaxAgeInSeconds`](recipe-session.mdx#defaultmaxageinseconds-2) | node\_modules/supertokens-website/lib/build/claims/primitiveClaim.d.ts:10 | -| `id` | `readonly` | `string` | - | [`PrimitiveClaim`](recipe-session.mdx#primitiveclaim).[`id`](recipe-session.mdx#id-2) | node\_modules/supertokens-website/lib/build/claims/primitiveClaim.d.ts:8 | -| `refresh` | `readonly` | (`userContext`) => `Promise`\<`void`\> | - | [`BooleanClaim`](recipe-session.mdx#booleanclaim).[`refresh`](recipe-session.mdx#refresh) | node\_modules/supertokens-website/lib/build/claims/primitiveClaim.d.ts:9 | -| `validators` | `public` | `object` & `BooleanValidators` & `object` | [`BooleanClaim`](recipe-session.mdx#booleanclaim).[`validators`](recipe-session.mdx#validators) | - | [tmp/supertokens-web-js/lib/ts/recipe/emailverification/emailVerificationClaim.ts:82](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/emailverification/emailVerificationClaim.ts#L82) | +| `defaultMaxAgeInSeconds` | `readonly` | `number` | - | [`PrimitiveClaim`](recipe-session#primitiveclaim).[`defaultMaxAgeInSeconds`](recipe-session#defaultmaxageinseconds-2) | node\_modules/supertokens-website/lib/build/claims/primitiveClaim.d.ts:10 | +| `id` | `readonly` | `string` | - | [`PrimitiveClaim`](recipe-session#primitiveclaim).[`id`](recipe-session#id-2) | node\_modules/supertokens-website/lib/build/claims/primitiveClaim.d.ts:8 | +| `refresh` | `readonly` | (`userContext`) => `Promise`\<`void`\> | - | [`BooleanClaim`](recipe-session#booleanclaim).[`refresh`](recipe-session#refresh) | node\_modules/supertokens-website/lib/build/claims/primitiveClaim.d.ts:9 | +| `validators` | `public` | `object` & `BooleanValidators` & `object` | [`BooleanClaim`](recipe-session#booleanclaim).[`validators`](recipe-session#validators) | - | [tmp/supertokens-web-js/lib/ts/recipe/emailverification/emailVerificationClaim.ts:82](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/emailverification/emailVerificationClaim.ts#L82) | #### Methods @@ -270,7 +263,7 @@ Defined in: node\_modules/supertokens-website/lib/build/claims/primitiveClaim.d. ###### Inherited from -[`BooleanClaim`](recipe-session.mdx#booleanclaim).[`getLastFetchedTime`](recipe-session.mdx#getlastfetchedtime) +[`BooleanClaim`](recipe-session#booleanclaim).[`getLastFetchedTime`](recipe-session#getlastfetchedtime) ##### getValueFromPayload() @@ -293,7 +286,7 @@ Defined in: node\_modules/supertokens-website/lib/build/claims/primitiveClaim.d. ###### Inherited from -[`BooleanClaim`](recipe-session.mdx#booleanclaim).[`getValueFromPayload`](recipe-session.mdx#getvaluefrompayload) +[`BooleanClaim`](recipe-session#booleanclaim).[`getValueFromPayload`](recipe-session#getvaluefrompayload) ## Variables @@ -365,11 +358,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/emailverification/index.ts:116 | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-emailverification-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-emailverification-types#userinput) | #### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-emailverification-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-emailverification-types#preandpostapihookaction)\> *** @@ -391,8 +384,8 @@ Check if an email has been verified | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -428,8 +421,8 @@ Send an email to the user for verification. | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -464,8 +457,8 @@ Verify an email | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -485,28 +478,28 @@ STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ ### PostAPIHookContext -Re-exports [PostAPIHookContext](recipe-emailverification-types.mdx#postapihookcontext) +Re-exports [PostAPIHookContext](recipe-emailverification-types#postapihookcontext) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-emailverification-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-emailverification-types#preapihookcontext) *** ### RecipeFunctionOptions -Re-exports [RecipeFunctionOptions](recipe-emailpassword.mdx#recipefunctionoptions) +Re-exports [RecipeFunctionOptions](recipe-emailpassword#recipefunctionoptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-emailverification-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-emailverification-types#recipeinterface) *** ### UserInput -Re-exports [UserInput](recipe-emailverification-types.mdx#userinput) +Re-exports [UserInput](recipe-emailverification-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth-types.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth-types.mdx index 43a7b587ff..9909ea9bde 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth-types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/multifactorauth/types -page_title: MFA Types -sidebar_position: 4 description: References documentation for the supertokens-web-js/recipe/multifactorauth/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 4 --- -# MFA Types - - ## Type Aliases ### InputType diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth.mdx index 1c387208f9..5a84cb4ad6 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/multifactorauth -page_title: MFA -sidebar_position: 4 description: References documentation for the supertokens-web-js/recipe/multifactorauth package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 4 --- -# MFA - - ## Classes ### default @@ -50,11 +43,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/index.ts:23](h | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-multifactorauth-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-multifactorauth-types#userinput) | ###### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<`"GET_MFA_INFO"`\> +[`CreateRecipeFunction`](types#createrecipefunction)\<`"GET_MFA_INFO"`\> ##### resyncSessionAndFetchMFAInfo() @@ -76,15 +69,15 @@ Loads information about what factors the current session can set up/complete and | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns `Promise`\<\{ `emails`: `Record`\<`string`, `string`[] \| `undefined`\>; - `factors`: [`MFAFactorInfo`](recipe-multifactorauth-types.mdx#mfafactorinfo); + `factors`: [`MFAFactorInfo`](recipe-multifactorauth-types#mfafactorinfo); `fetchResponse`: `Response`; `phoneNumbers`: `Record`\<`string`, `string`[] \| `undefined`\>; `status`: `"OK"`; @@ -102,7 +95,7 @@ We include "Class" in the class name, because it makes it easier to import/use t #### Implements -- [`SessionClaim`](recipe-session.mdx#sessionclaim)\<[`MFAClaimValue`](recipe-multifactorauth-types.mdx#mfaclaimvalue)\> +- [`SessionClaim`](recipe-session#sessionclaim)\<[`MFAClaimValue`](recipe-multifactorauth-types#mfaclaimvalue)\> #### Constructors @@ -118,7 +111,7 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAut | Parameter | Type | | ------ | ------ | -| `getRecipeImpl` | () => [`RecipeInterface`](recipe-multifactorauth-types.mdx#recipeinterface) | +| `getRecipeImpl` | () => [`RecipeInterface`](recipe-multifactorauth-types#recipeinterface) | ###### Returns @@ -128,11 +121,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAut | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `getRecipeImpl` | `protected` | () => [`RecipeInterface`](recipe-multifactorauth-types.mdx#recipeinterface) | `undefined` | [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts:15](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts#L15) | +| `getRecipeImpl` | `protected` | () => [`RecipeInterface`](recipe-multifactorauth-types#recipeinterface) | `undefined` | [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts:15](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts#L15) | | `id` | `public` | `string` | `"st-mfa"` | [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts:9](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts#L9) | | `validators` | `public` | `object` | `undefined` | [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts:10](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts#L10) | -| `validators.hasCompletedFactors` | `public` | (`requirements`) => [`SessionClaimValidator`](recipe-session.mdx#sessionclaimvalidator) | `undefined` | [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts:12](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts#L12) | -| `validators.hasCompletedMFARequirementsForAuth` | `public` | () => [`SessionClaimValidator`](recipe-session.mdx#sessionclaimvalidator) | `undefined` | [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts:11](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts#L11) | +| `validators.hasCompletedFactors` | `public` | (`requirements`) => [`SessionClaimValidator`](recipe-session#sessionclaimvalidator) | `undefined` | [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts:12](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts#L12) | +| `validators.hasCompletedMFARequirementsForAuth` | `public` | () => [`SessionClaimValidator`](recipe-session#sessionclaimvalidator) | `undefined` | [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts:11](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts#L11) | #### Methods @@ -157,7 +150,7 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAut ###### Implementation of -[`SessionClaim`](recipe-session.mdx#sessionclaim).[`getLastFetchedTime`](recipe-session.mdx#getlastfetchedtime-6) +[`SessionClaim`](recipe-session#sessionclaim).[`getLastFetchedTime`](recipe-session#getlastfetchedtime-6) ##### getValueFromPayload() @@ -185,7 +178,7 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAut ###### Implementation of -[`SessionClaim`](recipe-session.mdx#sessionclaim).[`getValueFromPayload`](recipe-session.mdx#getvaluefrompayload-6) +[`SessionClaim`](recipe-session#sessionclaim).[`getValueFromPayload`](recipe-session#getvaluefrompayload-6) ##### refresh() @@ -207,7 +200,7 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/multiFactorAut ###### Implementation of -[`SessionClaim`](recipe-session.mdx#sessionclaim).[`refresh`](recipe-session.mdx#refresh-5) +[`SessionClaim`](recipe-session#sessionclaim).[`refresh`](recipe-session#refresh-5) ## Variables @@ -223,11 +216,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/multifactorauth/index.ts:46](h | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-multifactorauth-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-multifactorauth-types#userinput) | #### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<`"GET_MFA_INFO"`\> +[`CreateRecipeFunction`](types#createrecipefunction)\<`"GET_MFA_INFO"`\> *** @@ -261,15 +254,15 @@ Loads information about what factors the current session can set up/complete and | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns `Promise`\<\{ `emails`: `Record`\<`string`, `string`[] \| `undefined`\>; - `factors`: [`MFAFactorInfo`](recipe-multifactorauth-types.mdx#mfafactorinfo); + `factors`: [`MFAFactorInfo`](recipe-multifactorauth-types#mfafactorinfo); `fetchResponse`: `Response`; `phoneNumbers`: `Record`\<`string`, `string`[] \| `undefined`\>; `status`: `"OK"`; @@ -281,34 +274,34 @@ Loads information about what factors the current session can set up/complete and ### PostAPIHookContext -Re-exports [PostAPIHookContext](recipe-multifactorauth-types.mdx#postapihookcontext) +Re-exports [PostAPIHookContext](recipe-multifactorauth-types#postapihookcontext) *** ### PreAndPostAPIHookAction -Re-exports [PreAndPostAPIHookAction](recipe-multifactorauth-types.mdx#preandpostapihookaction) +Re-exports [PreAndPostAPIHookAction](recipe-multifactorauth-types#preandpostapihookaction) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-multifactorauth-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-multifactorauth-types#preapihookcontext) *** ### RecipeFunctionOptions -Re-exports [RecipeFunctionOptions](recipe-emailpassword.mdx#recipefunctionoptions) +Re-exports [RecipeFunctionOptions](recipe-emailpassword#recipefunctionoptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-multifactorauth-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-multifactorauth-types#recipeinterface) *** ### UserInput -Re-exports [UserInput](recipe-multifactorauth-types.mdx#userinput) +Re-exports [UserInput](recipe-multifactorauth-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy-types.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy-types.mdx index 0cd7be4f47..6d217b9bde 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy-types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/multitenancy/types -page_title: MultiTenancy Types -sidebar_position: 5 description: References documentation for the supertokens-web-js/recipe/multitenancy/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 5 --- -# MultiTenancy Types - - ## Type Aliases ### InputType diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy.mdx index 58d9048a61..59c818e563 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/multitenancy -page_title: MultiTenancy -sidebar_position: 5 description: References documentation for the supertokens-web-js/recipe/multitenancy package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 5 --- -# MultiTenancy - - ## Classes ### default @@ -59,8 +52,8 @@ Gets enabled login methods and their configuration from the backend | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `tenantId?`: `string`; `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `tenantId?`: `string`; `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.tenantId?` | `string` | | `input.userContext?` | `any` | @@ -116,11 +109,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/multitenancy/index.ts:23](http | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-multitenancy-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-multitenancy-types#userinput) | ###### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<`"GET_LOGIN_METHODS"`\> +[`CreateRecipeFunction`](types#createrecipefunction)\<`"GET_LOGIN_METHODS"`\> ## Variables @@ -155,8 +148,8 @@ Gets enabled login methods and their configuration from the backend | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `tenantId?`: `string`; `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `tenantId?`: `string`; `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.tenantId?` | `string` | | `input.userContext?` | `any` | @@ -216,38 +209,38 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/multitenancy/index.ts:73](http | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-multitenancy-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-multitenancy-types#userinput) | #### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<`"GET_LOGIN_METHODS"`\> +[`CreateRecipeFunction`](types#createrecipefunction)\<`"GET_LOGIN_METHODS"`\> ## References ### PostAPIHookContext -Re-exports [PostAPIHookContext](recipe-multitenancy-types.mdx#postapihookcontext) +Re-exports [PostAPIHookContext](recipe-multitenancy-types#postapihookcontext) *** ### PreAndPostAPIHookAction -Re-exports [PreAndPostAPIHookAction](recipe-multitenancy-types.mdx#preandpostapihookaction) +Re-exports [PreAndPostAPIHookAction](recipe-multitenancy-types#preandpostapihookaction) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-multitenancy-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-multitenancy-types#preapihookcontext) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-multitenancy-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-multitenancy-types#recipeinterface) *** ### UserInput -Re-exports [UserInput](recipe-multitenancy-types.mdx#userinput) +Re-exports [UserInput](recipe-multitenancy-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider-types.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider-types.mdx index 2abfe928ac..8099f2ce91 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider-types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/oauth2provider/types -page_title: OAuth Provider Types -sidebar_position: 6 description: References documentation for the supertokens-web-js/recipe/oauth2provider/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 6 --- -# OAuth Provider Types - - ## Type Aliases ### InputType diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider.mdx index 3f1d2d0876..fb7d003ee6 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/oauth2provider -page_title: OAuth Provider -sidebar_position: 6 description: References documentation for the supertokens-web-js/recipe/oauth2provider package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 6 --- -# OAuth Provider - - ## Classes ### default @@ -50,16 +43,16 @@ Returns information about an OAuth login in progress | Parameter | Type | | ------ | ------ | -| `input` | \{ `loginChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input` | \{ `loginChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.loginChallenge` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns `Promise`\<\{ `fetchResponse`: `Response`; - `info`: [`LoginInfo`](recipe-oauth2provider-types.mdx#logininfo); + `info`: [`LoginInfo`](recipe-oauth2provider-types#logininfo); `status`: `"OK"`; \}\> @@ -87,9 +80,9 @@ Accepts the OAuth2 Login request and returns the redirect URL to continue the OA | Parameter | Type | | ------ | ------ | -| `input` | \{ `loginChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input` | \{ `loginChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.loginChallenge` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -118,11 +111,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/oauth2provider/index.ts:29](ht | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-oauth2provider-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-oauth2provider-types#userinput) | ###### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-oauth2provider-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-oauth2provider-types#preandpostapihookaction)\> ##### logOut() @@ -142,9 +135,9 @@ Accepts the OAuth2 Logout request, clears the SuperTokens session and returns po | Parameter | Type | | ------ | ------ | -| `input` | \{ `logoutChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input` | \{ `logoutChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.logoutChallenge` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -181,16 +174,16 @@ Returns information about an OAuth login in progress | Parameter | Type | | ------ | ------ | -| `input` | \{ `loginChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input` | \{ `loginChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.loginChallenge` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns `Promise`\<\{ `fetchResponse`: `Response`; - `info`: [`LoginInfo`](recipe-oauth2provider-types.mdx#logininfo); + `info`: [`LoginInfo`](recipe-oauth2provider-types#logininfo); `status`: `"OK"`; \}\> @@ -220,9 +213,9 @@ Accepts the OAuth2 Login request and returns the redirect URL to continue the OA | Parameter | Type | | ------ | ------ | -| `input` | \{ `loginChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input` | \{ `loginChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.loginChallenge` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -253,11 +246,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/oauth2provider/index.ts:114](h | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-oauth2provider-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-oauth2provider-types#userinput) | #### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-oauth2provider-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-oauth2provider-types#preandpostapihookaction)\> *** @@ -279,9 +272,9 @@ Accepts the OAuth2 Logout request, clears the SuperTokens session and returns po | Parameter | Type | | ------ | ------ | -| `input` | \{ `logoutChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input` | \{ `logoutChallenge`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.logoutChallenge` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -302,40 +295,40 @@ STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ ### LoginInfo -Re-exports [LoginInfo](recipe-oauth2provider-types.mdx#logininfo) +Re-exports [LoginInfo](recipe-oauth2provider-types#logininfo) *** ### PostAPIHookContext -Re-exports [PostAPIHookContext](recipe-oauth2provider-types.mdx#postapihookcontext) +Re-exports [PostAPIHookContext](recipe-oauth2provider-types#postapihookcontext) *** ### PreAndPostAPIHookAction -Re-exports [PreAndPostAPIHookAction](recipe-oauth2provider-types.mdx#preandpostapihookaction) +Re-exports [PreAndPostAPIHookAction](recipe-oauth2provider-types#preandpostapihookaction) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-oauth2provider-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-oauth2provider-types#preapihookcontext) *** ### RecipeFunctionOptions -Re-exports [RecipeFunctionOptions](recipe-emailpassword.mdx#recipefunctionoptions) +Re-exports [RecipeFunctionOptions](recipe-emailpassword#recipefunctionoptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-oauth2provider-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-oauth2provider-types#recipeinterface) *** ### UserInput -Re-exports [UserInput](recipe-oauth2provider-types.mdx#userinput) +Re-exports [UserInput](recipe-oauth2provider-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless-types.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless-types.mdx index 9a7d379762..254d41b8c0 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless-types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/passwordless/types -page_title: Passwordless Types -sidebar_position: 7 description: References documentation for the supertokens-web-js/recipe/passwordless/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 7 --- -# Passwordless Types - - ## Type Aliases ### InputType @@ -99,7 +92,7 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/passwordless/types.ts:62](http | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `clearLoginAttemptInfo` | (`input`) => `Promise`\<`void`\> | Clear any information about login attempts from storage | [tmp/supertokens-web-js/lib/ts/recipe/passwordless/types.ts:312](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/passwordless/types.ts#L312) | -| `consumeCode` | (`input`) => `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; `fetchResponse`: `Response`; `maximumCodeInputAttempts`: `number`; `status`: `"INCORRECT_USER_INPUT_CODE_ERROR"` \| `"EXPIRED_USER_INPUT_CODE_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"RESTART_FLOW_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \}\> | Log the user in using the input code or link code **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/passwordless/types.ts:168](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/passwordless/types.ts#L168) | +| `consumeCode` | (`input`) => `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; `fetchResponse`: `Response`; `maximumCodeInputAttempts`: `number`; `status`: `"INCORRECT_USER_INPUT_CODE_ERROR"` \| `"EXPIRED_USER_INPUT_CODE_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"RESTART_FLOW_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \}\> | Log the user in using the input code or link code **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/passwordless/types.ts:168](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/passwordless/types.ts#L168) | | `createCode` | (`input`) => `Promise`\< \| \{ `deviceId`: `string`; `fetchResponse`: `Response`; `flowType`: [`PasswordlessFlowType`](#passwordlessflowtype); `preAuthSessionId`: `string`; `status`: `"OK"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \}\> | Create and send a code to the user for passwordless auth **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/passwordless/types.ts:80](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/passwordless/types.ts#L80) | | `doesEmailExist` | (`input`) => `Promise`\<\{ `doesExist`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; \}\> | Check if a user with the given email exists **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/passwordless/types.ts:244](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/passwordless/types.ts#L244) | | `doesPhoneNumberExist` | (`input`) => `Promise`\<\{ `doesExist`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; \}\> | Check if a user with the given phone number exists **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/passwordless/types.ts:263](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/passwordless/types.ts#L263) | diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless.mdx index db5bf73074..8ba734c0b8 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/passwordless -page_title: Passwordless -sidebar_position: 7 description: References documentation for the supertokens-web-js/recipe/passwordless package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 7 --- -# Passwordless - - ## Classes ### default @@ -88,7 +81,7 @@ Log the user in using the input code or link code | Parameter | Type | | ------ | ------ | -| `input?` | \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; `userInputCode`: `string`; \} \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input?` | \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; `userInputCode`: `string`; \} \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | ###### Returns @@ -97,7 +90,7 @@ Log the user in using the input code or link code `createdNewRecipeUser`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; @@ -147,7 +140,7 @@ Create and send a code to the user for passwordless auth | Parameter | Type | | ------ | ------ | -| `input` | \| \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: `any`; \} \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `phoneNumber`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: `any`; \} | +| `input` | \| \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: `any`; \} \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `phoneNumber`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: `any`; \} | ###### Returns @@ -155,7 +148,7 @@ Create and send a code to the user for passwordless auth \| \{ `deviceId`: `string`; `fetchResponse`: `Response`; - `flowType`: [`PasswordlessFlowType`](recipe-passwordless-types.mdx#passwordlessflowtype); + `flowType`: [`PasswordlessFlowType`](recipe-passwordless-types#passwordlessflowtype); `preAuthSessionId`: `string`; `status`: `"OK"`; \} @@ -189,9 +182,9 @@ Check if a user with the given email exists | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.email` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -226,8 +219,8 @@ Check if a user with the given phone number exists | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `phoneNumber`: `string`; `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `phoneNumber`: `string`; `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.phoneNumber` | `string` | | `input.userContext?` | `any` | @@ -355,11 +348,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/passwordless/index.ts:31](http | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-passwordless-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-passwordless-types#userinput) | ###### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-passwordless-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-passwordless-types#preandpostapihookaction)\> ##### resendCode() @@ -378,8 +371,8 @@ Resend the code to the user | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -502,7 +495,7 @@ Log the user in using the input code or link code | Parameter | Type | | ------ | ------ | -| `input?` | \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; `userInputCode`: `string`; \} \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input?` | \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; `userInputCode`: `string`; \} \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | #### Returns @@ -511,7 +504,7 @@ Log the user in using the input code or link code `createdNewRecipeUser`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `failedCodeInputAttemptCount`: `number`; @@ -563,7 +556,7 @@ Create and send a code to the user for passwordless auth | Parameter | Type | | ------ | ------ | -| `input` | \| \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: `any`; \} \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `phoneNumber`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: `any`; \} | +| `input` | \| \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: `any`; \} \| \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `phoneNumber`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext?`: `any`; \} | #### Returns @@ -571,7 +564,7 @@ Create and send a code to the user for passwordless auth \| \{ `deviceId`: `string`; `fetchResponse`: `Response`; - `flowType`: [`PasswordlessFlowType`](recipe-passwordless-types.mdx#passwordlessflowtype); + `flowType`: [`PasswordlessFlowType`](recipe-passwordless-types#passwordlessflowtype); `preAuthSessionId`: `string`; `status`: `"OK"`; \} @@ -607,9 +600,9 @@ Check if a user with the given email exists | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.email` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -646,8 +639,8 @@ Check if a user with the given phone number exists | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `phoneNumber`: `string`; `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `phoneNumber`: `string`; `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.phoneNumber` | `string` | | `input.userContext?` | `any` | @@ -785,11 +778,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/passwordless/index.ts:446](htt | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-passwordless-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-passwordless-types#userinput) | #### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-passwordless-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-passwordless-types#preandpostapihookaction)\> *** @@ -810,8 +803,8 @@ Resend the code to the user | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -882,34 +875,34 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/passwordless/index.ts:452](htt ### PostAPIHookContext -Re-exports [PostAPIHookContext](recipe-passwordless-types.mdx#postapihookcontext) +Re-exports [PostAPIHookContext](recipe-passwordless-types#postapihookcontext) *** ### PreAndPostAPIHookAction -Re-exports [PreAndPostAPIHookAction](recipe-passwordless-types.mdx#preandpostapihookaction) +Re-exports [PreAndPostAPIHookAction](recipe-passwordless-types#preandpostapihookaction) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-passwordless-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-passwordless-types#preapihookcontext) *** ### RecipeFunctionOptions -Re-exports [RecipeFunctionOptions](recipe-emailpassword.mdx#recipefunctionoptions) +Re-exports [RecipeFunctionOptions](recipe-emailpassword#recipefunctionoptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-passwordless-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-passwordless-types#recipeinterface) *** ### UserInput -Re-exports [UserInput](recipe-passwordless-types.mdx#userinput) +Re-exports [UserInput](recipe-passwordless-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-session-types.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-session-types.mdx index d9d1074f38..23f85c4f97 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-session-types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-session-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/session/types -page_title: Session Types -sidebar_position: 8 description: References documentation for the supertokens-web-js/recipe/session/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 8 --- -# Session Types - - ## Type Aliases ### InputType @@ -26,7 +19,7 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/session/types.ts:50](https://g | Name | Type | Defined in | | ------ | ------ | ------ | -| `appInfo` | [`NormalisedAppInfo`](types.mdx#normalisedappinfo) | [tmp/supertokens-web-js/lib/ts/recipe/session/types.ts:52](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/session/types.ts#L52) | +| `appInfo` | [`NormalisedAppInfo`](types#normalisedappinfo) | [tmp/supertokens-web-js/lib/ts/recipe/session/types.ts:52](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/session/types.ts#L52) | | `enableDebugLogs` | `boolean` | [tmp/supertokens-web-js/lib/ts/recipe/session/types.ts:53](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/session/types.ts#L53) | | `recipeId` | `string` | [tmp/supertokens-web-js/lib/ts/recipe/session/types.ts:51](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/session/types.ts#L51) | diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-session.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-session.mdx index 22efdbaa5b..03de680b51 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-session.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-session.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/session -page_title: Session -sidebar_position: 8 description: References documentation for the supertokens-web-js/recipe/session package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 8 --- -# Session - - ## Classes ### BooleanClaim @@ -24,7 +17,7 @@ Defined in: node\_modules/supertokens-website/lib/build/claims/booleanClaim.d.ts #### Extended by -- [`EmailVerificationClaimClass`](recipe-emailverification.mdx#emailverificationclaimclass) +- [`EmailVerificationClaimClass`](recipe-emailverification#emailverificationclaimclass) #### Constructors @@ -294,11 +287,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/session/index.ts:23](https://g | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-session-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-session-types#userinput) | ###### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<`unknown`\> +[`CreateRecipeFunction`](types#createrecipefunction)\<`unknown`\> ##### signOut() @@ -1037,11 +1030,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/session/index.ts:101](https:// | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-session-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-session-types#userinput) | #### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<`unknown`\> +[`CreateRecipeFunction`](types#createrecipefunction)\<`unknown`\> *** @@ -1093,4 +1086,4 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/session/index.ts:112](https:// ### UserInput -Re-exports [UserInput](recipe-session-types.mdx#userinput) +Re-exports [UserInput](recipe-session-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty-types.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty-types.mdx index c2ff245ade..0d010a9d01 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty-types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/thirdparty/types -page_title: ThirdParty Types -sidebar_position: 9 description: References documentation for the supertokens-web-js/recipe/thirdparty/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 9 --- -# ThirdParty Types - - ## Type Aliases ### InputType @@ -90,7 +83,7 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/thirdparty/types.ts:66](https: | `getAuthStateFromURL` | (`input`) => `string` | Returns the auth state from the current URL | [tmp/supertokens-web-js/lib/ts/recipe/thirdparty/types.ts:226](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/thirdparty/types.ts#L226) | | `getStateAndOtherInfoFromStorage` | \<`CustomStateProperties`\>(`input`) => [`StateObject`](#stateobject) & `CustomStateProperties` \| `undefined` | Get the current login state from storage, this is also used when calling signInUp | [tmp/supertokens-web-js/lib/ts/recipe/thirdparty/types.ts:74](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/thirdparty/types.ts#L74) | | `setStateAndOtherInfoToStorage` | \<`CustomStateProperties`\>(`input`) => `Promise`\<`void`\> | Set the login state to storage | [tmp/supertokens-web-js/lib/ts/recipe/thirdparty/types.ts:85](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/thirdparty/types.ts#L85) | -| `signInAndUp` | (`input`) => `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; `tenantId?`: `string`; `user`: [`User`](types.mdx#user); \} \| \{ `fetchResponse`: `Response`; `status`: `"NO_EMAIL_GIVEN_BY_PROVIDER"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \}\> | Sign up/Sign in the user, this method uses the login attempt information from storage **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/thirdparty/types.ts:165](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/thirdparty/types.ts#L165) | +| `signInAndUp` | (`input`) => `Promise`\< \| \{ `createdNewRecipeUser`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; `tenantId?`: `string`; `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; `status`: `"NO_EMAIL_GIVEN_BY_PROVIDER"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_UP_NOT_ALLOWED"`; \}\> | Sign up/Sign in the user, this method uses the login attempt information from storage **Throws** STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"` | [tmp/supertokens-web-js/lib/ts/recipe/thirdparty/types.ts:165](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/thirdparty/types.ts#L165) | | `verifyAndGetStateOrThrowError` | \<`CustomStateProperties`\>(`input`) => `Promise`\<[`StateObject`](#stateobject) & `CustomStateProperties`\> | Verify that the state recieved from the third party provider matches the one in storage | [tmp/supertokens-web-js/lib/ts/recipe/thirdparty/types.ts:204](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/thirdparty/types.ts#L204) | *** diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty.mdx index 0795f70ab9..382ed8901e 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/thirdparty -page_title: ThirdParty -sidebar_position: 9 description: References documentation for the supertokens-web-js/recipe/thirdparty package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 9 --- -# ThirdParty - - ## Classes ### default @@ -46,9 +39,9 @@ Get the URL that should be opened for third party authentication | Parameter | Type | | ------ | ------ | -| `input` | \{ `frontendRedirectURI`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `redirectURIOnProviderDashboard?`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: `any`; \} | +| `input` | \{ `frontendRedirectURI`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `redirectURIOnProviderDashboard?`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: `any`; \} | | `input.frontendRedirectURI` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.redirectURIOnProviderDashboard?` | `string` | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.thirdPartyId` | `string` | @@ -89,7 +82,7 @@ Get the current login state from storage, this is also used when calling signInU ###### Returns -[`StateObject`](recipe-thirdparty-types.mdx#stateobject) & `CustomStateProperties` +[`StateObject`](recipe-thirdparty-types#stateobject) & `CustomStateProperties` State object from storage @@ -105,11 +98,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/thirdparty/index.ts:31](https: | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-thirdparty-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-thirdparty-types#userinput) | ###### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-thirdparty-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-thirdparty-types#preandpostapihookaction)\> ##### signInAndUp() @@ -140,8 +133,8 @@ Sign up/Sign in the user, this method uses the login attempt information from st | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -151,7 +144,7 @@ Sign up/Sign in the user, this method uses the login attempt information from st `createdNewRecipeUser`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -204,9 +197,9 @@ Get the URL that should be opened for third party authentication | Parameter | Type | | ------ | ------ | -| `input` | \{ `frontendRedirectURI`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `redirectURIOnProviderDashboard?`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: `any`; \} | +| `input` | \{ `frontendRedirectURI`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `redirectURIOnProviderDashboard?`: `string`; `shouldTryLinkingWithSessionUser?`: `boolean`; `thirdPartyId`: `string`; `userContext?`: `any`; \} | | `input.frontendRedirectURI` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.redirectURIOnProviderDashboard?` | `string` | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.thirdPartyId` | `string` | @@ -249,7 +242,7 @@ Get the current login state from storage, this is also used when calling signInU #### Returns -[`StateObject`](recipe-thirdparty-types.mdx#stateobject) & `CustomStateProperties` +[`StateObject`](recipe-thirdparty-types#stateobject) & `CustomStateProperties` State object from storage @@ -267,11 +260,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/thirdparty/index.ts:133](https | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-thirdparty-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-thirdparty-types#userinput) | #### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-thirdparty-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-thirdparty-types#preandpostapihookaction)\> *** @@ -304,8 +297,8 @@ Sign up/Sign in the user, this method uses the login attempt information from st | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -315,7 +308,7 @@ Sign up/Sign in the user, this method uses the login attempt information from st `createdNewRecipeUser`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -358,40 +351,40 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/thirdparty/index.ts:137](https ### PostAPIHookContext -Re-exports [PostAPIHookContext](recipe-thirdparty-types.mdx#postapihookcontext) +Re-exports [PostAPIHookContext](recipe-thirdparty-types#postapihookcontext) *** ### PreAndPostAPIHookAction -Re-exports [PreAndPostAPIHookAction](recipe-thirdparty-types.mdx#preandpostapihookaction) +Re-exports [PreAndPostAPIHookAction](recipe-thirdparty-types#preandpostapihookaction) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-thirdparty-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-thirdparty-types#preapihookcontext) *** ### RecipeFunctionOptions -Re-exports [RecipeFunctionOptions](recipe-emailpassword.mdx#recipefunctionoptions) +Re-exports [RecipeFunctionOptions](recipe-emailpassword#recipefunctionoptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-thirdparty-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-thirdparty-types#recipeinterface) *** ### StateObject -Re-exports [StateObject](recipe-thirdparty-types.mdx#stateobject) +Re-exports [StateObject](recipe-thirdparty-types#stateobject) *** ### UserInput -Re-exports [UserInput](recipe-thirdparty-types.mdx#userinput) +Re-exports [UserInput](recipe-thirdparty-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-totp-types.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-totp-types.mdx index 068af241da..be70e4b270 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-totp-types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-totp-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/totp/types -page_title: TOTP Types -sidebar_position: 10 description: References documentation for the supertokens-web-js/recipe/totp/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 10 --- -# TOTP Types - - ## Type Aliases ### DeviceInfo diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-totp.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-totp.mdx index 1ef2389e8a..0b6b48dd3f 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-totp.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-totp.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/totp -page_title: TOTP -sidebar_position: 10 description: References documentation for the supertokens-web-js/recipe/totp package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 10 --- -# TOTP - - ## Classes ### default @@ -57,9 +50,9 @@ Creates a new unverified device. | Parameter | Type | | ------ | ------ | -| `input?` | \{ `deviceName?`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input?` | \{ `deviceName?`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.deviceName?` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -91,11 +84,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/totp/index.ts:29](https://gith | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-totp-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-totp-types#userinput) | ###### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-totp-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-totp-types#preandpostapihookaction)\> ##### listDevices() @@ -115,8 +108,8 @@ Lists all TOTP devices of the current user | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -147,9 +140,9 @@ Removes a TOTP device | Parameter | Type | | ------ | ------ | -| `input` | \{ `deviceName`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input` | \{ `deviceName`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.deviceName` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | ###### Returns @@ -191,8 +184,8 @@ Verifies that the totp code belongs to a verified device of the current user | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `totp`: `string`; `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `totp`: `string`; `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.totp` | `string` | | `input.userContext?` | `any` | @@ -251,9 +244,9 @@ Verifies the totp device for the current user | Parameter | Type | | ------ | ------ | -| `input` | \{ `deviceName`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `totp`: `string`; `userContext?`: `any`; \} | +| `input` | \{ `deviceName`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `totp`: `string`; `userContext?`: `any`; \} | | `input.deviceName` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.totp` | `string` | | `input.userContext?` | `any` | @@ -310,9 +303,9 @@ Creates a new unverified device. | Parameter | Type | | ------ | ------ | -| `input?` | \{ `deviceName?`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input?` | \{ `deviceName?`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.deviceName?` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -346,11 +339,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/totp/index.ts:165](https://git | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-totp-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-totp-types#userinput) | #### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-totp-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-totp-types#preandpostapihookaction)\> *** @@ -372,8 +365,8 @@ Lists all TOTP devices of the current user | Parameter | Type | | ------ | ------ | -| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input?` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -406,9 +399,9 @@ Removes a TOTP device | Parameter | Type | | ------ | ------ | -| `input` | \{ `deviceName`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext?`: `any`; \} | +| `input` | \{ `deviceName`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext?`: `any`; \} | | `input.deviceName` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext?` | `any` | #### Returns @@ -452,8 +445,8 @@ Verifies that the totp code belongs to a verified device of the current user | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `totp`: `string`; `userContext?`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `totp`: `string`; `userContext?`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.totp` | `string` | | `input.userContext?` | `any` | @@ -514,9 +507,9 @@ Verifies the totp device for the current user | Parameter | Type | | ------ | ------ | -| `input` | \{ `deviceName`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `totp`: `string`; `userContext?`: `any`; \} | +| `input` | \{ `deviceName`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `totp`: `string`; `userContext?`: `any`; \} | | `input.deviceName` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.totp` | `string` | | `input.userContext?` | `any` | @@ -550,40 +543,40 @@ Verifies the totp device for the current user ### DeviceInfo -Re-exports [DeviceInfo](recipe-totp-types.mdx#deviceinfo) +Re-exports [DeviceInfo](recipe-totp-types#deviceinfo) *** ### PostAPIHookContext -Re-exports [PostAPIHookContext](recipe-totp-types.mdx#postapihookcontext) +Re-exports [PostAPIHookContext](recipe-totp-types#postapihookcontext) *** ### PreAndPostAPIHookAction -Re-exports [PreAndPostAPIHookAction](recipe-totp-types.mdx#preandpostapihookaction) +Re-exports [PreAndPostAPIHookAction](recipe-totp-types#preandpostapihookaction) *** ### PreAPIHookContext -Re-exports [PreAPIHookContext](recipe-totp-types.mdx#preapihookcontext) +Re-exports [PreAPIHookContext](recipe-totp-types#preapihookcontext) *** ### RecipeFunctionOptions -Re-exports [RecipeFunctionOptions](recipe-emailpassword.mdx#recipefunctionoptions) +Re-exports [RecipeFunctionOptions](recipe-emailpassword#recipefunctionoptions) *** ### RecipeInterface -Re-exports [RecipeInterface](recipe-totp-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-totp-types#recipeinterface) *** ### UserInput -Re-exports [UserInput](recipe-totp-types.mdx#userinput) +Re-exports [UserInput](recipe-totp-types#userinput) diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-userroles.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-userroles.mdx index fb31bf96d4..ef77dd58a1 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-userroles.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-userroles.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/userroles -page_title: UserRoles -sidebar_position: 11 description: References documentation for the supertokens-web-js/recipe/userroles package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 11 --- -# UserRoles - - ## Classes ### default @@ -34,8 +27,8 @@ new default(): default; | Property | Modifier | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | ------ | -| `PermissionClaim` | `static` | [`PrimitiveArrayClaim`](recipe-session.mdx#primitivearrayclaim)\<`string`\> | `PermissionClaim` | [tmp/supertokens-web-js/lib/ts/recipe/userroles/index.ts:20](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/userroles/index.ts#L20) | -| `UserRoleClaim` | `static` | [`PrimitiveArrayClaim`](recipe-session.mdx#primitivearrayclaim)\<`string`\> | `UserRoleClaim` | [tmp/supertokens-web-js/lib/ts/recipe/userroles/index.ts:19](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/userroles/index.ts#L19) | +| `PermissionClaim` | `static` | [`PrimitiveArrayClaim`](recipe-session#primitivearrayclaim)\<`string`\> | `PermissionClaim` | [tmp/supertokens-web-js/lib/ts/recipe/userroles/index.ts:20](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/userroles/index.ts#L20) | +| `UserRoleClaim` | `static` | [`PrimitiveArrayClaim`](recipe-session#primitivearrayclaim)\<`string`\> | `UserRoleClaim` | [tmp/supertokens-web-js/lib/ts/recipe/userroles/index.ts:19](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/userroles/index.ts#L19) | ## Variables diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn-types.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn-types.mdx index db44f5ffc3..c0da7d9023 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn-types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn-types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/webauthn/types -page_title: WebAuthn Types -sidebar_position: 12 description: References documentation for the supertokens-web-js/recipe/webauthn/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 12 --- -# WebAuthn Types - - ## Type Aliases ### AuthenticationOptions @@ -140,22 +133,22 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:125](https:/ | Property | Type | Defined in | | ------ | ------ | ------ | | `authenticateCredential` | (`input`) => `Promise`\< \| \{ `authenticationResponse`: `AuthenticationResponseJSON`; `status`: `"OK"`; \} \| \{ `error`: `any`; `status`: `"FAILED_TO_AUTHENTICATE_USER"`; \} \| \{ `error`: `any`; `status`: `"WEBAUTHN_NOT_SUPPORTED"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:251](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L251) | -| `authenticateCredentialWithSignIn` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_NOT_ALLOWED"`; \} \| \{ `error`: `any`; `status`: `"FAILED_TO_AUTHENTICATE_USER"`; \} \| \{ `error`: `any`; `status`: `"WEBAUTHN_NOT_SUPPORTED"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:293](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L293) | -| `createAndRegisterCredentialForSessionUser` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| \{ `reason?`: `string`; `status`: `"REGISTER_CREDENTIAL_NOT_ALLOWED"`; \} \| \{ `err`: `string`; `status`: `"INVALID_EMAIL_ERROR"`; \} \| \{ `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `reason?`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \} \| \{ `status`: `"AUTHENTICATOR_ALREADY_REGISTERED"`; \} \| \{ `error`: `any`; `status`: `"FAILED_TO_REGISTER_USER"`; \} \| \{ `error`: `any`; `status`: `"WEBAUTHN_NOT_SUPPORTED"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:338](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L338) | +| `authenticateCredentialWithSignIn` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_NOT_ALLOWED"`; \} \| \{ `error`: `any`; `status`: `"FAILED_TO_AUTHENTICATE_USER"`; \} \| \{ `error`: `any`; `status`: `"WEBAUTHN_NOT_SUPPORTED"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:293](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L293) | +| `createAndRegisterCredentialForSessionUser` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `reason?`: `string`; `status`: `"REGISTER_CREDENTIAL_NOT_ALLOWED"`; \} \| \{ `err`: `string`; `status`: `"INVALID_EMAIL_ERROR"`; \} \| \{ `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `reason?`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \} \| \{ `status`: `"AUTHENTICATOR_ALREADY_REGISTERED"`; \} \| \{ `error`: `any`; `status`: `"FAILED_TO_REGISTER_USER"`; \} \| \{ `error`: `any`; `status`: `"WEBAUTHN_NOT_SUPPORTED"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:338](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L338) | | `createCredential` | (`input`) => `Promise`\< \| \{ `registrationResponse`: `RegistrationResponseJSON`; `status`: `"OK"`; \} \| \{ `status`: `"AUTHENTICATOR_ALREADY_REGISTERED"`; \} \| \{ `error`: `any`; `status`: `"FAILED_TO_REGISTER_USER"`; \} \| \{ `error`: `any`; `status`: `"WEBAUTHN_NOT_SUPPORTED"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:239](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L239) | | `doesBrowserSupportWebAuthn` | (`input`) => `Promise`\< \| \{ `browserSupportsWebauthn`: `boolean`; `platformAuthenticatorIsAvailable`: `boolean`; `status`: `"OK"`; \} \| \{ `error`: `any`; `status`: `"ERROR"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:406](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L406) | -| `generateRecoverAccountToken` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"RECOVER_ACCOUNT_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:207](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L207) | -| `getEmailExists` | (`input`) => `Promise`\< \| \{ `exists`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:199](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L199) | +| `generateRecoverAccountToken` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"RECOVER_ACCOUNT_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:207](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L207) | +| `getEmailExists` | (`input`) => `Promise`\< \| \{ `exists`: `boolean`; `fetchResponse`: `Response`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:199](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L199) | | `getRegisterOptions` | (`input`) => `Promise`\< \| [`RegistrationOptions`](#registrationoptions) \| \{ `fetchResponse`: `Response`; `status`: `"RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"`; \} \| \{ `err`: `string`; `fetchResponse`: `Response`; `status`: `"INVALID_EMAIL_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:126](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L126) | -| `getSignInOptions` | (`input`) => `Promise`\< \| [`AuthenticationOptions`](#authenticationoptions) \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:147](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L147) | -| `listCredentials` | (`input`) => `Promise`\< \| \{ `credentials`: `object`[]; `fetchResponse`: `Response`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:359](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L359) | -| `recoverAccount` | (`input`) => `Promise`\< \| \{ `email`: `string`; `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:219](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L219) | -| `registerCredential` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `reason?`: `string`; `status`: `"REGISTER_CREDENTIAL_NOT_ALLOWED"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason?`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:384](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L384) | -| `registerCredentialWithRecoverAccount` | (`input`) => `Promise`\< \| \{ `email`: `string`; `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `fetchResponse`: `Response`; `status`: `"RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \} \| \{ `status`: `"AUTHENTICATOR_ALREADY_REGISTERED"`; \} \| \{ `error`: `any`; `status`: `"FAILED_TO_REGISTER_USER"`; \} \| \{ `error`: `any`; `status`: `"WEBAUTHN_NOT_SUPPORTED"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:310](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L310) | -| `registerCredentialWithSignUp` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `err`: `string`; `fetchResponse`: `Response`; `status`: `"INVALID_EMAIL_ERROR"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_UP_NOT_ALLOWED"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; \} \| \{ `status`: `"AUTHENTICATOR_ALREADY_REGISTERED"`; \} \| \{ `error`: `any`; `status`: `"FAILED_TO_REGISTER_USER"`; \} \| \{ `error`: `any`; `status`: `"WEBAUTHN_NOT_SUPPORTED"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:262](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L262) | -| `removeCredential` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"CREDENTIAL_NOT_FOUND_ERROR"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:372](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L372) | -| `signIn` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:179](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L179) | -| `signUp` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types.mdx#user); \} \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_UP_NOT_ALLOWED"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:155](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L155) | +| `getSignInOptions` | (`input`) => `Promise`\< \| [`AuthenticationOptions`](#authenticationoptions) \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:147](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L147) | +| `listCredentials` | (`input`) => `Promise`\< \| \{ `credentials`: `object`[]; `fetchResponse`: `Response`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:359](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L359) | +| `recoverAccount` | (`input`) => `Promise`\< \| \{ `email`: `string`; `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:219](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L219) | +| `registerCredential` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `reason?`: `string`; `status`: `"REGISTER_CREDENTIAL_NOT_ALLOWED"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason?`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:384](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L384) | +| `registerCredentialWithRecoverAccount` | (`input`) => `Promise`\< \| \{ `email`: `string`; `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; `status`: `"RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \} \| \{ `status`: `"AUTHENTICATOR_ALREADY_REGISTERED"`; \} \| \{ `error`: `any`; `status`: `"FAILED_TO_REGISTER_USER"`; \} \| \{ `error`: `any`; `status`: `"WEBAUTHN_NOT_SUPPORTED"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:310](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L310) | +| `registerCredentialWithSignUp` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `err`: `string`; `fetchResponse`: `Response`; `status`: `"INVALID_EMAIL_ERROR"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_UP_NOT_ALLOWED"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; \} \| \{ `status`: `"AUTHENTICATOR_ALREADY_REGISTERED"`; \} \| \{ `error`: `any`; `status`: `"FAILED_TO_REGISTER_USER"`; \} \| \{ `error`: `any`; `status`: `"WEBAUTHN_NOT_SUPPORTED"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:262](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L262) | +| `removeCredential` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"CREDENTIAL_NOT_FOUND_ERROR"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:372](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L372) | +| `signIn` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_IN_NOT_ALLOWED"`; \} \| [`GeneralErrorResponse`](types#generalerrorresponse)\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:179](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L179) | +| `signUp` | (`input`) => `Promise`\< \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; `user`: [`User`](types#user); \} \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"SIGN_UP_NOT_ALLOWED"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_CREDENTIALS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"OPTIONS_NOT_FOUND_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"INVALID_OPTIONS_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `reason`: `string`; `status`: `"INVALID_AUTHENTICATOR_ERROR"`; \} \| \{ `fetchResponse`: `Response`; `status`: `"EMAIL_ALREADY_EXISTS_ERROR"`; \}\> | [tmp/supertokens-web-js/lib/ts/recipe/webauthn/types.ts:155](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/recipe/webauthn/types.ts#L155) | *** diff --git a/docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn.mdx b/docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn.mdx index 5257879904..6757e1bc50 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/recipe/webauthn -page_title: WebAuthn -sidebar_position: 12 description: References documentation for the supertokens-web-js/recipe/webauthn package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 12 --- -# WebAuthn - - ## Classes ### default @@ -60,8 +53,8 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `authenticationOptions`: `Omit`\<[`AuthenticationOptions`](recipe-webauthn-types.mdx#authenticationoptions), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | -| `input.authenticationOptions` | `Omit`\<[`AuthenticationOptions`](recipe-webauthn-types.mdx#authenticationoptions), `"fetchResponse"` \| `"status"`\> | +| `input` | \{ `authenticationOptions`: `Omit`\<[`AuthenticationOptions`](recipe-webauthn-types#authenticationoptions), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | +| `input.authenticationOptions` | `Omit`\<[`AuthenticationOptions`](recipe-webauthn-types#authenticationoptions), `"fetchResponse"` \| `"status"`\> | | `input.userContext` | `any` | ###### Returns @@ -125,19 +118,19 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.userContext` | `any` | ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -216,16 +209,16 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `recipeUserId`: `string`; `userContext`: `any`; \} | +| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `recipeUserId`: `string`; `userContext`: `any`; \} | | `input.email` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.recipeUserId` | `string` | | `input.userContext` | `any` | ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; @@ -296,8 +289,8 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `registrationOptions`: `Omit`\<[`RegistrationOptions`](recipe-webauthn-types.mdx#registrationoptions), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | -| `input.registrationOptions` | `Omit`\<[`RegistrationOptions`](recipe-webauthn-types.mdx#registrationoptions), `"fetchResponse"` \| `"status"`\> | +| `input` | \{ `registrationOptions`: `Omit`\<[`RegistrationOptions`](recipe-webauthn-types#registrationoptions), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | +| `input.registrationOptions` | `Omit`\<[`RegistrationOptions`](recipe-webauthn-types#registrationoptions), `"fetchResponse"` \| `"status"`\> | | `input.userContext` | `any` | ###### Returns @@ -382,15 +375,15 @@ Generate and send a recover account token. | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext`: `any`; \} | +| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext`: `any`; \} | | `input.email` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext` | `any` | ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; @@ -423,15 +416,15 @@ Checks whether there is an webauthn user with the passed email. | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext`: `any`; \} | +| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext`: `any`; \} | | `input.email` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext` | `any` | ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `exists`: `boolean`; `fetchResponse`: `Response`; @@ -503,8 +496,8 @@ challenge to be fulfilled in order for successful addition of the identity. `attestation`: `"none"` \| `"indirect"` \| `"direct"` \| `"enterprise"`; `authenticatorSelection`: \{ `requireResidentKey`: `boolean`; - `residentKey`: [`ResidentKey`](recipe-webauthn-types.mdx#residentkey); - `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification-1); + `residentKey`: [`ResidentKey`](recipe-webauthn-types#residentkey); + `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification-1); \}; `challenge`: `string`; `createdAt`: `string`; @@ -569,20 +562,20 @@ is correct. | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext` | `any` | ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `challenge`: `string`; `fetchResponse`: `Response`; `status`: `"OK"`; `timeout`: `number`; - `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification-1); + `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification-1); `webauthnGeneratedOptionsId`: `string`; \} \| \{ @@ -604,11 +597,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/webauthn/index.ts:31](https:// | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-webauthn-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-webauthn-types#userinput) | ###### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-webauthn-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-webauthn-types#preandpostapihookaction)\> ##### listCredentials() @@ -629,14 +622,14 @@ List the credentials for the user | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext` | `any` | ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `credentials`: `object`[]; `status`: `"OK"`; @@ -686,9 +679,9 @@ Recover the account using the token received in email. | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `token`: `string`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `token`: `string`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | `RegistrationResponseJSON` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.token` | `string` | | `input.userContext` | `any` | | `input.webauthnGeneratedOptionsId` | `string` | @@ -696,12 +689,12 @@ Recover the account using the token received in email. ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `email`: `string`; `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -764,9 +757,9 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `recipeUserId`: `string`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `recipeUserId`: `string`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | `RegistrationResponseJSON` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.recipeUserId` | `string` | | `input.userContext` | `any` | | `input.webauthnGeneratedOptionsId` | `string` | @@ -774,7 +767,7 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `status`: `"OK"`; \} @@ -861,20 +854,20 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `recoverAccountToken`: `string`; `userContext`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `recoverAccountToken`: `string`; `userContext`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.recoverAccountToken` | `string` | | `input.userContext` | `any` | ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `email`: `string`; `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -987,20 +980,20 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; \} | +| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; \} | | `input.email` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.userContext` | `any` | ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `err`: `string`; @@ -1073,15 +1066,15 @@ Remove the credential for the passed credential ID | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext`: `any`; `webauthnCredentialId`: `string`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext`: `any`; `webauthnCredentialId`: `string`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext` | `any` | | `input.webauthnCredentialId` | `string` | ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `status`: `"OK"`; \} @@ -1121,9 +1114,9 @@ Sign in with the credential and the generated options ID. | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: `AuthenticationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: `AuthenticationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | `AuthenticationResponseJSON` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.userContext` | `any` | | `input.webauthnGeneratedOptionsId` | `string` | @@ -1131,11 +1124,11 @@ Sign in with the credential and the generated options ID. ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -1196,9 +1189,9 @@ device. | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | `RegistrationResponseJSON` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.userContext` | `any` | | `input.webauthnGeneratedOptionsId` | `string` | @@ -1206,11 +1199,11 @@ device. ###### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -1271,8 +1264,8 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `authenticationOptions`: `Omit`\<[`AuthenticationOptions`](recipe-webauthn-types.mdx#authenticationoptions), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | -| `input.authenticationOptions` | `Omit`\<[`AuthenticationOptions`](recipe-webauthn-types.mdx#authenticationoptions), `"fetchResponse"` \| `"status"`\> | +| `input` | \{ `authenticationOptions`: `Omit`\<[`AuthenticationOptions`](recipe-webauthn-types#authenticationoptions), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | +| `input.authenticationOptions` | `Omit`\<[`AuthenticationOptions`](recipe-webauthn-types#authenticationoptions), `"fetchResponse"` \| `"status"`\> | | `input.userContext` | `any` | #### Returns @@ -1338,19 +1331,19 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.userContext` | `any` | #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -1431,16 +1424,16 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `recipeUserId`: `string`; `userContext`: `any`; \} | +| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `recipeUserId`: `string`; `userContext`: `any`; \} | | `input.email` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.recipeUserId` | `string` | | `input.userContext` | `any` | #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; @@ -1513,8 +1506,8 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `registrationOptions`: `Omit`\<[`RegistrationOptions`](recipe-webauthn-types.mdx#registrationoptions), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | -| `input.registrationOptions` | `Omit`\<[`RegistrationOptions`](recipe-webauthn-types.mdx#registrationoptions), `"fetchResponse"` \| `"status"`\> | +| `input` | \{ `registrationOptions`: `Omit`\<[`RegistrationOptions`](recipe-webauthn-types#registrationoptions), `"fetchResponse"` \| `"status"`\>; `userContext`: `any`; \} | +| `input.registrationOptions` | `Omit`\<[`RegistrationOptions`](recipe-webauthn-types#registrationoptions), `"fetchResponse"` \| `"status"`\> | | `input.userContext` | `any` | #### Returns @@ -1603,15 +1596,15 @@ Generate and send a recover account token. | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext`: `any`; \} | +| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext`: `any`; \} | | `input.email` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext` | `any` | #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; @@ -1646,15 +1639,15 @@ Checks whether there is an webauthn user with the passed email. | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext`: `any`; \} | +| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext`: `any`; \} | | `input.email` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext` | `any` | #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `exists`: `boolean`; `fetchResponse`: `Response`; @@ -1728,8 +1721,8 @@ challenge to be fulfilled in order for successful addition of the identity. `attestation`: `"none"` \| `"indirect"` \| `"direct"` \| `"enterprise"`; `authenticatorSelection`: \{ `requireResidentKey`: `boolean`; - `residentKey`: [`ResidentKey`](recipe-webauthn-types.mdx#residentkey); - `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification-1); + `residentKey`: [`ResidentKey`](recipe-webauthn-types#residentkey); + `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification-1); \}; `challenge`: `string`; `createdAt`: `string`; @@ -1796,20 +1789,20 @@ is correct. | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext` | `any` | #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `challenge`: `string`; `fetchResponse`: `Response`; `status`: `"OK"`; `timeout`: `number`; - `userVerification`: [`UserVerification`](recipe-webauthn-types.mdx#userverification-1); + `userVerification`: [`UserVerification`](recipe-webauthn-types#userverification-1); `webauthnGeneratedOptionsId`: `string`; \} \| \{ @@ -1833,11 +1826,11 @@ Defined in: [tmp/supertokens-web-js/lib/ts/recipe/webauthn/index.ts:648](https:/ | Parameter | Type | | ------ | ------ | -| `config?` | [`UserInput`](recipe-webauthn-types.mdx#userinput) | +| `config?` | [`UserInput`](recipe-webauthn-types#userinput) | #### Returns -[`CreateRecipeFunction`](types.mdx#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-webauthn-types.mdx#preandpostapihookaction)\> +[`CreateRecipeFunction`](types#createrecipefunction)\<[`PreAndPostAPIHookAction`](recipe-webauthn-types#preandpostapihookaction)\> *** @@ -1860,14 +1853,14 @@ List the credentials for the user | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext` | `any` | #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `credentials`: `object`[]; `status`: `"OK"`; @@ -1919,9 +1912,9 @@ Recover the account using the token received in email. | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `token`: `string`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `token`: `string`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | `RegistrationResponseJSON` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.token` | `string` | | `input.userContext` | `any` | | `input.webauthnGeneratedOptionsId` | `string` | @@ -1929,12 +1922,12 @@ Recover the account using the token received in email. #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `email`: `string`; `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -1999,9 +1992,9 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `recipeUserId`: `string`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `recipeUserId`: `string`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | `RegistrationResponseJSON` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.recipeUserId` | `string` | | `input.userContext` | `any` | | `input.webauthnGeneratedOptionsId` | `string` | @@ -2009,7 +2002,7 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `status`: `"OK"`; \} @@ -2098,20 +2091,20 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `recoverAccountToken`: `string`; `userContext`: `any`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `recoverAccountToken`: `string`; `userContext`: `any`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.recoverAccountToken` | `string` | | `input.userContext` | `any` | #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `email`: `string`; `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -2226,20 +2219,20 @@ It uses `@simplewebauthn/browser` to make the webauthn calls. | Parameter | Type | | ------ | ------ | -| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; \} | +| `input` | \{ `email`: `string`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; \} | | `input.email` | `string` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.userContext` | `any` | #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `err`: `string`; @@ -2314,15 +2307,15 @@ Remove the credential for the passed credential ID | Parameter | Type | | ------ | ------ | -| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `userContext`: `any`; `webauthnCredentialId`: `string`; \} | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input` | \{ `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `userContext`: `any`; `webauthnCredentialId`: `string`; \} | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.userContext` | `any` | | `input.webauthnCredentialId` | `string` | #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `status`: `"OK"`; \} @@ -2364,9 +2357,9 @@ Sign in with the credential and the generated options ID. | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: `AuthenticationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: `AuthenticationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | `AuthenticationResponseJSON` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.userContext` | `any` | | `input.webauthnGeneratedOptionsId` | `string` | @@ -2374,11 +2367,11 @@ Sign in with the credential and the generated options ID. #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -2441,9 +2434,9 @@ device. | Parameter | Type | | ------ | ------ | -| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | +| `input` | \{ `credential`: `RegistrationResponseJSON`; `options?`: [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions); `shouldTryLinkingWithSessionUser?`: `boolean`; `userContext`: `any`; `webauthnGeneratedOptionsId`: `string`; \} | | `input.credential` | `RegistrationResponseJSON` | -| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword.mdx#recipefunctionoptions) | +| `input.options?` | [`RecipeFunctionOptions`](recipe-emailpassword#recipefunctionoptions) | | `input.shouldTryLinkingWithSessionUser?` | `boolean` | | `input.userContext` | `any` | | `input.webauthnGeneratedOptionsId` | `string` | @@ -2451,11 +2444,11 @@ device. #### Returns `Promise`\< - \| [`GeneralErrorResponse`](types.mdx#generalerrorresponse) + \| [`GeneralErrorResponse`](types#generalerrorresponse) \| \{ `fetchResponse`: `Response`; `status`: `"OK"`; - `user`: [`User`](types.mdx#user); + `user`: [`User`](types#user); \} \| \{ `fetchResponse`: `Response`; @@ -2490,4 +2483,4 @@ device. ### RecipeInterface -Re-exports [RecipeInterface](recipe-webauthn-types.mdx#recipeinterface) +Re-exports [RecipeInterface](recipe-webauthn-types#recipeinterface) diff --git a/docs/references/frontend-sdks/supertokens-web-js/types.mdx b/docs/references/frontend-sdks/supertokens-web-js/types.mdx index 8e11445e49..26dffd8eb9 100644 --- a/docs/references/frontend-sdks/supertokens-web-js/types.mdx +++ b/docs/references/frontend-sdks/supertokens-web-js/types.mdx @@ -1,17 +1,10 @@ --- title: supertokens-web-js/types -page_title: SuperTokens Web JS Types -sidebar_position: 1 description: References documentation for the supertokens-web-js/types package -hide_title: true -page_type: sdk-reference -package_name: supertokens-node -category: references +sidebar: + order: 1 --- -# SuperTokens Web JS Types - - ## Type Aliases ### AllRecipeConfigs @@ -26,16 +19,16 @@ Defined in: [tmp/supertokens-web-js/lib/ts/types.ts:207](https://github.com/supe | Property | Type | Defined in | | ------ | ------ | ------ | -| `emailpassword` | [`UserInput`](recipe-emailpassword-types.mdx#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:208](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L208) | -| `emailverification` | [`UserInput`](recipe-emailverification-types.mdx#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:209](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L209) | -| `multifactorauth` | [`UserInput`](recipe-multifactorauth-types.mdx#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:210](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L210) | -| `multitenancy` | [`UserInput`](recipe-multitenancy-types.mdx#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:211](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L211) | -| `oauth2provider` | [`UserInput`](recipe-oauth2provider-types.mdx#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:212](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L212) | -| `passwordless` | [`UserInput`](recipe-passwordless-types.mdx#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:213](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L213) | -| `session` | [`UserInput`](recipe-session-types.mdx#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:214](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L214) | -| `thirdparty` | [`UserInput`](recipe-thirdparty-types.mdx#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:215](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L215) | -| `totp` | [`UserInput`](recipe-totp-types.mdx#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:216](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L216) | -| `webauthn` | [`UserInput`](recipe-webauthn-types.mdx#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:217](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L217) | +| `emailpassword` | [`UserInput`](recipe-emailpassword-types#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:208](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L208) | +| `emailverification` | [`UserInput`](recipe-emailverification-types#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:209](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L209) | +| `multifactorauth` | [`UserInput`](recipe-multifactorauth-types#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:210](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L210) | +| `multitenancy` | [`UserInput`](recipe-multitenancy-types#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:211](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L211) | +| `oauth2provider` | [`UserInput`](recipe-oauth2provider-types#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:212](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L212) | +| `passwordless` | [`UserInput`](recipe-passwordless-types#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:213](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L213) | +| `session` | [`UserInput`](recipe-session-types#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:214](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L214) | +| `thirdparty` | [`UserInput`](recipe-thirdparty-types#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:215](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L215) | +| `totp` | [`UserInput`](recipe-totp-types#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:216](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L216) | +| `webauthn` | [`UserInput`](recipe-webauthn-types#userinput) | [tmp/supertokens-web-js/lib/ts/types.ts:217](https://github.com/supertokens/supertokens-web-js/blob/be2e0fd7dcade8352cdc9639abe968e5cda5b1cd/lib/ts/types.ts#L217) | *** diff --git a/docs/references/how-supertokens-works.mdx b/docs/references/how-supertokens-works.mdx index 6cf4b55be4..a1a9d8d9a7 100644 --- a/docs/references/how-supertokens-works.mdx +++ b/docs/references/how-supertokens-works.mdx @@ -1,17 +1,10 @@ --- title: How SuperTokens works -hide_title: true -sidebar_position: 2 -description: >- - Integrate SuperTokens for secure authentication using frontend and backend - SDKs with customizable recipes. -page_type: guide -category: references +description: Integrate SuperTokens for secure authentication using frontend and backend SDKs with customizable recipes. +sidebar: + order: 2 --- - -# How SuperTokens works - ## Overview A SuperTokens deployment consists of three components: @@ -23,38 +16,32 @@ It interfaces with the database and gets queried by the backend SDK for operatio This component can be self hosted by you, inside your own infrastructure. - - -Flowchart of architecture when using SuperTokens managed service - - -Flowchart of architecture when self-hosting SuperTokens - - + + +Flowchart of architecture when using SuperTokens managed service + + +Flowchart of architecture when self-hosting SuperTokens + + Your app's frontend doesn't talk to the SuperTokens core directly. Instead, it talks to the authentication APIs exposed by the backend SDK in your API layer. The SDK then talks to the SuperTokens core. -:::caution Important +:::warning[Important] If you need to call the APIs directly keep in mind the following aspects: - You should never call the SuperTokens core API from your frontend. The frontend should only communicate using the routes exposed by the backend SDK. ::: - You can follow the next video for a more detailed explanation on how each component works. - +
- +
## Examples @@ -62,13 +49,13 @@ You can follow the next video for a more detailed explanation on how each compon ### Sign in flow -:::info Important +:::info[Important] Whilst this section explains the flow for email / password login, other login methods are similar on a conceptual level - it's with a different set of APIs ::: - +
- +
## The frontend calls the backend SDK sign in API with the user credentials. @@ -83,25 +70,20 @@ Whilst this section explains the flow for email / password login, other login me The next high level diagram shows the entire communication flow between the components. - - -Flowchart of sign in flow when using SuperTokens managed service - - -Flowchart of sign in flow when self-hosting SuperTokens - - + + +Flowchart of sign in flow when using SuperTokens managed service + + +Flowchart of sign in flow when self-hosting SuperTokens + + ### Session verification flow - +
- +
After sign in, the frontend receives the access and refresh tokens. For web-based clients, the system uses [`HttpOnly` cookies](https://owasp.org/www-community/HttpOnly) by default. @@ -111,14 +93,30 @@ The access token is short lived, whilst the refresh token is long lived. #### Refresh flow -## When you make API calls, the access token is automatically attached to the request by the frontend SDK. -## The backend can use the `Verify Session` SDK function to check the validity of the session. -## If the session exists, you get a `session` object in your API. You can use it to remove user information and manipulate the session. -## If the call results in an error, the `Verify Session` function sends a `401` status code to the frontend. -## Upon receiving a `401`, the frontend calls the backend SDK refresh endpoint. -## The backend SDK then calls the SuperTokens core service to generate a new access and refresh tokens. -## The backend SDK sends the new tokens to the frontend. -## The frontend then retries the original request, with the new access token. + + + + + + + + + + + + + + + + + + + + + + + + @@ -131,10 +129,10 @@ That is because, if your application doesn't have multiple websites, all logging In fact, you don't even need OAuth 2.0 if you have multiple sub domains for your application - it can all work using session cookies. However, in case you have applications that are on different domains and need to login via a common site (for example, `foo.com` and `bar.com` both login via `auth.com`), then you require OAuth. -For that you can use the `OAuth2` recipe which allows you to implement a common authentication service for [web applications](/docs/authentication/unified-login/introduction) or [microservices](/docs/authentication/m2m/introduction). +For that you can use the `OAuth2` recipe which allows you to implement a common authentication service for [web applications](/authentication/unified-login/introduction) or [microservices](/authentication/m2m/introduction). ### What is a recipe? -Each login method is a separate recipe. If you want email password login, you should see the [email password recipe docs](/docs/authentication/email-password/introduction), for passwordless, you should see the [passwordless recipe docs](/docs/authentication/passwordless/introduction). -You can use multiple recipes at once too. Most of these guides use the [Session recipe](/docs/post-authentication/session-management/introduction) along with one of the login recipes. +Each login method is a separate recipe. If you want email password login, you should see the [email password recipe docs](/authentication/email-password/introduction), for passwordless, you should see the [passwordless recipe docs](/authentication/passwordless/introduction). +You can use multiple recipes at once too. Most of these guides use the [Session recipe](/post-authentication/session-management/introduction) along with one of the login recipes. SuperTokens divides its structure into recipes because when using a recipe, all the configurations and types are specific to that recipe's feature set. This, in turn, makes it easier for you to customize the auth logic. diff --git a/docs/references/index.mdx b/docs/references/index.mdx index 4b903541d6..b24518f836 100644 --- a/docs/references/index.mdx +++ b/docs/references/index.mdx @@ -1,64 +1,34 @@ --- -id: index title: Overview -hide_title: true -sidebar_position: 1 -hide_table_of_contents: true -description: >- - Explore SuperTokens concepts, APIs, and advanced customization options for - authentication integration. -page_type: overview +description: Explore SuperTokens concepts, APIs, and advanced customization options for authentication integration. +sidebar: + order: 1 --- - -# Overview - Discover the underlying concepts and the APIs exposed by **SuperTokens**. ## References Read through detailed information on entities that you encounter while using **SuperTokens**. - - - - Frontend SDK Reference - - - Information on how the frontend SDKs have a structure and how to use them. - - - - - Backend SDK Reference - - - Information on the structure of the backend SDKs and how to use them. - - - - - - FDI Reference - - - Details about the endpoints exposed by the **Frontend Driver Interface**. + + +Information on how the frontend SDKs have a structure and how to use them. + + +Information on the structure of the backend SDKs and how to use them. + + +Details about the endpoints exposed by the **Frontend Driver Interface**. This is the API enabled by the backend SDKs. - - - - - - CDI Reference - - - Details about the endpoints exposed by the **Core Driver Interface**. + + + +Details about the endpoints exposed by the **Core Driver Interface**. This is the API enabled by the SuperTokens Core Service. - - + - - + ## Advanced customisation @@ -66,53 +36,25 @@ Read through detailed information on entities that you encounter while using **S See how you can fine-tune your authentication flow by using specific SDK features. - - - - Frontend Hooks - - - - - - - - Frontend Function Overrides - - - - - - - - - Backend Function Overrides - - - - - - - - Backend API Overrides - - - - - - - - React Components Override - - - - - - - Pre-Built UI Theming - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/references/meta.ts b/docs/references/meta.ts new file mode 100644 index 0000000000..8bf9de6a9d --- /dev/null +++ b/docs/references/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "References", + "icon": "book-open", + "order": 1 +}); diff --git a/docs/references/plugins/_category_.json b/docs/references/plugins/_category_.json deleted file mode 100644 index b233c2d800..0000000000 --- a/docs/references/plugins/_category_.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "label": "Plugins", - "customProps": { - "isMainCategory": true - }, - "position": 2 -} diff --git a/docs/references/plugins/captcha-nodejs.mdx b/docs/references/plugins/captcha-nodejs.mdx index ed5bffa779..3e35a1e959 100644 --- a/docs/references/plugins/captcha-nodejs.mdx +++ b/docs/references/plugins/captcha-nodejs.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/captcha-nodejs' --- -# `@supertokens-plugins/captcha-nodejs` - ## Classes ### CaptchaPluginError diff --git a/docs/references/plugins/captcha-react.mdx b/docs/references/plugins/captcha-react.mdx index fb08e26079..7a8b693725 100644 --- a/docs/references/plugins/captcha-react.mdx +++ b/docs/references/plugins/captcha-react.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/captcha-react' --- -# `@supertokens-plugins/captcha-react` - ## Classes ### Captcha diff --git a/docs/references/plugins/introduction.mdx b/docs/references/plugins/introduction.mdx index ec35ec9ec1..a54c1d7148 100644 --- a/docs/references/plugins/introduction.mdx +++ b/docs/references/plugins/introduction.mdx @@ -1,13 +1,10 @@ --- -sidebar_position: 1 title: Introduction -hide_title: true description: Extend SuperTokens functionality with official plugins for enhanced authentication features. -page_type: overview +sidebar: + order: 1 --- -# Plugins - ## Overview Plugins are an extension system that allows you to include additional functionality to your **SuperTokens** authentication flows without modifying the core recipes. @@ -24,68 +21,44 @@ Support for other platforms is under active development. The official plugins repository is available [on GitHub](https://github.com/supertokens/supertokens-plugins). You can check the documentation reference pages for a high level overview of the components of each plugin. - - - - captcha-react - - - - - captcha-nodejs - - - - - user-banning-react - - - - - user-banning-nodejs - - - - - tenant-discovery-react - - - - - tenant-discovery-nodejs - - - - - opentelemetry-nodejs - - - - - profile-base-react - - - - - profile-details-nodejs - - - - - profile-details-react - - - - - progressive-profiling-nodejs - - - - - progressive-profiling-react - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## How it works @@ -95,28 +68,17 @@ Custom features get injected by overriding existing functions and components. If you want to read more on the customization points, check out the following sections: - - - - Frontend Function Overrides - - - - - React Component Overrides - - - - - - Backend Function Overrides - - - - - Backend API Overrides - - - + + + + + + + + + + + + diff --git a/docs/references/plugins/meta.ts b/docs/references/plugins/meta.ts new file mode 100644 index 0000000000..6e269976dd --- /dev/null +++ b/docs/references/plugins/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Plugins", + "icon": "plug", + "order": 2 +}); diff --git a/docs/references/plugins/opentelemetry-nodejs.mdx b/docs/references/plugins/opentelemetry-nodejs.mdx index 37da88015c..326205ffa3 100644 --- a/docs/references/plugins/opentelemetry-nodejs.mdx +++ b/docs/references/plugins/opentelemetry-nodejs.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/opentelemetry-nodejs' --- -# `@supertokens-plugins/opentelemetry-nodejs` - ## Classes ### PluginImpl @@ -39,10 +37,10 @@ Defined in: [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts | `getTracer` | (`this`: [`PluginImpl`](#pluginimpl)) => `Tracer` | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:34](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L34) | | `getTracingHeadersForCoreCall` | (`this`: [`PluginImpl`](#pluginimpl), `req`: `HttpRequest`, `userContext`: `UserContext`) => [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `string`\> | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:62](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L62) | | `startActiveSpan` | \<`T`\>(`this`: [`PluginImpl`](#pluginimpl), `tracer`: `Tracer`, `spanName`: `string`, `attributes`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>, `fn`: (`span`: `Span`) => `T`) => `T` | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:24](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L24) | -| `startSpan` | (`this`: [`PluginImpl`](#pluginimpl), `tracer`: `Tracer`, `spanName`: `string`, `attributes`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => \{ `addEvent`: (`eventName`: `string`, `attributes`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)\>) => `void`; `end`: () => `void`; `setAttributes`: (`attributes`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)\>) => `void`; `setStatus`: (`status`: `SpanStatus`) => `void`; \} | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:10](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L10) | -| `transformErrorToAttributes` | (`this`: [`PluginImpl`](#pluginimpl), `error`: `unknown`) => [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)\> | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:50](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L50) | -| `transformInputToAttributes` | (`this`: [`PluginImpl`](#pluginimpl), `input`: `unknown`) => [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)\> | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:38](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L38) | -| `transformResultToAttributes` | (`this`: [`PluginImpl`](#pluginimpl), `input`: `unknown`) => [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)\> | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:44](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L44) | +| `startSpan` | (`this`: [`PluginImpl`](#pluginimpl), `tracer`: `Tracer`, `spanName`: `string`, `attributes`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => \{ `addEvent`: (`eventName`: `string`, `attributes`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`BaseFormSection`](profile-details-nodejs#baseformsection)\>) => `void`; `end`: () => `void`; `setAttributes`: (`attributes`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`BaseFormSection`](profile-details-nodejs#baseformsection)\>) => `void`; `setStatus`: (`status`: `SpanStatus`) => `void`; \} | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:10](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L10) | +| `transformErrorToAttributes` | (`this`: [`PluginImpl`](#pluginimpl), `error`: `unknown`) => [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`BaseFormSection`](profile-details-nodejs#baseformsection)\> | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:50](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L50) | +| `transformInputToAttributes` | (`this`: [`PluginImpl`](#pluginimpl), `input`: `unknown`) => [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`BaseFormSection`](profile-details-nodejs#baseformsection)\> | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:38](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L38) | +| `transformResultToAttributes` | (`this`: [`PluginImpl`](#pluginimpl), `input`: `unknown`) => [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`BaseFormSection`](profile-details-nodejs#baseformsection)\> | [supertokens-plugins/packages/opentelemetry-nodejs/src/pluginImpl.ts:44](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/pluginImpl.ts#L44) | ## Type Aliases @@ -79,7 +77,7 @@ Defined in: [supertokens-plugins/packages/opentelemetry-nodejs/src/types.ts:5](h | `addEvent` | (`eventName`: `string`, `attributes`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => `void` | [supertokens-plugins/packages/opentelemetry-nodejs/src/types.ts:7](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/types.ts#L7) | | `end` | () => `void` | [supertokens-plugins/packages/opentelemetry-nodejs/src/types.ts:6](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/types.ts#L6) | | `setAttributes` | (`attributes`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => `void` | [supertokens-plugins/packages/opentelemetry-nodejs/src/types.ts:8](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/types.ts#L8) | -| `setStatus` | (`status`: [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)) => `void` | [supertokens-plugins/packages/opentelemetry-nodejs/src/types.ts:9](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/types.ts#L9) | +| `setStatus` | (`status`: [`BaseFormSection`](profile-details-nodejs#baseformsection)) => `void` | [supertokens-plugins/packages/opentelemetry-nodejs/src/types.ts:9](https://github.com/supertokens/supertokens-plugins/blob/main/packages/opentelemetry-nodejs/src/types.ts#L9) | *** diff --git a/docs/references/plugins/profile-base-react.mdx b/docs/references/plugins/profile-base-react.mdx index b1812eb896..e964d58f53 100644 --- a/docs/references/plugins/profile-base-react.mdx +++ b/docs/references/plugins/profile-base-react.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/profile-base-react' --- -# `@supertokens-plugins/profile-base-react` - ## Type Aliases ### RegisterSection() diff --git a/docs/references/plugins/profile-details-nodejs.mdx b/docs/references/plugins/profile-details-nodejs.mdx index 2365495d83..1e83280979 100644 --- a/docs/references/plugins/profile-details-nodejs.mdx +++ b/docs/references/plugins/profile-details-nodejs.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/profile-details-nodejs' --- -# `@supertokens-plugins/profile-details-nodejs` - ## Classes ### Implementation diff --git a/docs/references/plugins/profile-details-react.mdx b/docs/references/plugins/profile-details-react.mdx index 7d8463ecc3..a6c6bdf96a 100644 --- a/docs/references/plugins/profile-details-react.mdx +++ b/docs/references/plugins/profile-details-react.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/profile-details-react' --- -# `@supertokens-plugins/profile-details-react` - ## Type Aliases ### AccountDetails @@ -66,14 +64,14 @@ Defined in: [supertokens-plugins/packages/profile-details-react/src/types.ts:15] | Type Parameter | Default type | | ------ | ------ | -| `T` *extends* [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection) | [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection) | +| `T` *extends* [`BaseFormSection`](profile-details-nodejs#baseformsection) | [`BaseFormSection`](profile-details-nodejs#baseformsection) | #### Properties | Property | Type | Defined in | | ------ | ------ | ------ | | `className?` | `string` | [supertokens-plugins/packages/profile-details-react/src/types.ts:17](https://github.com/supertokens/supertokens-plugins/blob/main/packages/profile-details-react/src/types.ts#L17) | -| `options?` | [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)\[`"options"`\] | [supertokens-plugins/packages/profile-details-react/src/types.ts:18](https://github.com/supertokens/supertokens-plugins/blob/main/packages/profile-details-react/src/types.ts#L18) | +| `options?` | [`BaseFormSection`](profile-details-nodejs#baseformsection)\[`"options"`\] | [supertokens-plugins/packages/profile-details-react/src/types.ts:18](https://github.com/supertokens/supertokens-plugins/blob/main/packages/profile-details-react/src/types.ts#L18) | | `value` | `T` | [supertokens-plugins/packages/profile-details-react/src/types.ts:16](https://github.com/supertokens/supertokens-plugins/blob/main/packages/profile-details-react/src/types.ts#L16) | *** diff --git a/docs/references/plugins/profile-details-shared.mdx b/docs/references/plugins/profile-details-shared.mdx index 59d40f924a..3029bfe6c8 100644 --- a/docs/references/plugins/profile-details-shared.mdx +++ b/docs/references/plugins/profile-details-shared.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: profile-details-shared --- -# profile-details-shared - ## Type Aliases ### BaseField\ diff --git a/docs/references/plugins/progressive-profiling-nodejs.mdx b/docs/references/plugins/progressive-profiling-nodejs.mdx index 10ba83b631..3606c3ee87 100644 --- a/docs/references/plugins/progressive-profiling-nodejs.mdx +++ b/docs/references/plugins/progressive-profiling-nodejs.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/progressive-profiling-nodejs' --- -# `@supertokens-plugins/progressive-profiling-nodejs` - ## Classes ### Implementation @@ -115,10 +113,10 @@ Defined in: [supertokens-plugins/packages/progressive-profiling-nodejs/src/types | Parameter | Type | | ------ | ------ | -| `payload` | \{ `get`: (`session`: `SessionContainerInterface`, `userContext?`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)\>; `sections`: [`FormSection`](#formsection)[]; `set`: (`data`: [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection), `session`: `SessionContainerInterface`, `userContext?`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>; `storageHandlerId`: `string`; \} | -| `payload.get` | (`session`: `SessionContainerInterface`, `userContext?`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)\> | +| `payload` | \{ `get`: (`session`: `SessionContainerInterface`, `userContext?`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`BaseFormSection`](profile-details-nodejs#baseformsection)\>; `sections`: [`FormSection`](#formsection)[]; `set`: (`data`: [`BaseFormSection`](profile-details-nodejs#baseformsection), `session`: `SessionContainerInterface`, `userContext?`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>; `storageHandlerId`: `string`; \} | +| `payload.get` | (`session`: `SessionContainerInterface`, `userContext?`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`BaseFormSection`](profile-details-nodejs#baseformsection)\> | | `payload.sections` | [`FormSection`](#formsection)[] | -| `payload.set` | (`data`: [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection), `session`: `SessionContainerInterface`, `userContext?`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\> | +| `payload.set` | (`data`: [`BaseFormSection`](profile-details-nodejs#baseformsection), `session`: `SessionContainerInterface`, `userContext?`: [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `any`\>) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\> | | `payload.storageHandlerId` | `string` | #### Returns diff --git a/docs/references/plugins/progressive-profiling-react.mdx b/docs/references/plugins/progressive-profiling-react.mdx index fcfa4a247c..112ef738d1 100644 --- a/docs/references/plugins/progressive-profiling-react.mdx +++ b/docs/references/plugins/progressive-profiling-react.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/progressive-profiling-react' --- -# `@supertokens-plugins/progressive-profiling-react` - ## Type Aliases ### FormInputComponentMap @@ -36,7 +34,7 @@ Defined in: [supertokens-plugins/packages/progressive-profiling-react/src/types. | Property | Type | Defined in | | ------ | ------ | ------ | -| `onSuccess?` | (`data`: [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)) => \| [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\> \| `undefined` | [supertokens-plugins/packages/progressive-profiling-react/src/types.ts:11](https://github.com/supertokens/supertokens-plugins/blob/main/packages/progressive-profiling-react/src/types.ts#L11) | +| `onSuccess?` | (`data`: [`BaseFormSection`](profile-details-nodejs#baseformsection)) => \| [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\> \| `undefined` | [supertokens-plugins/packages/progressive-profiling-react/src/types.ts:11](https://github.com/supertokens/supertokens-plugins/blob/main/packages/progressive-profiling-react/src/types.ts#L11) | | `requireSetup?` | `boolean` | [supertokens-plugins/packages/progressive-profiling-react/src/types.ts:8](https://github.com/supertokens/supertokens-plugins/blob/main/packages/progressive-profiling-react/src/types.ts#L8) | | `setupPagePath?` | `string` | [supertokens-plugins/packages/progressive-profiling-react/src/types.ts:7](https://github.com/supertokens/supertokens-plugins/blob/main/packages/progressive-profiling-react/src/types.ts#L7) | | `showEndSection?` | `boolean` | [supertokens-plugins/packages/progressive-profiling-react/src/types.ts:10](https://github.com/supertokens/supertokens-plugins/blob/main/packages/progressive-profiling-react/src/types.ts#L10) | @@ -82,7 +80,7 @@ Defined in: [supertokens-plugins/packages/progressive-profiling-react/src/types. | Property | Type | Defined in | | ------ | ------ | ------ | -| `onSuccess?` | (`data`: [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)) => \| [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\> \| `undefined` | [supertokens-plugins/packages/progressive-profiling-react/src/types.ts:19](https://github.com/supertokens/supertokens-plugins/blob/main/packages/progressive-profiling-react/src/types.ts#L19) | +| `onSuccess?` | (`data`: [`BaseFormSection`](profile-details-nodejs#baseformsection)) => \| [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\> \| `undefined` | [supertokens-plugins/packages/progressive-profiling-react/src/types.ts:19](https://github.com/supertokens/supertokens-plugins/blob/main/packages/progressive-profiling-react/src/types.ts#L19) | | `requireSetup` | `boolean` | [supertokens-plugins/packages/progressive-profiling-react/src/types.ts:16](https://github.com/supertokens/supertokens-plugins/blob/main/packages/progressive-profiling-react/src/types.ts#L16) | | `setupPagePath` | `string` | [supertokens-plugins/packages/progressive-profiling-react/src/types.ts:15](https://github.com/supertokens/supertokens-plugins/blob/main/packages/progressive-profiling-react/src/types.ts#L15) | | `showEndSection` | `boolean` | [supertokens-plugins/packages/progressive-profiling-react/src/types.ts:18](https://github.com/supertokens/supertokens-plugins/blob/main/packages/progressive-profiling-react/src/types.ts#L18) | diff --git a/docs/references/plugins/progressive-profiling-shared.mdx b/docs/references/plugins/progressive-profiling-shared.mdx index b8ace4e984..a9c717ecc8 100644 --- a/docs/references/plugins/progressive-profiling-shared.mdx +++ b/docs/references/plugins/progressive-profiling-shared.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: progressive-profiling-shared --- -# progressive-profiling-shared - ## Type Aliases ### FormField diff --git a/docs/references/plugins/tenant-discovery-nodejs.mdx b/docs/references/plugins/tenant-discovery-nodejs.mdx index 0d0bc5748c..0d430200ee 100644 --- a/docs/references/plugins/tenant-discovery-nodejs.mdx +++ b/docs/references/plugins/tenant-discovery-nodejs.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/tenant-discovery-nodejs' --- -# `@supertokens-plugins/tenant-discovery-nodejs` - ## Type Aliases ### MinimalTenantDetails diff --git a/docs/references/plugins/tenant-discovery-react.mdx b/docs/references/plugins/tenant-discovery-react.mdx index 725cd073b5..2960325891 100644 --- a/docs/references/plugins/tenant-discovery-react.mdx +++ b/docs/references/plugins/tenant-discovery-react.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/tenant-discovery-react' --- -# `@supertokens-plugins/tenant-discovery-react` - ## Interfaces ### TenantDetails diff --git a/docs/references/plugins/tenants-nodejs.mdx b/docs/references/plugins/tenants-nodejs.mdx index 1153a92601..2172781555 100644 --- a/docs/references/plugins/tenants-nodejs.mdx +++ b/docs/references/plugins/tenants-nodejs.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/tenants-nodejs' --- -# `@supertokens-plugins/tenants-nodejs` - ## Classes ### DefaultPluginEmailService @@ -381,17 +379,17 @@ Defined in: [supertokens-plugins/packages/tenants-nodejs/src/types.ts:91](https: | `assignRoleToUserInTenant` | (`tenantId`: `string`, `userId`: `string`, `role`: `string`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:181](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L181) | | `associateAllLoginMethodsOfUserWithTenant` | [`AssociateAllLoginMethodsOfUserWithTenant`](#associateallloginmethodsofuserwithtenant) | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:144](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L144) | | `canApproveJoinRequest` | (`targetUser`: `User`, `tenantId`: `string`, `session`: `SessionContainerInterface`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:102](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L102) | -| `canApproveTenantCreationRequest` | (`targetUser`: `User`, `creationRequest`: [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection), `session`: `SessionContainerInterface`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:103](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L103) | +| `canApproveTenantCreationRequest` | (`targetUser`: `User`, `creationRequest`: [`BaseFormSection`](profile-details-nodejs#baseformsection), `session`: `SessionContainerInterface`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:103](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L103) | | `canCreateInvitation` | (`email`: `string`, `role`: `string`, `tenantId`: `string`, `session`: `SessionContainerInterface`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:96](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L96) | | `canRemoveTargetUserFromTenant` | (`targetUser`: `User`, `tenantId`: `string`, `session`: `SessionContainerInterface`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:108](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L108) | | `createTenantAndAssignAdmin` | (`tenantDetails`: \{ `firstFactors?`: `string`[] \| `null`; `name`: `string`; \}, `userId`: `string`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\< \| \{ `createdNew`: `boolean`; `status`: `"OK"`; \} \| [`ErrorResponse`](#errorresponse)\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:113](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L113) | | `doesTenantCreationRequireApproval` | (`session`: `SessionContainerInterface`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:95](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L95) | | `doesUserHaveTenantCreationRequest` | (`userId`: `string`, `metadata`: [`TenantCreationRequestMetadataType`](#tenantcreationrequestmetadatatype)) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:179](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L179) | | `getAppUrl` | [`GetAppUrl`](#getappurl) | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:177](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L177) | -| `getInvitations` | (`tenantId`: `string`, `metadata`: [`MetadataType`](#metadatatype)) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\< \| \{ `invitees`: [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)[]; `status`: `"OK"`; \} \| [`ErrorResponse`](#errorresponse)\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:140](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L140) | +| `getInvitations` | (`tenantId`: `string`, `metadata`: [`MetadataType`](#metadatatype)) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\< \| \{ `invitees`: [`BaseFormSection`](profile-details-nodejs#baseformsection)[]; `status`: `"OK"`; \} \| [`ErrorResponse`](#errorresponse)\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:140](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L140) | | `getPreferredTenantId` | (`tenantIds`: `string`[], `inputTenantId`: `string`) => `string` \| `undefined` | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:180](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L180) | -| `getTenantCreationRequests` | (`metadata`: [`TenantCreationRequestMetadataType`](#tenantcreationrequestmetadatatype), `userContext`: `UserContext`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\< \| \{ `status`: `"OK"`; \} & \{ `requests`: [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)[]; \} \| [`ErrorResponse`](#errorresponse)\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:156](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L156) | -| `getTenants` | (`session`: `SessionContainerInterface` \| `string`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\< \| \{ `status`: `"OK"`; \} & [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection) \| [`ErrorResponse`](#errorresponse)\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:92](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L92) | +| `getTenantCreationRequests` | (`metadata`: [`TenantCreationRequestMetadataType`](#tenantcreationrequestmetadatatype), `userContext`: `UserContext`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\< \| \{ `status`: `"OK"`; \} & \{ `requests`: [`BaseFormSection`](profile-details-nodejs#baseformsection)[]; \} \| [`ErrorResponse`](#errorresponse)\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:156](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L156) | +| `getTenants` | (`session`: `SessionContainerInterface` \| `string`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\< \| \{ `status`: `"OK"`; \} & [`BaseFormSection`](profile-details-nodejs#baseformsection) \| [`ErrorResponse`](#errorresponse)\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:92](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L92) | | `getTenantUsers` | (`tenantId`: `string`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\< \| \{ `status`: `"OK"`; `users`: `User` & \{ `roles?`: `string`[]; \}[]; \} \| [`ErrorResponse`](#errorresponse)\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:120](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L120) | | `isAllowedToCreateTenant` | (`session`: `SessionContainerInterface`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:94](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L94) | | `isAllowedToJoinTenant` | (`targetUser`: `User`, `session`: `SessionContainerInterface`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\> | [supertokens-plugins/packages/tenants-nodejs/src/types.ts:93](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-nodejs/src/types.ts#L93) | diff --git a/docs/references/plugins/tenants-react.mdx b/docs/references/plugins/tenants-react.mdx index 78f0dd6cc9..45c56dbee5 100644 --- a/docs/references/plugins/tenants-react.mdx +++ b/docs/references/plugins/tenants-react.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/tentants-react' --- -# `@supertokens-plugins/tentants-react` - ## Type Aliases ### AddInvitationProps @@ -40,7 +38,7 @@ Defined in: [supertokens-plugins/packages/tenants-react/src/components/invitatio | Property | Type | Defined in | | ------ | ------ | ------ | -| `invitations` | [`BaseFormSection`](profile-details-nodejs.mdx#baseformsection)[] | [supertokens-plugins/packages/tenants-react/src/components/invitations/InvitedUsers.tsx:17](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-react/src/components/invitations/InvitedUsers.tsx#L17) | +| `invitations` | [`BaseFormSection`](profile-details-nodejs#baseformsection)[] | [supertokens-plugins/packages/tenants-react/src/components/invitations/InvitedUsers.tsx:17](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-react/src/components/invitations/InvitedUsers.tsx#L17) | | `onRemove` | (`email`: `string`) => [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\> | [supertokens-plugins/packages/tenants-react/src/components/invitations/InvitedUsers.tsx:16](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-react/src/components/invitations/InvitedUsers.tsx#L16) | | `tenantId` | `string` | [supertokens-plugins/packages/tenants-react/src/components/invitations/InvitedUsers.tsx:18](https://github.com/supertokens/supertokens-plugins/blob/main/packages/tenants-react/src/components/invitations/InvitedUsers.tsx#L18) | diff --git a/docs/references/plugins/user-banning-nodejs.mdx b/docs/references/plugins/user-banning-nodejs.mdx index 66514b8751..1a1287ecb9 100644 --- a/docs/references/plugins/user-banning-nodejs.mdx +++ b/docs/references/plugins/user-banning-nodejs.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/user-banning-nodejs' --- -# `@supertokens-plugins/user-banning-nodejs` - ## Classes ### UserBanningService diff --git a/docs/references/plugins/user-banning-react.mdx b/docs/references/plugins/user-banning-react.mdx index b155c475a9..4c534973b2 100644 --- a/docs/references/plugins/user-banning-react.mdx +++ b/docs/references/plugins/user-banning-react.mdx @@ -1,9 +1,7 @@ --- -page_type: plugin-reference +title: '@supertokens-plugins/user-banning-react' --- -# `@supertokens-plugins/user-banning-react` - ## Type Aliases ### SuperTokensPluginUserBanningPluginConfig diff --git a/docs/references/testing-and-debugging/_category_.json b/docs/references/testing-and-debugging/_category_.json deleted file mode 100644 index 94bdf957f1..0000000000 --- a/docs/references/testing-and-debugging/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Testing and Debugging", - "customProps": { "isMainCategory": true }, - "position": 6 -} diff --git a/docs/references/testing-and-debugging/api-testing.mdx b/docs/references/testing-and-debugging/api-testing.mdx index 09270a06cb..6a8deef9cb 100644 --- a/docs/references/testing-and-debugging/api-testing.mdx +++ b/docs/references/testing-and-debugging/api-testing.mdx @@ -1,19 +1,13 @@ --- title: API Testing -hide_title: true -sidebar_position: 1 description: Test the APIs exposed by the backend SDK. -pagination_prev: null -page_type: guide -category: references +sidebar: + order: 1 --- - -# Testing with postman - The following guide goes over the process of testing backend APIs with Postman. These APIs are automatically exposed via the backend SDK (`/auth/*` path). -:::info Important +:::info[Important] - Make sure that the ThirdParty Recipe is correctly setup in your backend - For the examples given below, the backend runs on domain `localhost` and port `3001`. - You can find the Open API spec for the APIs under test [in the SwaggerHub API documentation](https://app.swaggerhub.com/apis/SuperTokens/FDI). @@ -32,7 +26,7 @@ The `/auth/signinup` API requires the `redirectURI`, `thirdPartyId`, and `code` - `sAccessToken` - `sRefreshToken` -- More information about these cookies is available [in the session management security documentation](/docs/post-authentication/session-management/security#cookie-consent). +- More information about these cookies is available [in the session management security documentation](/post-authentication/session-management/security#cookie-consent). ## 2. Session verification @@ -41,8 +35,8 @@ The `/auth/signinup` API requires the `redirectURI`, `thirdPartyId`, and `code` - For example, there is an API used to query user data with the `verifySession` middleware as shown below. - - + + ```tsx import express from "express"; @@ -62,8 +56,8 @@ app.post("/change-user-data", verifySession(), async (req, res) => { }) ``` - - + + ```go import ( @@ -104,8 +98,8 @@ func main() { } ``` - - + + ```python # The following code snippet is an example API (fastapi). You do not need to @@ -115,30 +109,30 @@ from supertokens_python.recipe.session.framework.fastapi import verify_session from supertokens_python.recipe.session import SessionContainer from fastapi import Depends -@app.post('/change-user-data') # type: ignore +@app.post('/change-user-data') async def change_user_data(session: SessionContainer = Depends(verify_session())): _ = session.get_user_id() # mutate some user data # send response ``` - - + + - In Postman, set the request type to `POST`. - Set the URL to `http://localhost:3001/change-user-data` - If you have the `antiCsrf` attribute set to `VIA_TOKEN` in your backend SuperTokens configuration, then in the Postman Header tab, set a key as `anti-csrf` and value as the `anti-csrf` token retrieved from the login response. - On a successful response, the response body contains user data. -:::info Important +:::info[Important] By default, for `GET` APIs, you don't need to provide the `anti-csrf` request header as anti-CSRF checks are only done in non-`GET` APIs ::: -Request to change user data in postman +Request to change user data in postman In case you query the `/change-user-data` API with an expired access token, you receive a `401` response with the message `try refresh token`. -Failed query due to expired access token in postman +Failed query due to expired access token in postman To generate new session tokens you can use the `/auth/session/refresh` API as shown in the next section. @@ -150,11 +144,11 @@ In case your `access token` expires you can call the `/auth/session/refresh` API - Set the URL to `http://localhost:3001/auth/session/refresh` - On a successful response, the system sets new session tokens. -Successful session refresh in postman +Successful session refresh in postman You can see the new session tokens by switching to the cookies tab -Viewing session tokens in cookies tab in postman +Viewing session tokens in cookies tab in postman ## 4. Logout @@ -164,4 +158,4 @@ The `/auth/signout` API invalidates the user sessions. This clears the session c - Set the URL to `http://localhost:3001/auth/signout` - On a successful response, Postman and the database clear the session tokens. -Successful sign out request in postman +Successful sign out request in postman diff --git a/docs/references/testing-and-debugging/common-issues.mdx b/docs/references/testing-and-debugging/common-issues.mdx index 5be2ce2072..b1d1b49d6a 100644 --- a/docs/references/testing-and-debugging/common-issues.mdx +++ b/docs/references/testing-and-debugging/common-issues.mdx @@ -1,14 +1,10 @@ --- title: Common issues -hide_title: true -sidebar_position: 3 description: 'Resolve common issues that might occur when you integrate SuperTokens. ' -page_type: guides -category: references +sidebar: + order: 3 --- -# Common issues - ## Overview If you run into issues during your integration, please go through [this checklist](https://github.com/supertokens/supertokens-core/issues/1044) to see if you can find a resolution. @@ -63,7 +59,7 @@ This happens when the CORS credentials field is not set to true. Set credentials to `true` in the CORS setting to remedy this issue. -```tsx +```tsx {13} import SuperTokens from "supertokens-node"; import express from "express"; import cors from "cors"; @@ -76,15 +72,13 @@ app.use( origin: "http://localhost:3000", allowedHeaders: ["content-type", ...SuperTokens.getAllCORSHeaders()], methods: ["GET", "PUT", "POST", "DELETE"], - //highlight-start credentials: true, // Make sure credentials is set to true - //highlight-end }) ); ``` -
+
### Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin. Status code: 204 @@ -96,7 +90,7 @@ A couple of cases might cause this to happen. 3. Another variant of this error occurs when the OPTIONS API returns a 404 error. If the `origin` field is correctly set up, then the error is likely a misconfigured API gateway or reverse proxy. -```tsx +```tsx {13,21} import supertokens from "supertokens-node"; import express from "express"; import cors from "cors"; @@ -109,7 +103,6 @@ supertokens.init({ appInfo: { appName: "...", apiDomain: "...", - // highlight-next-line websiteDomain: "http://localhost:3000", }, recipeList: [/* ... */], @@ -118,9 +111,7 @@ supertokens.init({ const app = express(); app.use( cors({ - //highlight-start origin: "http://localhost:3000", // Make sure this is the same as the website domain - //highlight-end allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()], methods: ["GET", "PUT", "POST", "DELETE"], credentials: true, @@ -136,7 +127,7 @@ app.use( This appears when `Access-Control-Allow-Origin` header uses `*`. To fix, add the correct origin value in the CORS settings. -```tsx +```tsx {9} import supertokens from "supertokens-node"; import express from "express"; import cors from "cors"; @@ -145,9 +136,7 @@ const app = express(); app.use( cors({ - //highlight-start origin: "http://localhost:3000", // Make sure this is the same as the website domain - //highlight-end allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()], methods: ["GET", "PUT", "POST", "DELETE"], credentials: true, @@ -163,7 +152,7 @@ app.use( Similar to the previous issue, this appears when `Access-Control-Allow-Origin` header includes `*`. To fix, add in the correct origin value, `http://localhost:3000` in this case, in the CORS settings. -```tsx +```tsx {9} import supertokens from "supertokens-node"; import express from "express"; import cors from "cors"; @@ -172,9 +161,7 @@ const app = express(); app.use( cors({ - //highlight-start origin: "http://localhost:3000", // Make sure this is the same as the website domain - //highlight-end allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()], methods: ["GET", "PUT", "POST", "DELETE"], credentials: true, diff --git a/docs/references/testing-and-debugging/how-to-troubleshoot.mdx b/docs/references/testing-and-debugging/how-to-troubleshoot.mdx index c33739f22e..1ec194401a 100644 --- a/docs/references/testing-and-debugging/how-to-troubleshoot.mdx +++ b/docs/references/testing-and-debugging/how-to-troubleshoot.mdx @@ -1,23 +1,13 @@ --- -id: how-to-troubleshoot title: How to enable debug logs -hide_title: true -sidebar_position: 2 -description: >- - Enable debug logs for each SuperTokens component to troubleshoot your - integration. -page_type: guide -category: references +description: Enable debug logs for each SuperTokens component to troubleshoot your integration. +sidebar: + order: 2 --- - -# How to enable debug logs - - ## Backend logs -:::important -This is only available on versions: +:::note[This is only available on versions:] - SuperTokens-node >= v9.1.2 - SuperTokens-golang >= v0.5.5 - SuperTokens-python >= v0.6.3 @@ -26,14 +16,13 @@ This is only available on versions: Our backend SDK provides useful logs that can help with debugging. To enable logging, you need to set the debug setting to `true` in the `init` function call: - - + + -```tsx +```tsx {4} import supertokens from "supertokens-node"; supertokens.init({ - // highlight-next-line debug: true, supertokens: { connectionURI: "...", @@ -47,15 +36,14 @@ supertokens.init({ }); ``` - - + + -```go +```go {5} import "github.com/supertokens/supertokens-golang/supertokens" func main() { supertokens.Init(supertokens.TypeInput{ - // highlight-next-line Debug: true, Supertokens: &supertokens.ConnectionInfo{ ConnectionURI: "...", @@ -66,14 +54,13 @@ func main() { ``` - - + + -```python +```python {4} from supertokens_python import init, InputAppInfo, SupertokensConfig init( - # highlight-next-line debug=True, app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."), supertokens_config=SupertokensConfig( @@ -87,8 +74,8 @@ init( ) ``` - - + + Logs on your terminal have the following shape: ```bash @@ -104,51 +91,44 @@ com.supertokens {"t": "2022-04-09T08:44:49.057Z", "sdkVer": "...", "message": "S Add `enableDebugLogs` when calling the `init` function: - + - + - + - + -```tsx +```tsx {5} import React from 'react'; import SuperTokens from "supertokens-auth-react"; SuperTokens.init({ - // highlight-next-line enableDebugLogs: true, - // @ts-ignore appInfo: { /*...*/ }, - // @ts-ignore recipeList: [/*...*/] }); ``` - + - + You need to make changes to the auth route configuration, as well as to the `supertokens-web-js` SDK configuration at the root of your application: -```tsx +```tsx {4} // this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded) -import {init as supertokensUIInit} from "supertokens-auth-react-script"; supertokensUIInit({ - // highlight-next-line enableDebugLogs: true, - // @ts-ignore appInfo: { /*...*/ }, - // @ts-ignore recipeList: [/*...*/] }); ``` This change goes in the `supertokens-web-js` SDK configuration at the root of your application: -```tsx +```tsx {12} import SuperTokens from 'supertokens-web-js'; import Session from 'supertokens-web-js/recipe/session'; @@ -160,26 +140,25 @@ SuperTokens.init({ recipeList: [ Session.init(), ], - // highlight-next-line enableDebugLogs: true, }); ``` - + - + - +
- + - - + + - - + + -```tsx +```tsx {12} import SuperTokens from 'supertokens-web-js'; import Session from 'supertokens-web-js/recipe/session'; @@ -191,17 +170,14 @@ SuperTokens.init({ recipeList: [ Session.init(), ], - // highlight-next-line enableDebugLogs: true, }); ``` - - + + -```tsx -import supertokens from "supertokens-web-js-script"; -import supertokensSession from "supertokens-web-js-script/recipe/session"; +```tsx {9} supertokens.init({ appInfo: { apiDomain: "...", @@ -210,60 +186,56 @@ supertokens.init({ recipeList: [ supertokensSession.init(), ], - // highlight-next-line enableDebugLogs: true, }); ``` - - + + The above prints out SuperTokens debug log on the browser console: -Frontend browser debug logs +Frontend browser debug logs - + - + - + - + -```tsx +```tsx {5} import SuperTokens from 'supertokens-react-native'; SuperTokens.init({ apiDomain: "...", - // highlight-next-line enableDebugLogs: true, }); ``` The above prints out SuperTokens debug logs on the terminal if you're using the React Native CLI or Expo: -React Native debug logs +React Native debug logs - + - + -:::caution -Debug logs feature not yet available for Android +:::warning[Debug logs feature not yet available for Android] ::: - + - + -:::caution -Debug logs feature not yet available for iOS +:::warning[Debug logs feature not yet available for iOS] ::: - + - + ```dart import 'package:supertokens_flutter/supertokens.dart'; @@ -275,18 +247,17 @@ void main() { The above prints out SuperTokens debug logs on the terminal: -Flutter debug logs +Flutter debug logs - + - + - + - - - + + ## SuperTokens core logs @@ -301,19 +272,18 @@ If you want to change the log levels, you can set the core's `log_level` configu By default, the core prints out `INFO`, `WARN`, and `ERROR` logs. - - + + -```bash +```bash {3} docker run \ -p 3567:3567 \ - // highlight-next-line -e LOG_LEVEL=DEBUG \ -d supertokens/supertokens- ``` - + - + ```yaml # You need to add the following to the config.yaml file. @@ -321,5 +291,5 @@ By default, the core prints out `INFO`, `WARN`, and `ERROR` logs. log_level: "DEBUG" ``` - - + + diff --git a/docs/references/testing-and-debugging/meta.ts b/docs/references/testing-and-debugging/meta.ts new file mode 100644 index 0000000000..27c9a8bcf7 --- /dev/null +++ b/docs/references/testing-and-debugging/meta.ts @@ -0,0 +1,7 @@ +import { defineMeta } from "blume"; + +export default defineMeta({ + "title": "Testing and Debugging", + "icon": "bug", + "order": 6 +}); diff --git a/docs/references/updating-supertokens.mdx b/docs/references/updating-supertokens.mdx index cc78702cdb..350b2cf9eb 100644 --- a/docs/references/updating-supertokens.mdx +++ b/docs/references/updating-supertokens.mdx @@ -1,17 +1,10 @@ --- -id: updating-supertokens title: Update Guide -hide_title: true -sidebar_position: 6 -description: >- - Update SuperTokens core and SDKs to maintain compatibility and access new - features. -page_type: guide -category: references +description: Update SuperTokens core and SDKs to maintain compatibility and access new features. +sidebar: + order: 6 --- -# Updating SuperTokens core and SDKs - ## Overview Follow these steps to update SuperTokens. @@ -27,7 +20,7 @@ You may then bring your core back online. ### Self-hosted core -See the migration sections in the [SuperTokens-core changelog](https://github.com/supertokens/supertokens-core/blob/master/CHANGELOG.md). +See the migration sections in the [SuperTokens-core changelog](https://github.com/supertokens/supertokens-core/blob/master/CHANGELOG). ### Managed core @@ -41,9 +34,9 @@ Follow the steps in the migration sections of the linked changelog from your cur | Backend | Changelog | |---------|-----------| -| NodeJS | [SuperTokens-node](https://github.com/supertokens/supertokens-node/blob/master/CHANGELOG.md) | -| GoLang | [SuperTokens-golang](https://github.com/supertokens/supertokens-golang/blob/master/CHANGELOG.md) | -| Python | [SuperTokens-python](https://github.com/supertokens/supertokens-python/blob/master/CHANGELOG.md) | +| NodeJS | [SuperTokens-node](https://github.com/supertokens/supertokens-node/blob/master/CHANGELOG) | +| GoLang | [SuperTokens-golang](https://github.com/supertokens/supertokens-golang/blob/master/CHANGELOG) | +| Python | [SuperTokens-python](https://github.com/supertokens/supertokens-python/blob/master/CHANGELOG) | --- @@ -53,9 +46,9 @@ Follow the steps in the migration sections of the linked changelog from your cur | Framework/Platform | Changelog | |-------------------|-----------| -| ReactJS | [SuperTokens-auth-react](https://github.com/supertokens/supertokens-auth-react/blob/master/CHANGELOG.md) | -| Vanilla JS | [SuperTokens-web-js](https://github.com/supertokens/supertokens-web-js/blob/master/CHANGELOG.md) | -| React Native | [SuperTokens-react-native](https://github.com/supertokens/supertokens-react-native/blob/master/CHANGELOG.md) | -| iOS | [SuperTokens-ios](https://github.com/supertokens/supertokens-ios/blob/master/CHANGELOG.md) | -| Flutter | [SuperTokens-flutter](https://github.com/supertokens/supertokens-flutter/blob/master/CHANGELOG.md) | -| Android | [SuperTokens-android](https://github.com/supertokens/supertokens-android/blob/master/CHANGELOG.md) | +| ReactJS | [SuperTokens-auth-react](https://github.com/supertokens/supertokens-auth-react/blob/master/CHANGELOG) | +| Vanilla JS | [SuperTokens-web-js](https://github.com/supertokens/supertokens-web-js/blob/master/CHANGELOG) | +| React Native | [SuperTokens-react-native](https://github.com/supertokens/supertokens-react-native/blob/master/CHANGELOG) | +| iOS | [SuperTokens-ios](https://github.com/supertokens/supertokens-ios/blob/master/CHANGELOG) | +| Flutter | [SuperTokens-flutter](https://github.com/supertokens/supertokens-flutter/blob/master/CHANGELOG) | +| Android | [SuperTokens-android](https://github.com/supertokens/supertokens-android/blob/master/CHANGELOG) | diff --git a/docusaurus.config.ts b/docusaurus.config.ts deleted file mode 100644 index e13c4e8791..0000000000 --- a/docusaurus.config.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { themes as prismThemes } from "prism-react-renderer"; -import type { Config } from "@docusaurus/types"; -import type * as Preset from "@docusaurus/preset-classic"; -import addNofollowToExternalLinks from "./src/plugins/addNofollowToExternalLinks"; - -import remarkDocItemContextValues from "./src/plugins/remarkDocItemContextValues"; -import remarkRemoveCodeTypeCheckingCommentsAndRows from "./src/plugins/remarkRemoveCodeTypeCheckingCommentsAndRows"; -import remarkRemoveWebJsScriptImports from "./src/plugins/remarkRemoveWebJsScriptImports"; -import remarkDocItemDescription from "./src/plugins/remarkDocItemDescription"; -import remarkAddBadgesInHeadings from "./src/plugins/remarkAddBadgesInHeadings"; -import generateLllmsTxt from "./src/plugins/generateLllmsTxt"; -import generateLllmsFullTxt from "./src/plugins/generateLllmsFullTxt"; - -const config: Config = { - title: "SuperTokens Docs", - tagline: "Open Source User Authentication", - url: "https://supertokens.com", - baseUrl: "/", - favicon: "img/favicon.ico", - trailingSlash: false, - onBrokenLinks: process.env.DEPLOYMENT_TYPE === "preview" ? "warn" : "throw", - onBrokenMarkdownLinks: process.env.DEPLOYMENT_TYPE === "preview" ? "warn" : "throw", - future: { - // Faster mode breaks the css styles in the latest version of docusaurus - experimental_faster: false, - v4: false, - }, - // Even if you don't use internationalization, you can use this field to set - // useful metadata like html lang. For example, if your site is Chinese, you - // may want to replace "en" with "zh-Hans". - i18n: { - defaultLocale: "en", - locales: ["en"], - }, - presets: [ - [ - "classic", - { - docs: { - routeBasePath: "/docs", - sidebarPath: "./sidebars.ts", - exclude: ["**/_*", "**/_*/**"], - breadcrumbs: false, - editUrl: "https://github.com/supertokens/docs/tree/master/", - beforeDefaultRemarkPlugins: [ - remarkDocItemContextValues, - remarkRemoveCodeTypeCheckingCommentsAndRows, - remarkRemoveWebJsScriptImports, - remarkAddBadgesInHeadings, - ], - rehypePlugins: [addNofollowToExternalLinks], - remarkPlugins: [remarkDocItemDescription], - async sidebarItemsGenerator({ defaultSidebarItemsGenerator, ...args }) { - const sidebarItems = await defaultSidebarItemsGenerator(args); - - return sidebarItems; - }, - }, - blog: false, - pages: false, - theme: { - customCss: ["./src/css/custom.scss", "./src/css/fonts.css", "./src/css/radix.css"], - }, - } satisfies Preset.Options, - ], - ], - themeConfig: { - colorMode: { - defaultMode: "dark", - disableSwitch: true, - respectPrefersColorScheme: true, - }, - image: "https://supertokens.com/static/assets/home-meta.png", - navbar: { - title: "SuperTokens", - logo: { - alt: "SuperTokens Logo", - src: "img/logoWithNameLight.svg", - srcDark: "img/logoWithNameLight.svg", - href: "/", - target: "_blank", - }, - items: [], - }, - algolia: { - apiKey: "ce04a158637d345fc094ebbfa9a5156a", - indexName: "supertokens", - appId: "SBR5UR2Z16", - insights: true, - }, - prism: { - theme: prismThemes.oneDark, - additionalLanguages: ["kotlin", "java", "swift", "dart", "csharp", "php", "bash"], - }, - metadata: [ - { - name: "keywords", - content: "authentication, open source, login, authorization, security, session management", - }, - { name: "robots", content: "index, follow" }, - { name: "twitter:card", content: "summary_large_image" }, - { name: "twitter:creator", content: "@supertokens.io" }, - { name: "twitter:title", content: "SuperTokens, Open Source User Authentication" }, - { - name: "twitter:description", - content: "Open Source User Authentication. Build fast, maintain control, with reasonable pricing.", - }, - { name: "twitter:image", content: "https://supertokens.com/assets/images/website/og/homepage.png" }, - { property: "og:image", content: "https://supertokens.com/assets/images/website/og/homepage.png" }, - { property: "og:type", content: "website" }, - ], - } satisfies Preset.ThemeConfig, - headTags: [ - { - tagName: "script", - attributes: { type: "application/ld+json" }, - innerHTML: JSON.stringify({ - "@context": "https://schema.org", - "@type": "WebSite", - name: "SuperTokens Docs", - url: "https://supertokens.com/docs", - publisher: { - "@type": "Organization", - name: "SuperTokens", - url: "https://supertokens.com", - logo: { - "@type": "ImageObject", - url: "https://supertokens.com/assets/images/website/og/homepage.png", - }, - }, - }), - }, - ], - plugins: [ - "docusaurus-plugin-sass", - process.env.NODE_ENV === "production" && "@docusaurus/plugin-debug", - generateLllmsTxt, - generateLllmsFullTxt, - [ - // loads the supertokens.com react bundle for footer and analytics etc.. - "./src/plugins/reactBundle", - { - id: "react-bundle", - }, - ], - [ - "./src/plugins/transformOpenSearchLink", - //used to transform the opensearch.xml location in the metatags. - { - id: "transform-opensearch-link", - }, - ], - ].filter(Boolean), -}; - -// As far as I can tell docusaurus doesn't export this type -type NormalizedSidebarItems = Awaited< - ReturnType["sidebarItemsGenerator"]> ->[number]; - -// Reorders the default sidebar items based on the "childrenOrder" property specified in _category_.json, in customProps -// -// There are several ways to order navigation items in docusaurus -// We are using the file based approach in our docs because -// we rely on the folder/file tree as the source of truth when it comes to routing. -// It's easier to change things and to handle a large number of pages when -// things are composable and you do not have to edit a big JSON file. -// That being said, there's an issue with how Docusaurus extracts those pages and organizes them into sidebar items. -// Let's say you have a folder called "quickstart". -// - In that folder you have a _category_.json file where you specify the name of the sidebar category -// - Each mdx file in turn has a frontmatter property called "sidebar_position" which specifies the order of the page inside the sidebar category -// - If you add an additional page, that should between the existing pages, you need to also go to each of the other pages that are reodered -// and update their "sidebar_position" property to reflect the new order -// That can be quite cumborsome for categories with a lot of pages. -// -// TODO: This is blocked ATM because docusaurus does not include the file name in the category sidebar item -// function reorderSidebarItems(normalizedSidebarItem: NormalizedSidebarItems) { -// if (normalizedSidebarItem.type === "category") { -// const childrenOrder = normalizedSidebarItem.customProps.childrenOrder as string[] | undefined; -// if(childrenOrder) { -// normalizedSidebarItem.items = childrenOrder.map((childName) => { -// const child = normalizedSidebarItem.items.find((item) => { -// // @ts-expect-error -// const labelOrValue = 'label' in item ? item.label : item.value; -// return labelOrValue === childName; -// }); -// if(!child) { -// console.error(`Could not find child with label or value ${childName} in ${normalizedSidebarItem.label}`); -// } -// }); -// } -// } -// return normalizedSidebarItem; -// } - -export default config; diff --git a/islands/ExampleAppForm.tsx b/islands/ExampleAppForm.tsx new file mode 100644 index 0000000000..9fa4eb8930 --- /dev/null +++ b/islands/ExampleAppForm.tsx @@ -0,0 +1,53 @@ +import { useState } from "react"; + +const recipes = ["emailpassword", "passwordless", "thirdparty", "multifactorauth", "multitenancy"]; +const frontends = ["react", "angular", "vue", "next"]; +const backends = ["node", "go-http", "python"]; + +export default function ExampleAppForm() { + const [appName, setAppName] = useState(""); + const [recipe, setRecipe] = useState("emailpassword"); + const [frontend, setFrontend] = useState("react"); + const [backend, setBackend] = useState("node"); + const command = [ + "npx create-supertokens-app", + appName && `--appname=${JSON.stringify(appName)}`, + `--recipe=${recipe}`, + `--frontend=${frontend}`, + frontend !== "next" && `--backend=${backend}`, + ] + .filter(Boolean) + .join(" "); + + return ( +
+

Generate example app

+

Choose your stack, then run the generated command.

+
+ + + + +
+
{command}
+
+ ); +} diff --git a/islands/SDKCompatibilityTable.tsx b/islands/SDKCompatibilityTable.tsx new file mode 100644 index 0000000000..6bd3367f17 --- /dev/null +++ b/islands/SDKCompatibilityTable.tsx @@ -0,0 +1,77 @@ +import { useEffect, useState } from "react"; + +interface SdkOption { + id: string; + displayName: string; +} + +interface Compatibility { + coreToDriver: Record; + driverToFrontend: Record; +} + +const apiBase = "https://api.supertokens.com/0"; + +async function request(path: string): Promise { + const response = await fetch(`${apiBase}${path}`, { headers: { "api-version": "0" } }); + if (!response.ok) throw new Error(`Compatibility API returned ${response.status}`); + return response.json() as Promise; +} + +export default function SDKCompatibilityTable() { + const [frontends, setFrontends] = useState([]); + const [backends, setBackends] = useState([]); + const [frontend, setFrontend] = useState(""); + const [backend, setBackend] = useState(""); + const [compatibility, setCompatibility] = useState(null); + const [error, setError] = useState(""); + + useEffect(() => { + Promise.all([ + request<{ frontends: SdkOption[] }>("/frontends?mode=PRODUCTION"), + request<{ drivers: SdkOption[] }>("/drivers?planType=FREE&mode=PRODUCTION"), + ]) + .then(([frontendResult, backendResult]) => { + setFrontends(frontendResult.frontends); + setBackends(backendResult.drivers); + }) + .catch((reason: unknown) => setError(reason instanceof Error ? reason.message : "Failed to load SDKs")); + }, []); + + useEffect(() => { + if (!(frontend && backend)) return; + setCompatibility(null); + request(`/compatibility?driver=${encodeURIComponent(backend)}&frontend=${encodeURIComponent(frontend)}`) + .then(setCompatibility) + .catch((reason: unknown) => setError(reason instanceof Error ? reason.message : "Failed to load compatibility")); + }, [backend, frontend]); + + return ( +
+

SDK compatibility

+
+ + +
+ {error &&

{error}

} + {compatibility && ( +
+
Core to backend
{JSON.stringify(compatibility.coreToDriver, null, 2)}
+
Backend to frontend
{JSON.stringify(compatibility.driverToFrontend, null, 2)}
+
+ )} +
+ ); +} diff --git a/microfrontends.jsonc b/microfrontends.jsonc new file mode 100644 index 0000000000..9b176ca441 --- /dev/null +++ b/microfrontends.jsonc @@ -0,0 +1,21 @@ +{ + "$schema": "https://openapi.vercel.sh/microfrontends.json", + "applications": { + "saas-dashboard-ui": { + "packageName": "@supertokens/saas-dashboard-ui", + "development": { + "local": 3000, + "fallback": "supertokens.com", + }, + }, + "docs": { + "packageName": "@supertokens/docs", + "routing": [ + { + "group": "docs", + "paths": ["/docs/:path*"], + }, + ], + }, + }, +} diff --git a/static/cdi.yml b/openapi/cdi.yml similarity index 100% rename from static/cdi.yml rename to openapi/cdi.yml diff --git a/static/fdi.yml b/openapi/fdi.yml similarity index 100% rename from static/fdi.yml rename to openapi/fdi.yml diff --git a/package-lock.json b/package-lock.json index 2d53bd264b..37371725aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,1468 +1,1540 @@ { - "name": "v-3", + "name": "@supertokens/docs", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "v-3", + "name": "@supertokens/docs", "version": "0.0.0", "dependencies": { - "@algolia/client-search": "^5.29.0", - "@amplitude/analytics-browser": "^2.11.11", - "@amplitude/plugin-session-replay-browser": "^1.13.9", - "@docsearch/react": "^3.6.2", - "@docusaurus/core": "^3.8.1", - "@docusaurus/plugin-client-redirects": "^3.8.1", - "@docusaurus/plugin-debug": "^3.8.1", - "@docusaurus/preset-classic": "^3.8.1", - "@docusaurus/theme-search-algolia": "^3.8.1", - "@mdx-js/react": "^3.0.0", - "@radix-ui/react-accordion": "^1.2.2", - "@radix-ui/react-form": "^0.1.0", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/themes": "^3.1.6", - "@scalar/api-client": "^2.5.22", - "@scalar/api-client-react": "^1.3.27", - "@scalar/api-reference-react": "^0.7.38", - "@scalar/openapi-parser": "^0.10.14", - "@scalar/openapi-types": "^0.2.0", - "axios": "^1.7.9", - "class-variance-authority": "^0.7.1", - "clsx": "^2.0.0", - "docusaurus-plugin-sass": "^0.2.5", - "dotenv": "^16.4.5", - "js-cookie": "^3.0.5", - "lucide-react": "^0.534.0", - "motion": "^11.13.1", - "prism-react-renderer": "^2.4.1", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "react-markdown": "^10.1.0", - "sass": "^1.80.6", - "search-insights": "^2.17.3", - "supertokens-website": "^20.1.5", - "tailwind-merge": "^2.5.5", - "uuid": "^11.0.3", - "zod": "^4.0.17" + "@vercel/microfrontends": "^2.4.0", + "blume": "1.2.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" }, "devDependencies": { - "@docusaurus/faster": "^3.8.1", - "@docusaurus/module-type-aliases": "^3.8.1", - "@docusaurus/tsconfig": "^3.8.1", - "@docusaurus/types": "^3.8.1", - "@testing-library/jest-dom": "^6.6.3", - "@testing-library/react": "^16.2.0", - "@testing-library/user-event": "^14.6.1", + "@mdx-js/mdx": "^3.1.0", "@types/bun": "^1.2.9", "@types/fs-extra": "^11.0.4", - "@vitejs/plugin-react": "^4.3.4", - "algoliasearch": "^5.32.0", - "chalk": "^5.4.1", + "@types/node": "^22.10.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", "fs-extra": "^11.2.0", + "glob": "^11.0.0", "js-yaml": "^4.1.0", - "jsdom": "^26.0.0", - "ora": "^8.2.0", "prettier": "3.3.3", "tree-sitter": "^0.21.0", "tree-sitter-go": "^0.21.2", "tree-sitter-python": "^0.21.0", "tree-sitter-typescript": "^0.21.2", - "typedoc": "^0.28.12", + "typedoc": "^0.28.20", "typedoc-plugin-frontmatter": "^1.3.0", "typedoc-plugin-inline-sources": "^1.3.0", "typedoc-plugin-markdown": "^4.8.1", "typedoc-plugin-mdn-links": "^5.0.9", - "typedoc-plugin-merge-modules": "^7.0.0", - "typedoc-plugin-missing-exports": "^4.1.0", - "typescript": "~5.6.2", - "vitest": "^3.0.9", - "ws": "^8.18.0" + "typescript": "^6.0.3", + "unist-util-visit": "^5.0.0", + "vitest": "^4.0.0" }, "engines": { - "node": ">=18.0" + "node": ">=22.12.0" } }, - "node_modules/@adobe/css-tools": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", - "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@algolia/abtesting": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.2.0.tgz", - "integrity": "sha512-Z6Liq7US5CpdHExZLfPMBPxQHHUObV587kGvCLniLr1UTx0fGFIeGNWd005WIqQXqEda9GyAi7T2e7DUupVv0g==", - "license": "MIT", + "node_modules/@ai-sdk/gateway": { + "version": "2.0.121", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-2.0.121.tgz", + "integrity": "sha512-H5m+5rTovokYFVS9Wb+utB/Gjup9taIKxihBzSv+rVNGd2TYHJVk8/ldTMYnughTGNOUQLLI6RB6zimCXoDNzg==", + "license": "Apache-2.0", "dependencies": { - "@algolia/client-common": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "@ai-sdk/provider": "2.0.3", + "@ai-sdk/provider-utils": "3.0.30", + "@vercel/oidc": "3.1.0" }, "engines": { - "node": ">= 14.0.0" + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@algolia/autocomplete-core": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.9.tgz", - "integrity": "sha512-O7BxrpLDPJWWHv/DLA9DRFWs+iY1uOJZkqUwjS5HSZAGcl0hIVCQ97LTLewiZmZ402JYUrun+8NqFP+hCknlbQ==", - "license": "MIT", - "dependencies": { - "@algolia/autocomplete-plugin-algolia-insights": "1.17.9", - "@algolia/autocomplete-shared": "1.17.9" + "node_modules/@ai-sdk/gateway/node_modules/@vercel/oidc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.1.0.tgz", + "integrity": "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20" } }, - "node_modules/@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.9.tgz", - "integrity": "sha512-u1fEHkCbWF92DBeB/KHeMacsjsoI0wFhjZtlCq2ddZbAehshbZST6Hs0Avkc0s+4UyBGbMDnSuXHLuvRWK5iDQ==", - "license": "MIT", + "node_modules/@ai-sdk/provider": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.3.tgz", + "integrity": "sha512-h88OPkavHTiN9tMn2l5awAznGB0lXzjcLhgR1/rvjB2zlLprsNxbM2tt6OJsHUxduLC3klq0/eqaSf6fX5XVww==", + "license": "Apache-2.0", "dependencies": { - "@algolia/autocomplete-shared": "1.17.9" + "json-schema": "^0.4.0" }, - "peerDependencies": { - "search-insights": ">= 1 < 3" + "engines": { + "node": ">=18" } }, - "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.9.tgz", - "integrity": "sha512-Na1OuceSJeg8j7ZWn5ssMu/Ax3amtOwk76u4h5J4eK2Nx2KB5qt0Z4cOapCsxot9VcEN11ADV5aUSlQF4RhGjQ==", - "license": "MIT", + "node_modules/@ai-sdk/provider-utils": { + "version": "3.0.30", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.30.tgz", + "integrity": "sha512-NCJ9JKow5ENAgEZxzvEvF20thwDiH+hutvzmrUDbloRX0azpJHNst8+7pZIVryYhLM9wgpT5/ShTSjPTFhkxEQ==", + "license": "Apache-2.0", "dependencies": { - "@algolia/autocomplete-shared": "1.17.9" + "@ai-sdk/provider": "2.0.3", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" }, "peerDependencies": { - "@algolia/client-search": ">= 4.9.1 < 6", - "algoliasearch": ">= 4.9.1 < 6" + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@algolia/autocomplete-shared": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.9.tgz", - "integrity": "sha512-iDf05JDQ7I0b7JEA/9IektxN/80a2MZ1ToohfmNS3rfeuQnIKI3IJlIafD0xu4StbtQTghx9T3Maa97ytkXenQ==", + "node_modules/@algolia/abtesting": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.22.0.tgz", + "integrity": "sha512-BFR6zNowNKcY7Ou7TaJc9QWexES4YKPbmf/OTFofpdsdhz4x6q0lbxp3duO0EHnyrN7rE4ba/TSXuY+BDGu4+g==", "license": "MIT", - "peerDependencies": { - "@algolia/client-search": ">= 4.9.1 < 6", - "algoliasearch": ">= 4.9.1 < 6" + "optional": true, + "peer": true, + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/client-abtesting": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.36.0.tgz", - "integrity": "sha512-uGr57O1UqDDeZHYXr1VnUomtdgQMxb6fS8yC/LXCMOn5ucN4k6FlcCRqXQnUyiiFZNG/rVK3zpRiyomq4JWXdQ==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.56.0.tgz", + "integrity": "sha512-7r4Z3NC7yU1oAQVWJNA2HX7tX481F3pJvCGyLIXiTdBcthz4Q/o21jwcMYDFkuI92UWTNBQQmHYgwHo1zS5dzg==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.36.0.tgz", - "integrity": "sha512-/zrf0NMxcvBBQ4r9lIqM7rMt7oI7gY7bZ+bNcgpZAQMvzXbKJVla3MqKGuPC/bfOthKvAcAr0mCZ8/7GwBmkVw==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.56.0.tgz", + "integrity": "sha512-avmjXQSq+jadFO8Xl2em05/uQdQnEmHsJyOAdVbZkmVgpMfxL12aJwVVfGNwYr9nulcpuJN1X0lTaQ5wxuNGcA==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.36.0.tgz", - "integrity": "sha512-fDsg9w6xXWQyNkm/VfiWF2D9wnpTPv0fRVei7lWtz7cXJewhOmP1kKE2GaDTI4QDxVxgDkoPJ1+3UVMIzTcjjQ==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.56.0.tgz", + "integrity": "sha512-v2TPStUhY//ripPjIVclZ8AWc7DEGooXULZGFlFu37zNatgHjw34oZZ+OSbbc/YHO+xZwPl62I1k8xH1m4S2eg==", "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-insights": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.36.0.tgz", - "integrity": "sha512-x6ZICyIN3BZjja47lqlMLG+AZwfx9wrYWttd6Daxp+wX/fFGxha6gdqxeoi5J44BmFqK8CUU4u8vpwHqGOCl4g==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.56.0.tgz", + "integrity": "sha512-P0ehROpM4Sem3Sqo5x2cKPgj67D3G3jy0rh1Amwkcvsfr6tkvIcdCmerieanqTF7NxUMPNFLkpIFeMO8Rpa50w==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.36.0.tgz", - "integrity": "sha512-gnH9VHrC+/9OuaumbgxNXzzEq1AY2j3tm00ymNXNz35T7RQ2AK/x4T5b2UnjOUJejuXaSJ88gFyPk3nM5OhJZQ==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.56.0.tgz", + "integrity": "sha512-SXK3Vn3WVxyzbm31oePZBJkp1wpOyuWdd4B/Pv7n0aXDxmeSWhC1R1FC1517mMrFAIaPH4Rt0x6RUe7ZNjz8FA==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.36.0.tgz", - "integrity": "sha512-GkWIS+cAMoxsNPHEp3j7iywO9JJMVHVCWHzPPHFXIe0iNIOfsnZy5MqC1T9sifjqoU9b0GGbzzdxB3TEdwfiFA==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.56.0.tgz", + "integrity": "sha512-5+ZdX8garFnmycnZgKhtXHePEaLj5zqDxI/0lkhhluzCcvTn0/PvvTirTg8hHYetQHvn7GDyeAiqTAieMvMW4A==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.36.0.tgz", - "integrity": "sha512-MLx32nSeDSNxfx28IfvwfHEfeo3AYe9JgEj0rLeYtJGmt0W30K6tCNokxhWGUUKrggQTH6H1lnohWsoj2OC2bw==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.56.0.tgz", + "integrity": "sha512-+mKUdYvqOi0BcvpAEyCEw49vSBptufIcfibtHz2bdr1pI789M46Yt0uQEk/sxtK3teh71OQvVFHaTDzShUWewQ==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, - "node_modules/@algolia/events": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", - "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==", - "license": "MIT" - }, "node_modules/@algolia/ingestion": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.36.0.tgz", - "integrity": "sha512-6zmlPLCsyzShOsfs1G1uqxwLTojte3NLyukwyUmJFfa46DSq3wkIOE9hFtqAoV951dXp4sZd2KCFYJmgRjcYbA==", + "version": "1.56.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.56.0.tgz", + "integrity": "sha512-9g/zj+AZx5moFcdFIrYQoVrueXivjUcc3MQHtCYT8WhIuk1lUh1AyEhvJCS0XBZld09cLvd1AZ3BvDBpVpX2UA==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.36.0.tgz", - "integrity": "sha512-SjJeDqlzAKJiWhquqfDWLEu5X/PIM+5KvUH65c4LBvt8T+USOVJbijtzA9UHZ1eUIfFSDBmbzEH0YvlS6Di2mg==", + "version": "1.56.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.56.0.tgz", + "integrity": "sha512-Qf3Sr6f9A9uxCZUf3MXS0d2b877uYzEB5yxqpVGXAhcJnBCQjrRRon0KvefpGkxy+BshrIJs96OUoMtGqXTFDA==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.36.0.tgz", - "integrity": "sha512-FalJm3h9fwoZZpkkMpA0r4Grcvjk32FzmC4CXvlpyF/gBvu6pXE01yygjJBU20zGVLGsXU+Ad8nYPf+oGD7Zkg==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.56.0.tgz", + "integrity": "sha512-GXWG1rWc5wu8hY4N33Y3b6ernY6sAdAvmKWN/zHAiACOx40WnpG0TVX5YazCAr/9gOYGInSiM2A0y2jy2xbiDA==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.36.0.tgz", - "integrity": "sha512-weE9SImWIDmQrfGLb1pSPEfP3mioKQ84GaQRpUmjFxlxG/4nW2bSsmkV+kNp1s+iomL2gnxFknSmcQuuAy+kPA==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.56.0.tgz", + "integrity": "sha512-7t24cBxaInS3mZb7ddEaZT/tp6q+/aR4YttsQVyP1/i+LmwPR34atO35KjaLFCcRVrlP7sYOAqkCfg6lIRB+ew==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0" + "@algolia/client-common": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.36.0.tgz", - "integrity": "sha512-zGPI2sgzvOwCHTVMmDvc301iirOKCtJ+Egh+HQB/+DG0zTGUT1DpdwQVT25A7Yin/twnO8CkFpI/S+74FVYNjg==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.56.0.tgz", + "integrity": "sha512-R7ePHgVYmDFjZpvrsVAfbDz/d4RxKAYZ5/vgLfIsCVRZRryjWl/3INOxpOICzitehQ5FjNtNjcLQTrmHPTcHBQ==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0" + "@algolia/client-common": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.36.0.tgz", - "integrity": "sha512-dNbBGE/O6VG/6vFhv3CFm5za4rubAVrhQf/ef0YWiDqPMmalPxGEzIijw4xV1mU1JmX2ffyp/x8Kdtz24sDkOQ==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.56.0.tgz", + "integrity": "sha512-PIOUXlSnrqM0S+WOgDRb4RzotydJH7ZoT6tOyL7tAO7qJOfvX5wsEW8Pe+PMKMwvuI4/gIyK9cg2H7lJXqnc4Q==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@algolia/client-common": "5.36.0" + "@algolia/client-common": "5.56.0" }, "engines": { "node": ">= 14.0.0" } }, - "node_modules/@amplitude/analytics-browser": { - "version": "2.23.5", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.23.5.tgz", - "integrity": "sha512-R1N506rifI3/axSTM3EQkVjCgeJsmhybRONOdnA3MCJwOIC77UVEOIzTVNjnAAzgBSxDNTCy6ejGgBf3PgzBog==", + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", "license": "MIT", "dependencies": { - "@amplitude/analytics-core": "^2.22.1", - "@amplitude/analytics-remote-config": "^0.4.0", - "@amplitude/plugin-autocapture-browser": "^1.11.1", - "@amplitude/plugin-network-capture-browser": "^1.5.4", - "@amplitude/plugin-page-view-tracking-browser": "^2.3.45", - "@amplitude/plugin-web-vitals-browser": "^0.1.0-beta.20", - "tslib": "^2.4.1" + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/@amplitude/analytics-client-common": { - "version": "2.3.39", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-client-common/-/analytics-client-common-2.3.39.tgz", - "integrity": "sha512-Dt31IIalME8whTXLgnKPLh9HbHTr8dC9F51reS1gngXAkOTErzAvbBl6UIc09bjqHWmimsRYgi6nflubnqwvMQ==", + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@amplitude/analytics-connector": "^1.4.8", - "@amplitude/analytics-core": "^2.22.1", - "@amplitude/analytics-types": "^2.10.0", - "tslib": "^2.4.1" + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" } }, - "node_modules/@amplitude/analytics-connector": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.6.4.tgz", - "integrity": "sha512-SpIv0IQMNIq6SH3UqFGiaZyGSc7PBZwRdq7lvP0pBxW8i4Ny+8zwI0pV+VMfMHQwWY3wdIbWw5WQphNjpdq1/Q==", - "license": "MIT" + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true }, - "node_modules/@amplitude/analytics-core": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.22.1.tgz", - "integrity": "sha512-nzlulhS7jYQc91wOc392avBLDAiPZmIBuJ1apA640YlleX/egVxKgZVYHH3Ge4ZNkaxoESwUb4mf2R+ZI0fXxA==", + "node_modules/@astrojs/check": { + "version": "0.9.10", + "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.10.tgz", + "integrity": "sha512-zgx/UQMozdjOa3bOxjgeCFdtpE3c9rRX6xHwa+2QXvy8z8Akifu2AtubHyv/zzC2znO8dl8fFWL4K+Ba9kS8HQ==", "license": "MIT", "dependencies": { - "@amplitude/analytics-connector": "^1.6.4", - "tslib": "^2.4.1" + "@astrojs/language-server": "^2.16.7", + "chokidar": "^4.0.3", + "kleur": "^4.1.5", + "yargs": "^18.0.0" + }, + "bin": { + "astro-check": "bin/astro-check.js" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^6.0.0" } }, - "node_modules/@amplitude/analytics-remote-config": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-remote-config/-/analytics-remote-config-0.4.1.tgz", - "integrity": "sha512-BYl6kQ9qjztrCACsugpxO+foLaQIC0aSEzoXEAb/gwOzInmqkyyI+Ub+aWTBih4xgB/lhWlOcidWHAmNiTJTNw==", + "node_modules/@astrojs/check/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "license": "MIT", "dependencies": { - "@amplitude/analytics-client-common": ">=1 <3", - "@amplitude/analytics-core": ">=1 <3", - "@amplitude/analytics-types": ">=1 <3", - "tslib": "^2.4.1" + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@amplitude/analytics-types": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-2.10.0.tgz", - "integrity": "sha512-WP8eEbJh10MmFVnxkHjg92i5DBxBFsRvSZxjDQPXEGL8ZP+i7rSsleiH2K3VrwoKksYfZ/1eAqrZvevAmjSlig==", - "license": "MIT" - }, - "node_modules/@amplitude/experiment-core": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@amplitude/experiment-core/-/experiment-core-0.7.2.tgz", - "integrity": "sha512-Wc2NWvgQ+bLJLeF0A9wBSPIaw0XuqqgkPKsoNFQrmS7r5Djd56um75In05tqmVntPJZRvGKU46pAp8o5tdf4mA==", + "node_modules/@astrojs/check/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "license": "MIT", - "dependencies": { - "js-base64": "^3.7.5" + "engines": { + "node": ">=6" } }, - "node_modules/@amplitude/plugin-autocapture-browser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@amplitude/plugin-autocapture-browser/-/plugin-autocapture-browser-1.11.1.tgz", - "integrity": "sha512-6nus1nXlH1ru/yjx07yk1cyjc9scAsE9dO4f0xxH8xpHlYQ4yVCuYApcguIpogISlPiySAxSZ+4WDreLrpQiDw==", + "node_modules/@astrojs/check/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "license": "MIT", - "dependencies": { - "@amplitude/analytics-core": "^2.22.1", - "@amplitude/analytics-remote-config": "^0.6.3", - "rxjs": "^7.8.1", - "tslib": "^2.4.1" + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@amplitude/plugin-autocapture-browser/node_modules/@amplitude/analytics-remote-config": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-remote-config/-/analytics-remote-config-0.6.3.tgz", - "integrity": "sha512-icE0ogCzdHAtQi9jiOFQUmKrvWQc5YEO6bLZUfQXCT/yTTNXppWnT1zHMKzXa3SMDosfrLwU/X8sro1PTI+jZQ==", - "license": "MIT", - "dependencies": { - "@amplitude/analytics-core": ">=1 <2", - "@amplitude/analytics-types": ">=1 <2", - "tslib": "^2.4.1" - } + "node_modules/@astrojs/compiler": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.1.tgz", + "integrity": "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==", + "license": "MIT" }, - "node_modules/@amplitude/plugin-autocapture-browser/node_modules/@amplitude/analytics-remote-config/node_modules/@amplitude/analytics-core": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-1.2.8.tgz", - "integrity": "sha512-Krxpr5uvS3HmmjvpYqPfbMbs2kcZZu09L+6KwQnPiofWRzoXWIM217fRfy6aSD/QrAoPGbZjvtVitw9cB7Cx+A==", + "node_modules/@astrojs/compiler-binding": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.3.1.tgz", + "integrity": "sha512-DaAUj29AIBU2XdJ8uwcab8lW5O2pk9pY8AXkcMw0sw77nVa3oeTYRcO+Dvbbpoexf6ThMc0FMWYCQ/wN1/T7oQ==", "license": "MIT", - "dependencies": { - "@amplitude/analytics-types": "^1.4.0", - "tslib": "^2.4.1" + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@astrojs/compiler-binding-darwin-arm64": "0.3.1", + "@astrojs/compiler-binding-darwin-x64": "0.3.1", + "@astrojs/compiler-binding-linux-arm64-gnu": "0.3.1", + "@astrojs/compiler-binding-linux-arm64-musl": "0.3.1", + "@astrojs/compiler-binding-linux-x64-gnu": "0.3.1", + "@astrojs/compiler-binding-linux-x64-musl": "0.3.1", + "@astrojs/compiler-binding-wasm32-wasi": "0.3.1", + "@astrojs/compiler-binding-win32-arm64-msvc": "0.3.1", + "@astrojs/compiler-binding-win32-x64-msvc": "0.3.1" + } + }, + "node_modules/@astrojs/compiler-binding-darwin-arm64": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.3.1.tgz", + "integrity": "sha512-IEmEF2fUIlTHtpeE/isyEGVOB14cEyh/LZOFYt6wn3jNyVpdC8aR5OZ+RzFUR/f+8ZDM1LaMwZKvoA7eMyJeFw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@amplitude/plugin-autocapture-browser/node_modules/@amplitude/analytics-types": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-1.4.0.tgz", - "integrity": "sha512-RiMPHBqdrJ8ktTqG+Wzj2htnN/PCG9jGZG0SXtTFnWwVvcAJYbYm55/nrP1TTyrx1OlLhvF2VG3lVUP/xGAU8w==", - "license": "MIT" - }, - "node_modules/@amplitude/plugin-network-capture-browser": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@amplitude/plugin-network-capture-browser/-/plugin-network-capture-browser-1.5.4.tgz", - "integrity": "sha512-GRvi44tNx2TdHQ/dnC9DLqwsaBE1gC/bmHNaudTbp/nwIM8nVCAxZaXaXJEUouK7WBAamr7a3WmFruecqCeOlA==", + "node_modules/@astrojs/compiler-binding-darwin-x64": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.3.1.tgz", + "integrity": "sha512-GF2kIxjpPDLsn94zbZNMsxEmkU828QqnmM7kiQJnaooS3jmI+I7kk6+oI6EpwOsK3femCMdcm+wmOsEqtGrmjQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@amplitude/analytics-core": "^2.22.1", - "rxjs": "^7.8.1", - "tslib": "^2.4.1" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@amplitude/plugin-page-view-tracking-browser": { - "version": "2.3.45", - "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.3.45.tgz", - "integrity": "sha512-L2JH/TDTdjfexkY5hHVS3dCb4+q5H1jeIKhXUcBQ/Wx91asLY9BsH91J4bo9EK4J4Al8jVRwqJz0tIQ17qW9RQ==", + "node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.3.1.tgz", + "integrity": "sha512-XJL3SDmOtVrqFhCirNcHwE91+IesJqlgNo23I4qW9QUYfwzm/TBZuH61fgqsb1ttgR1mMYz6ooPWs0JDhwMqpQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@amplitude/analytics-client-common": "^2.3.39", - "@amplitude/analytics-types": "^2.10.0", - "tslib": "^2.4.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@amplitude/plugin-session-replay-browser": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/@amplitude/plugin-session-replay-browser/-/plugin-session-replay-browser-1.22.10.tgz", - "integrity": "sha512-E0n65/YFlz41BvarH3YXXcSdVPpXQQ9Fvx6eznhsXlrMe4yL+VSbp6iQN7o+wNMHNm+TOsIqR5YWXWAga6yKug==", + "node_modules/@astrojs/compiler-binding-linux-arm64-musl": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.3.1.tgz", + "integrity": "sha512-xqE8BVbDoBueK/B47w30PtkVofUWJKGkwoMVE+EOMLf11rnoANxIAdA9FPqY+rng4oNI5ndHGsri1yPj2k8vZQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@amplitude/analytics-client-common": "^2.3.39", - "@amplitude/analytics-core": "^2.22.1", - "@amplitude/analytics-types": "^2.10.0", - "@amplitude/session-replay-browser": "^1.28.8", - "idb-keyval": "^6.2.1", - "tslib": "^2.4.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@amplitude/plugin-web-vitals-browser": { - "version": "0.1.0-frustrationanalytics.0", - "resolved": "https://registry.npmjs.org/@amplitude/plugin-web-vitals-browser/-/plugin-web-vitals-browser-0.1.0-frustrationanalytics.0.tgz", - "integrity": "sha512-xv4sje6/D8r+SgNFTA22FJ5PhtdhN+VSydvs63Frll+qWlyQwaZ1IgDbPyqjzryEkldHRPD7GUaQual+geoIYg==", + "node_modules/@astrojs/compiler-binding-linux-x64-gnu": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.3.1.tgz", + "integrity": "sha512-1y0StU1qiCuDFH3rmbRJXcxdfHxFPrES1Rd+RLffosvUR7I2cH5SF5SFnBN9vXpzpkmyElZm3Yr47iJBPN7vVA==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@amplitude/analytics-core": "^2.14.0-frustrationanalytics.0", - "rxjs": "^7.8.1", - "tslib": "^2.4.1", - "web-vitals": "^5.0.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@amplitude/rrdom": { - "version": "2.0.0-alpha.32", - "resolved": "https://registry.npmjs.org/@amplitude/rrdom/-/rrdom-2.0.0-alpha.32.tgz", - "integrity": "sha512-FvEoclQ/wHBh9if060V1eaDexUJMUWUV1g3w7+mKfz9yO1aT0XmY+UAqE7mvaEB2GnWyIPYMlFrKTZ25JZ8z+w==", + "node_modules/@astrojs/compiler-binding-linux-x64-musl": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.3.1.tgz", + "integrity": "sha512-16q0fYf7kpbmdObZEeZJEup8hQv/whgNwVjrSvT8umrKwLDSnNIWiQpm09lQQu6bweZB0XyIvHwlPitvJhC+hg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@amplitude/rrweb-snapshot": "^2.0.0-alpha.32" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@amplitude/rrweb": { - "version": "2.0.0-alpha.32", - "resolved": "https://registry.npmjs.org/@amplitude/rrweb/-/rrweb-2.0.0-alpha.32.tgz", - "integrity": "sha512-hpQTvFTTpRcz8ZODSR7WYEe02IXE5pXdPZivFbScr6UihiXvAApr41eVDP0tEQlg+JvahOYtuf8kyU89p+NIqg==", + "node_modules/@astrojs/compiler-binding-wasm32-wasi": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.3.1.tgz", + "integrity": "sha512-cB456shIwDv/PrVT+2QG7LFndpHkVge5HjqADKZgGaAc9JHVktCtjSrcdkRQ+3tbkPazNKaTLRjXLIiz2NIx9g==", + "cpu": [ + "wasm32" + ], "license": "MIT", + "optional": true, "dependencies": { - "@amplitude/rrdom": "^2.0.0-alpha.32", - "@amplitude/rrweb-snapshot": "^2.0.0-alpha.32", - "@amplitude/rrweb-types": "^2.0.0-alpha.32", - "@amplitude/rrweb-utils": "^2.0.0-alpha.32", - "@types/css-font-loading-module": "0.0.7", - "@xstate/fsm": "^1.4.0", - "base64-arraybuffer": "^1.0.1", - "mitt": "^3.0.0" + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@amplitude/rrweb-packer": { - "version": "2.0.0-alpha.32", - "resolved": "https://registry.npmjs.org/@amplitude/rrweb-packer/-/rrweb-packer-2.0.0-alpha.32.tgz", - "integrity": "sha512-vYT0JFzle/FV9jIpEbuumCLh516az6ltAo7mrd06dlGo1tgos7bJbl3kcnvEXmDG7WWsKwip/Qprap7cZ4CmJw==", + "node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.3.1.tgz", + "integrity": "sha512-ur/9+If/yTE69mmeX5MqSZndL0HOyx67GeNZUy3N7wVdWpLz9UTJXwyWS4UR2PUQHitghjsM5xoX0Ge56WRVQQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@amplitude/rrweb-types": "^2.0.0-alpha.32", - "fflate": "^0.4.4" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@amplitude/rrweb-plugin-console-record": { - "version": "2.0.0-alpha.32", - "resolved": "https://registry.npmjs.org/@amplitude/rrweb-plugin-console-record/-/rrweb-plugin-console-record-2.0.0-alpha.32.tgz", - "integrity": "sha512-oJuBSNuBnqnrRCneW3b/pMirSz0Ubr2Ebz/t+zJhkGBgrTPNMviv8sSyyGuSn0kL4RAh/9QAG1H1hiYf9cuzgA==", + "node_modules/@astrojs/compiler-binding-win32-x64-msvc": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.3.1.tgz", + "integrity": "sha512-k0W+kDBzDkNZOqu4kElDvCOIbKw5Ut9S1WZ1Krj3KTgNuBERNKXsMMsRLLcbgfdMdbe7bTekQLshZrrvmYpmwA==", + "cpu": [ + "x64" + ], "license": "MIT", - "peerDependencies": { - "@amplitude/rrweb": "^2.0.0-alpha.32" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@amplitude/rrweb-record": { - "version": "2.0.0-alpha.32", - "resolved": "https://registry.npmjs.org/@amplitude/rrweb-record/-/rrweb-record-2.0.0-alpha.32.tgz", - "integrity": "sha512-bs5ItsPfedVNiZyIzYgtey6S6qaU90XcP4/313dcvedzBk9o+eVjBG5DDbStJnwYnSj+lB+oAWw5uc9H9ghKjQ==", + "node_modules/@astrojs/compiler-rs": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.3.1.tgz", + "integrity": "sha512-aT7xkgsbNoS6nriY5qKpbihK43slFHO41iqgHCTdOvn1ifaQxLCc5yXy+6GzAtiafoaC1zA7OwVXCXMsvUZOkg==", "license": "MIT", "dependencies": { - "@amplitude/rrweb": "^2.0.0-alpha.32", - "@amplitude/rrweb-types": "^2.0.0-alpha.32" + "@astrojs/compiler-binding": "0.3.1" + }, + "engines": { + "node": ">=22.12.0" } }, - "node_modules/@amplitude/rrweb-snapshot": { - "version": "2.0.0-alpha.32", - "resolved": "https://registry.npmjs.org/@amplitude/rrweb-snapshot/-/rrweb-snapshot-2.0.0-alpha.32.tgz", - "integrity": "sha512-7kBfo965IS0HxGsB8yMClIARGbUMMdnu+7TkKwvnWRkfBiKLGu1DbYiE6wr3dBsScpyy/orPRoLDbxGVFctaZg==", + "node_modules/@astrojs/internal-helpers": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.10.2.tgz", + "integrity": "sha512-yt7fMgPYqSM4Tmr+taTW6Per+hjJ8Pk6lA1PAcDyqzOt8HzJ6Kje5WzCxA2Sd+9wsUW7uhkLeoTMK0cXPwH9rQ==", "license": "MIT", "dependencies": { - "postcss": "^8.4.38" + "@types/hast": "^3.0.4", + "@types/mdast": "^4.0.4", + "js-yaml": "^4.3.0", + "picomatch": "^4.0.4", + "retext-smartypants": "^6.2.0", + "shiki": "^4.0.2", + "smol-toml": "^1.6.0", + "unified": "^11.0.5" } }, - "node_modules/@amplitude/rrweb-types": { - "version": "2.0.0-alpha.32", - "resolved": "https://registry.npmjs.org/@amplitude/rrweb-types/-/rrweb-types-2.0.0-alpha.32.tgz", - "integrity": "sha512-tDs8uizkG+UwE2GKjXh+gH8WhUz0C3y7WfTwrtWi1TnsVc00sXaKSUo5G2h4YF4PGK6dpnLgJBqTwrqCZ211AQ==", - "license": "MIT" - }, - "node_modules/@amplitude/rrweb-utils": { - "version": "2.0.0-alpha.32", - "resolved": "https://registry.npmjs.org/@amplitude/rrweb-utils/-/rrweb-utils-2.0.0-alpha.32.tgz", - "integrity": "sha512-DCCQjuNACkIMkdY5/KBaEgL4znRHU694ClW3RIjqFXJ6j6pqGyjEhCqtlCes+XwdgwOQKnJGMNka3J9rmrSqHg==", - "license": "MIT" - }, - "node_modules/@amplitude/session-replay-browser": { - "version": "1.28.8", - "resolved": "https://registry.npmjs.org/@amplitude/session-replay-browser/-/session-replay-browser-1.28.8.tgz", - "integrity": "sha512-Rr4kUfSMrlFtODWF89lymX6aaMlysTwArmOKJ+BXzaAXIrSz0YAoqbYKtncsRmYLQIz9hhF29ZKTOZoXYp3f7g==", + "node_modules/@astrojs/language-server": { + "version": "2.16.13", + "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.13.tgz", + "integrity": "sha512-ekOa+CYprEq5n4EJC1qTIAhLk49HZIUQuFwrEuF+3JK/pdMaYnWoREFUI2A0KEPOJiFA2kamBzKzbYljDvUxLg==", "license": "MIT", "dependencies": { - "@amplitude/analytics-client-common": "^2.3.39", - "@amplitude/analytics-core": "^2.22.1", - "@amplitude/analytics-remote-config": "^0.6.3", - "@amplitude/analytics-types": "^2.10.0", - "@amplitude/rrweb-packer": "2.0.0-alpha.32", - "@amplitude/rrweb-plugin-console-record": "2.0.0-alpha.32", - "@amplitude/rrweb-record": "2.0.0-alpha.32", - "@amplitude/rrweb-utils": "2.0.0-alpha.32", - "@amplitude/targeting": "0.2.0", - "@rollup/plugin-replace": "^6.0.1", - "idb": "8.0.0", - "tslib": "^2.4.1" + "@astrojs/compiler": "^2.13.1", + "@astrojs/yaml2ts": "^0.2.4", + "@jridgewell/sourcemap-codec": "^1.5.5", + "@volar/kit": "~2.4.28", + "@volar/language-core": "~2.4.28", + "@volar/language-server": "~2.4.28", + "@volar/language-service": "~2.4.28", + "muggle-string": "^0.4.1", + "tinyglobby": "^0.2.16", + "volar-service-css": "0.0.71", + "volar-service-emmet": "0.0.71", + "volar-service-html": "0.0.71", + "volar-service-prettier": "0.0.71", + "volar-service-typescript": "0.0.71", + "volar-service-typescript-twoslash-queries": "0.0.71", + "volar-service-yaml": "0.0.71", + "vscode-html-languageservice": "^5.6.2", + "vscode-uri": "^3.1.0" + }, + "bin": { + "astro-ls": "bin/nodeServer.js" + }, + "peerDependencies": { + "prettier": "^3.0.0", + "prettier-plugin-astro": ">=0.11.0" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + } } }, - "node_modules/@amplitude/session-replay-browser/node_modules/@amplitude/analytics-remote-config": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-remote-config/-/analytics-remote-config-0.6.3.tgz", - "integrity": "sha512-icE0ogCzdHAtQi9jiOFQUmKrvWQc5YEO6bLZUfQXCT/yTTNXppWnT1zHMKzXa3SMDosfrLwU/X8sro1PTI+jZQ==", + "node_modules/@astrojs/markdown-remark": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-7.2.2.tgz", + "integrity": "sha512-FGfmK84zSNcrsBd0dl1gXE9JvZYElp8EXQa2jpHVAxG4deGKAp43wspxFupjADJX7MSsMRHwYCnfT6EyVmgeFQ==", "license": "MIT", "dependencies": { - "@amplitude/analytics-core": ">=1 <2", - "@amplitude/analytics-types": ">=1 <2", - "tslib": "^2.4.1" - } - }, - "node_modules/@amplitude/session-replay-browser/node_modules/@amplitude/analytics-remote-config/node_modules/@amplitude/analytics-core": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-1.2.8.tgz", - "integrity": "sha512-Krxpr5uvS3HmmjvpYqPfbMbs2kcZZu09L+6KwQnPiofWRzoXWIM217fRfy6aSD/QrAoPGbZjvtVitw9cB7Cx+A==", - "license": "MIT", - "dependencies": { - "@amplitude/analytics-types": "^1.4.0", - "tslib": "^2.4.1" - } - }, - "node_modules/@amplitude/session-replay-browser/node_modules/@amplitude/analytics-remote-config/node_modules/@amplitude/analytics-types": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-1.4.0.tgz", - "integrity": "sha512-RiMPHBqdrJ8ktTqG+Wzj2htnN/PCG9jGZG0SXtTFnWwVvcAJYbYm55/nrP1TTyrx1OlLhvF2VG3lVUP/xGAU8w==", - "license": "MIT" - }, - "node_modules/@amplitude/targeting": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@amplitude/targeting/-/targeting-0.2.0.tgz", - "integrity": "sha512-/50ywTrC4hfcfJVBbh5DFbqMPPfaIOivZeb5Gb+OGM03QrA+lsUqdvtnKLNuWtceD4H6QQ2KFzPJ5aAJLyzVDA==", - "license": "MIT", - "dependencies": { - "@amplitude/analytics-client-common": ">=1 <3", - "@amplitude/analytics-core": ">=1 <3", - "@amplitude/analytics-types": ">=1 <3", - "@amplitude/experiment-core": "0.7.2", - "idb": "^8.0.0", - "tslib": "^2.4.1" + "@astrojs/internal-helpers": "0.10.2", + "@astrojs/prism": "4.0.2", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.3", + "hast-util-to-text": "^4.0.2", + "mdast-util-definitions": "^6.0.0", + "rehype-raw": "^7.0.0", + "rehype-stringify": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.1.2", + "remark-smartypants": "^3.0.2", + "unified": "^11.0.5", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.1.0", + "unist-util-visit-parents": "^6.0.2", + "vfile": "^6.0.3" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } + "node_modules/@astrojs/markdown-remark/node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" }, - "node_modules/@asamuzakjp/css-color": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", - "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", - "dev": true, + "node_modules/@astrojs/markdown-satteri": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.3.5.tgz", + "integrity": "sha512-CvWVEFAbay7YO+i9SaqDJubipA5ckiVB89QWoMJ5XC0m5CtFg8JwZ7Kau6X9sYY7FZURH0w2l03ISH2jOS/RDQ==", "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.3", - "@csstools/css-color-parser": "^3.0.9", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "lru-cache": "^10.4.3" + "@astrojs/internal-helpers": "0.10.2", + "@astrojs/prism": "4.0.2", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.3", + "satteri": "^0.9.1" } }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, + "node_modules/@astrojs/markdown-satteri/node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "license": "ISC" }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "node_modules/@astrojs/prism": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.2.tgz", + "integrity": "sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" + "prismjs": "^1.30.0" }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", - "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" + "node": ">=22.12.0" } }, - "node_modules/@babel/core": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", - "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", + "node_modules/@astrojs/react": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-6.0.2.tgz", + "integrity": "sha512-Fvv2UqS7ajFL2Yjd5s4s5PcCBCSSfks4r04rbCHZO5z4pUPwCygV2ketI+iC+1P/sdHANLV3tgDL1wjzty4cJg==", "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.3", - "@babel/parser": "^7.28.3", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" + "@astrojs/internal-helpers": "0.10.2", + "@vitejs/plugin-react": "^5.2.0", + "devalue": "^5.8.1", + "ultrahtml": "^1.6.0", + "vite": "^8.0.13" }, "engines": { - "node": ">=6.9.0" + "node": ">=22.12.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "peerDependencies": { + "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0", + "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0", + "react": "^17.0.2 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "node_modules/@astrojs/react/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, + "optional": true, + "os": [ + "aix" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "node_modules/@astrojs/react/node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.3" - }, + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "node_modules/@astrojs/react/node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": ">=18" } }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", - "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "node_modules/@astrojs/react/node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.3", - "semver": "^6.3.1" - }, + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": ">=18" } }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", - "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "node_modules/@astrojs/react/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "regexpu-core": "^6.2.0", - "semver": "^6.3.1" - }, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": ">=18" } }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "node_modules/@astrojs/react/node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" } }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "node_modules/@astrojs/react/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", - "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "node_modules/@astrojs/react/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "node_modules/@astrojs/react/node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "node_modules/@astrojs/react/node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, + "node_modules/@astrojs/react/node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "node_modules/@astrojs/react/node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "node_modules/@astrojs/react/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "node_modules/@astrojs/react/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "node_modules/@astrojs/react/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "node_modules/@astrojs/react/node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "node_modules/@astrojs/react/node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "node_modules/@astrojs/react/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", - "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "node_modules/@astrojs/react/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2" - }, + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helpers": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", - "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", + "node_modules/@astrojs/react/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2" - }, + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/parser": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", - "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", + "node_modules/@astrojs/react/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "node_modules/@astrojs/react/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "node_modules/@astrojs/react/node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "sunos" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "node_modules/@astrojs/react/node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "node_modules/@astrojs/react/node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" - }, + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", - "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "node_modules/@astrojs/react/node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "node_modules/@astrojs/react/node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "hasInstallScript": true, "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/@astrojs/react/node_modules/vite": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", + "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.17", + "rolldown": "~1.1.5", + "tinyglobby": "^0.2.17" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || >=22.12.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" }, - "engines": { - "node": ">=6.9.0" + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "node_modules/@astrojs/telemetry": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", + "integrity": "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==", "license": "MIT", + "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "ci-info": "^4.2.0", + "debug": "^4.4.0", + "dlv": "^1.1.3", + "dset": "^3.1.4", + "is-docker": "^3.0.0", + "is-wsl": "^3.1.0", + "which-pm-runs": "^1.1.0" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "18.20.8 || ^20.3.0 || >=22.0.0" } }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "node_modules/@astrojs/yaml2ts": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.4.tgz", + "integrity": "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "yaml": "^2.8.3" } }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", - "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", - "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" } }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.3.tgz", - "integrity": "sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==", + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" + "@babel/types": "^7.29.7" }, - "engines": { - "node": ">=6.9.0" + "bin": { + "parser": "bin/babel-parser.js" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { + "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", - "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1474,10 +1546,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-export-namespace-from": { + "node_modules/@babel/plugin-transform-react-jsx-source": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1489,4288 +1561,3181 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "license": "MIT" }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "node_modules/@bruits/satteri-darwin-arm64": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.9.5.tgz", + "integrity": "sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "node_modules/@bruits/satteri-darwin-x64": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.9.5.tgz", + "integrity": "sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "node_modules/@bruits/satteri-linux-arm64-gnu": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.9.5.tgz", + "integrity": "sha512-u51id17uJwNEMK9nBlICsq6U31c+XVqQueVBkwRIzZG+gMpS8TOJctt5h5Wz33Z8xnMdTd+adtACVz0yHgGuOA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "node_modules/@bruits/satteri-linux-arm64-musl": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.9.5.tgz", + "integrity": "sha512-v39HxiwGC5Rqm01HksP6+5Y+xKLPlsuVFgIgpEAo+SiQ22c+mJVhS3u7Z6ePAKdhL5NJoK1xq70kLz3L13AhpQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "node_modules/@bruits/satteri-linux-x64-gnu": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.9.5.tgz", + "integrity": "sha512-F3uO8uFp3pAP5ZGXttwvh57GS7s0lL953tnNdyI2gRyP4kOOkp6pyGojNJzCjkDvWI2Cvb9iNrKok3aqQPauAw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "node_modules/@bruits/satteri-linux-x64-musl": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.9.5.tgz", + "integrity": "sha512-bicEqglLlz++mWyADaZoP0JY20s4vDfLjaPYgQqC+NI4zZLTOOg1T4GB8aqtc822Pqji8SQBmSrTb7CrP8i08Q==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "node_modules/@bruits/satteri-wasm32-wasi": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.9.5.tgz", + "integrity": "sha512-zauAuMwfPnKPUkd4AFixRFpXdgKwP2mKgxrIIo2gJzW0/ZneF9dbHnLkojSpaBnCCp7VUL1hIi5WWZvB1CqmAQ==", + "cpu": [ + "wasm32" + ], "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "node_modules/@bruits/satteri-win32-arm64-msvc": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.9.5.tgz", + "integrity": "sha512-SrfE7NEsgZjBvU3c+RR6oQRu0ToXY5uVJEbieXEF0YTctIV2zAVlbaMjWLts074QCgh3a+XHWkR/lWh2VH2LUg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@bruits/satteri-win32-x64-msvc": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.9.5.tgz", + "integrity": "sha512-5Kw9ZAtTGS8WHizyn+CJhjjfIQrw+7jcZodpmpXJjefnO15M8UexIi6JR2E5thyvsmHyhL6ZDDMUNR4bKJPd4g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@capsizecss/unpack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.1.tgz", + "integrity": "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "fontkitten": "^1.0.3" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", - "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", + "node_modules/@chevrotain/types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", + "license": "Apache-2.0" + }, + "node_modules/@clack/core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz", + "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.0" + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">= 20.12.0" } }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "node_modules/@clack/prompts": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.7.0.tgz", + "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" + "@clack/core": "1.4.3", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">= 20.12.0" } }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "optional": true, + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, + "optional": true, + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "optional": true, + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@csstools/css-tokenizer": "^3.0.4" } }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "node_modules/@emmetio/abbreviation": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz", + "integrity": "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@emmetio/scanner": "^1.0.4" } }, - "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.27.1.tgz", - "integrity": "sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug==", + "node_modules/@emmetio/css-abbreviation": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz", + "integrity": "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@emmetio/scanner": "^1.0.4" } }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", - "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", + "node_modules/@emmetio/css-parser": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@emmetio/css-parser/-/css-parser-0.4.1.tgz", + "integrity": "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@emmetio/stream-reader": "^2.2.0", + "@emmetio/stream-reader-utils": "^0.1.0" } }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", - "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", - "license": "MIT", + "node_modules/@emmetio/html-matcher": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emmetio/html-matcher/-/html-matcher-1.3.0.tgz", + "integrity": "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==", + "license": "ISC", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@emmetio/scanner": "^1.0.0" } }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", - "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", + "node_modules/@emmetio/scanner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.4.tgz", + "integrity": "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==", + "license": "MIT" + }, + "node_modules/@emmetio/stream-reader": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz", + "integrity": "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==", + "license": "MIT" + }, + "node_modules/@emmetio/stream-reader-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@emmetio/stream-reader-utils/-/stream-reader-utils-0.1.0.tgz", + "integrity": "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==", + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-2.0.0-alpha.3.tgz", + "integrity": "sha512-AZypUeJ/yByuxyS7BlSNRDOMLMlROYtjYdIAuBmJssVz1UJDSeYxLrdizhXCFYhedC5bqd/ASy8EuNXbVVXp9g==", "license": "MIT", + "optional": true, "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@emnapi/wasi-threads": "2.0.1", + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, + "node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-2.0.1.tgz", + "integrity": "sha512-9DsSk+o5NBX0CCJT8s0EROGSGxjR/tKu6aBTaVyq+SjAEQH4XcdcRxPBRzsBLizTTJ49MJjF+jgu3qnO9GLQcQ==", "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, + "node_modules/@emnapi/runtime": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-2.0.0-alpha.3.tgz", + "integrity": "sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==", "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", - "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.3.tgz", - "integrity": "sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.3.tgz", - "integrity": "sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg==", + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "semver": "^6.3.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", - "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", - "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.0", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.0", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.3", - "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-dotall-regex": "^7.27.1", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.0", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.3", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", - "semver": "^6.3.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": ">=18" } }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/preset-react": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.27.1.tgz", - "integrity": "sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-transform-react-display-name": "^7.27.1", - "@babel/plugin-transform-react-jsx": "^7.27.1", - "@babel/plugin-transform-react-jsx-development": "^7.27.1", - "@babel/plugin-transform-react-pure-annotations": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/preset-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", - "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-typescript": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/runtime": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", - "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.3.tgz", - "integrity": "sha512-LKYxD2CIfocUFNREQ1yk+dW+8OH8CRqmgatBZYXb+XhuObO8wsDpEoCNri5bKld9cnj8xukqZjxSX8p1YiRF8Q==", - "license": "MIT", - "dependencies": { - "core-js-pure": "^3.43.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/traverse": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", - "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.3", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2", - "debug": "^4.3.1" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/types": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", - "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@codemirror/autocomplete": { - "version": "6.18.6", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz", - "integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==", - "license": "MIT", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.17.0", - "@lezer/common": "^1.0.0" + "node": ">=18" } }, - "node_modules/@codemirror/commands": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz", - "integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.4.0", - "@codemirror/view": "^6.27.0", - "@lezer/common": "^1.1.0" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@codemirror/lang-css": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz", - "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@lezer/common": "^1.0.2", - "@lezer/css": "^1.1.7" + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@codemirror/lang-html": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz", - "integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/lang-css": "^6.0.0", - "@codemirror/lang-javascript": "^6.0.0", - "@codemirror/language": "^6.4.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.17.0", - "@lezer/common": "^1.0.0", - "@lezer/css": "^1.1.0", - "@lezer/html": "^1.3.0" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@codemirror/lang-javascript": { - "version": "6.2.4", - "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz", - "integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/language": "^6.6.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.17.0", - "@lezer/common": "^1.0.0", - "@lezer/javascript": "^1.0.0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@codemirror/lang-json": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz", - "integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@lezer/json": "^1.0.0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@codemirror/lang-xml": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.1.0.tgz", - "integrity": "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==", + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/language": "^6.4.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0", - "@lezer/xml": "^1.0.0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@codemirror/lang-yaml": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.2.tgz", - "integrity": "sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw==", + "node_modules/@gerrit0/mini-shiki": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.23.0.tgz", + "integrity": "sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==", + "dev": true, "license": "MIT", "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.2.0", - "@lezer/lr": "^1.0.0", - "@lezer/yaml": "^1.0.0" + "@shikijs/engine-oniguruma": "^3.23.0", + "@shikijs/langs": "^3.23.0", + "@shikijs/themes": "^3.23.0", + "@shikijs/types": "^3.23.0", + "@shikijs/vscode-textmate": "^10.0.2" } }, - "node_modules/@codemirror/language": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz", - "integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==", + "node_modules/@hono/node-server": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.0.12.tgz", + "integrity": "sha512-eWpQYr67tqJLeaSUl0Q+TquuYfUdTibpOJlUMV2FfUP7+KqCC5TufnwnlXL6mobZBJbGAYRd7ZvEBDCbLInjhg==", "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.23.0", - "@lezer/common": "^1.1.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "style-mod": "^4.0.0" + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "hono": "^4" } }, - "node_modules/@codemirror/lint": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz", - "integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==", - "license": "MIT", + "node_modules/@iconify-json/lucide": { + "version": "1.2.120", + "resolved": "https://registry.npmjs.org/@iconify-json/lucide/-/lucide-1.2.120.tgz", + "integrity": "sha512-4ECF24fxag1n5tZlPGrbWuCGqhkwD0rvAzfCXretqQb4KEC8Y6ja3khF8qmvpR1Mk0NQDhBTRK3Fr/YoV8QyJw==", + "license": "ISC", "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.35.0", - "crelt": "^1.0.5" + "@iconify/types": "*" } }, - "node_modules/@codemirror/search": { - "version": "6.5.11", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz", - "integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==", - "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" }, - "node_modules/@codemirror/state": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", - "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", + "node_modules/@iconify/utils": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.4.tgz", + "integrity": "sha512-b1S7B1k9ohZ+iNTi2ATxbRYG9fTrJmUT0rc46bvVnNxqNRGW7dyo/vRREwyniI5IRN2RSJHDcm+s3BjWrSAjHw==", "license": "MIT", "dependencies": { - "@marijn/find-cluster-break": "^1.0.0" + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" } }, - "node_modules/@codemirror/view": { - "version": "6.38.2", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.2.tgz", - "integrity": "sha512-bTWAJxL6EOFLPzTx+O5P5xAO3gTqpatQ2b/ARQ8itfU/v2LlpS3pH2fkL0A3E/Fx8Y2St2KES7ZEV0sHTsSW/A==", + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.5.0", - "crelt": "^1.0.6", - "style-mod": "^4.1.0", - "w3c-keyname": "^2.2.4" + "optional": true, + "engines": { + "node": ">=18" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "license": "MIT", + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.1.90" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, - "node_modules/@csstools/cascade-layer-name-parser": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.5.tgz", - "integrity": "sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" ], - "license": "MIT", "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, - "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" ], - "license": "MIT-0", - "engines": { - "node": ">=18" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" ], - "license": "MIT", - "engines": { - "node": ">=18" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/media-query-list-parser": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", - "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/postcss-alpha-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-alpha-function/-/postcss-alpha-function-1.0.0.tgz", - "integrity": "sha512-r2L8KNg5Wriq5n8IUQcjzy2Rh37J5YjzP9iOyHZL5fxdWYHB08vqykHQa4wAzN/tXwDuCHnhQDGCtxfS76xn7g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/postcss-cascade-layers": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.2.tgz", - "integrity": "sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" ], - "license": "MIT-0", - "dependencies": { - "@csstools/selector-specificity": "^5.0.0", - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", - "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss-selector-parser": "^7.0.0" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/postcss-color-function": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.11.tgz", - "integrity": "sha512-AtH22zLHTLm64HLdpv5EedT/zmYTm1MtdQbQhRZXxEB6iYtS6SrS1jLX3TcmUWMFzpumK/OVylCm3HcLms4slw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" } }, - "node_modules/@csstools/postcss-color-function-display-p3-linear": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function-display-p3-linear/-/postcss-color-function-display-p3-linear-1.0.0.tgz", - "integrity": "sha512-7q+OuUqfowRrP84m/Jl0wv3pfCQyUTCW5MxDIux+/yty5IkUUHOTigCjrC0Fjy3OT0ncGLudHbfLWmP7E1arNA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" } }, - "node_modules/@csstools/postcss-color-mix-function": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.11.tgz", - "integrity": "sha512-cQpXBelpTx0YhScZM5Ve0jDCA4RzwFc7oNafzZOGgCHt/GQVYiU8Vevz9QJcwy/W0Pyi/BneY+KMjz23lI9r+Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" } }, - "node_modules/@csstools/postcss-color-mix-variadic-function-arguments": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-variadic-function-arguments/-/postcss-color-mix-variadic-function-arguments-1.0.1.tgz", - "integrity": "sha512-c7hyBtbF+jlHIcUGVdWY06bHICgguV9ypfcELU3eU3W/9fiz2dxM8PqxQk2ndXYTzLnwPvNNqu1yCmQ++N6Dcg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" } }, - "node_modules/@csstools/postcss-content-alt-text": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.7.tgz", - "integrity": "sha512-cq/zWaEkpcg3RttJ5+GdNwk26NwxY5KgqgtNL777Fdd28AVGHxuBvqmK4Jq4oKhW1NX4M2LbgYAVVN0NZ+/XYQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" } }, - "node_modules/@csstools/postcss-exponential-functions": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.9.tgz", - "integrity": "sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" } }, - "node_modules/@csstools/postcss-font-format-keywords": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz", - "integrity": "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" ], - "license": "MIT-0", - "dependencies": { - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" - }, "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" } }, - "node_modules/@csstools/postcss-gamut-mapping": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.11.tgz", - "integrity": "sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" } }, - "node_modules/@csstools/postcss-gradients-interpolation-method": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.11.tgz", - "integrity": "sha512-8M3mcNTL3cGIJXDnvrJ2oWEcKi3zyw7NeYheFKePUlBmLYm1gkw9Rr/BA7lFONrOPeQA3yeMPldrrws6lqHrug==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" ], - "license": "MIT-0", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" + "@emnapi/runtime": "^1.7.0" }, "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/postcss-hwb-function": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.11.tgz", - "integrity": "sha512-9meZbsVWTZkWsSBazQips3cHUOT29a/UAwFz0AMEXukvpIGGDR9+GMl3nIckWO5sPImsadu4F5Zy+zjt8QgCdA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@img/sharp-wasm32/node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "tslib": "^2.4.0" } }, - "node_modules/@csstools/postcss-ic-unit": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.3.tgz", - "integrity": "sha512-RtYYm2qUIu9vAaHB0cC8rQGlOCQAUgEc2tMr7ewlGXYipBQKjoWmyVArqsk7SEr8N3tErq6P6UOJT3amaVof5Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" ], - "license": "MIT-0", - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" - }, "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/postcss-initial": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.1.tgz", - "integrity": "sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" ], - "license": "MIT-0", "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@csstools/postcss-is-pseudo-class": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.3.tgz", - "integrity": "sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" ], - "license": "MIT-0", - "dependencies": { - "@csstools/selector-specificity": "^5.0.0", - "postcss-selector-parser": "^7.0.0" + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" } }, - "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", - "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" }, - "peerDependencies": { - "postcss-selector-parser": "^7.0.0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@csstools/postcss-light-dark-function": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.10.tgz", - "integrity": "sha512-g7Lwb294lSoNnyrwcqoooh9fTAp47rRNo+ILg7SLRSMU3K9ePIwRt566sNx+pehiCelv4E1ICaU1EwLQuyF2qw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@csstools/postcss-logical-float-and-clear": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz", - "integrity": "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=6.0.0" } }, - "node_modules/@csstools/postcss-logical-overflow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz", - "integrity": "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@csstools/postcss-logical-overscroll-behavior": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz", - "integrity": "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@csstools/postcss-logical-resize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz", - "integrity": "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@mapbox/node-pre-gyp": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.3.tgz", + "integrity": "sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==", + "license": "BSD-3-Clause", "dependencies": { - "postcss-value-parser": "^4.2.0" + "consola": "^3.2.3", + "detect-libc": "^2.0.0", + "https-proxy-agent": "^7.0.5", + "node-fetch": "^2.6.7", + "nopt": "^8.0.0", + "semver": "^7.5.3", + "tar": "^7.4.0" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" }, "engines": { "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" } }, - "node_modules/@csstools/postcss-logical-viewport-units": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.4.tgz", - "integrity": "sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", + "license": "MIT", "dependencies": { - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@csstools/postcss-media-minmax": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.9.tgz", - "integrity": "sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@mermaid-js/parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.2.0.tgz", + "integrity": "sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==", "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/media-query-list-parser": "^4.0.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "@chevrotain/types": "~11.1.2" } }, - "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.5.tgz", - "integrity": "sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", + "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", + "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/media-query-list-parser": "^4.0.3" + "@hono/node-server": "^1.19.9 || ^2.0.5", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" }, "engines": { "node": ">=18" }, "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-nested-calc": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz", - "integrity": "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "zod": { + "optional": false } - ], - "license": "MIT-0", + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.0.tgz", + "integrity": "sha512-kDoONqMa+VnZ4vvvu/ZUurpJ4gkZU57e7g69qpNgWhYcZFPUHZM2CEMKm+cG6ufDVALbjMvfmMjFVqaK7uEMnA==", + "license": "MIT", + "optional": true, "dependencies": { - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" + "@tybys/wasm-util": "^0.10.3" }, "engines": { - "node": ">=18" + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "postcss": "^8.4" + "@emnapi/core": "^2.0.0-alpha.3", + "@emnapi/runtime": "^2.0.0-alpha.3" } }, - "node_modules/@csstools/postcss-normalize-display-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz", - "integrity": "sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "node_modules/@next/env": { + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.10.tgz", + "integrity": "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==", + "license": "MIT" }, - "node_modules/@csstools/postcss-oklab-function": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.11.tgz", - "integrity": "sha512-9f03ZGxZ2VmSCrM4SDXlAYP+Xpu4VFzemfQUQFL9OYxAbpvDy0FjDipZ0i8So1pgs8VIbQI0bNjFWgfdpGw8ig==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">= 8" } }, - "node_modules/@csstools/postcss-progressive-custom-properties": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.2.0.tgz", - "integrity": "sha512-fWCXRasX17N1NCPTCuwC3FJDV+Wc031f16cFuuMEfIsYJ1q5ABCa59W0C6VeMGqjNv6ldf37vvwXXAeaZjD9PA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">= 8" } }, - "node_modules/@csstools/postcss-random-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-2.0.1.tgz", - "integrity": "sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">= 8" } }, - "node_modules/@csstools/postcss-relative-color-syntax": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.11.tgz", - "integrity": "sha512-oQ5fZvkcBrWR+k6arHXk0F8FlkmD4IxM+rcGDLWrF2f31tWyEM3lSraeWAV0f7BGH6LIrqmyU3+Qo/1acfoJng==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=8.0.0" } }, - "node_modules/@csstools/postcss-scope-pseudo-class": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz", - "integrity": "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, + "node_modules/@orama/orama": { + "version": "3.1.18", + "resolved": "https://registry.npmjs.org/@orama/orama/-/orama-3.1.18.tgz", + "integrity": "sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA==", + "license": "Apache-2.0", "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">= 20.0.0" } }, - "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT" + }, + "node_modules/@oxc-project/types": { + "version": "0.139.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@csstools/postcss-sign-functions": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.4.tgz", - "integrity": "sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@pagefind/darwin-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.5.2.tgz", + "integrity": "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==", + "cpu": [ + "arm64" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@csstools/postcss-stepped-value-functions": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.9.tgz", - "integrity": "sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@pagefind/darwin-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.5.2.tgz", + "integrity": "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==", + "cpu": [ + "x64" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@csstools/postcss-text-decoration-shorthand": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.3.tgz", - "integrity": "sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@pagefind/freebsd-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.5.2.tgz", + "integrity": "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==", + "cpu": [ + "x64" ], - "license": "MIT-0", - "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@csstools/postcss-trigonometric-functions": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.9.tgz", - "integrity": "sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@pagefind/linux-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.5.2.tgz", + "integrity": "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==", + "cpu": [ + "arm64" ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@csstools/postcss-unset-value": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz", - "integrity": "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@pagefind/linux-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.5.2.tgz", + "integrity": "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==", + "cpu": [ + "x64" ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@csstools/utilities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz", - "integrity": "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } + "node_modules/@pagefind/windows-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/windows-arm64/-/windows-arm64-1.5.2.tgz", + "integrity": "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==", + "cpu": [ + "arm64" ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@docsearch/css": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.9.0.tgz", - "integrity": "sha512-cQbnVbq0rrBwNAKegIac/t6a8nWoUAn8frnkLFW6YARaRmAQr5/Eoe6Ln2fqkUCZ40KpdrKbpSAmgrkviOxuWA==", - "license": "MIT" + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@docsearch/react": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.9.0.tgz", - "integrity": "sha512-mb5FOZYZIkRQ6s/NWnM98k879vu5pscWqTLubLFBO87igYYT4VzVazh4h5o/zCvTIZgEt3PvsCOMOswOUo9yHQ==", + "node_modules/@pagefind/windows-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.5.2.tgz", + "integrity": "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@algolia/autocomplete-core": "1.17.9", - "@algolia/autocomplete-preset-algolia": "1.17.9", - "@docsearch/css": "3.9.0", - "algoliasearch": "^5.14.2" - }, - "peerDependencies": { - "@types/react": ">= 16.8.0 < 20.0.0", - "react": ">= 16.8.0 < 20.0.0", - "react-dom": ">= 16.8.0 < 20.0.0", - "search-insights": ">= 1 < 3" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "search-insights": { - "optional": true - } - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@docusaurus/babel": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.8.1.tgz", - "integrity": "sha512-3brkJrml8vUbn9aeoZUlJfsI/GqyFcDgQJwQkmBtclJgWDEQBKKeagZfOgx0WfUQhagL1sQLNW0iBdxnI863Uw==", + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "hasInstallScript": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@babel/core": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.25.9", - "@babel/preset-env": "^7.25.9", - "@babel/preset-react": "^7.25.9", - "@babel/preset-typescript": "^7.25.9", - "@babel/runtime": "^7.25.9", - "@babel/runtime-corejs3": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@docusaurus/logger": "3.8.1", - "@docusaurus/utils": "3.8.1", - "babel-plugin-dynamic-import-node": "^2.3.3", - "fs-extra": "^11.1.1", - "tslib": "^2.6.0" + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" }, "engines": { - "node": ">=18.0" - } - }, - "node_modules/@docusaurus/bundler": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.8.1.tgz", - "integrity": "sha512-/z4V0FRoQ0GuSLToNjOSGsk6m2lQUG4FRn8goOVoZSRsTrU8YR2aJacX5K3RG18EaX9b+52pN4m1sL3MQZVsQA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.9", - "@docusaurus/babel": "3.8.1", - "@docusaurus/cssnano-preset": "3.8.1", - "@docusaurus/logger": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils": "3.8.1", - "babel-loader": "^9.2.1", - "clean-css": "^5.3.3", - "copy-webpack-plugin": "^11.0.0", - "css-loader": "^6.11.0", - "css-minimizer-webpack-plugin": "^5.0.1", - "cssnano": "^6.1.2", - "file-loader": "^6.2.0", - "html-minifier-terser": "^7.2.0", - "mini-css-extract-plugin": "^2.9.2", - "null-loader": "^4.0.1", - "postcss": "^8.5.4", - "postcss-loader": "^7.3.4", - "postcss-preset-env": "^10.2.1", - "terser-webpack-plugin": "^5.3.9", - "tslib": "^2.6.0", - "url-loader": "^4.1.1", - "webpack": "^5.95.0", - "webpackbar": "^6.0.1" - }, - "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "@docusaurus/faster": "*" - }, - "peerDependenciesMeta": { - "@docusaurus/faster": { - "optional": true - } - } - }, - "node_modules/@docusaurus/core": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.8.1.tgz", - "integrity": "sha512-ENB01IyQSqI2FLtOzqSI3qxG2B/jP4gQPahl2C3XReiLebcVh5B5cB9KYFvdoOqOWPyr5gXK4sjgTKv7peXCrA==", - "license": "MIT", - "dependencies": { - "@docusaurus/babel": "3.8.1", - "@docusaurus/bundler": "3.8.1", - "@docusaurus/logger": "3.8.1", - "@docusaurus/mdx-loader": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-common": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "boxen": "^6.2.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "cli-table3": "^0.6.3", - "combine-promises": "^1.1.0", - "commander": "^5.1.0", - "core-js": "^3.31.1", - "detect-port": "^1.5.1", - "escape-html": "^1.0.3", - "eta": "^2.2.0", - "eval": "^0.1.8", - "execa": "5.1.1", - "fs-extra": "^11.1.1", - "html-tags": "^3.3.1", - "html-webpack-plugin": "^5.6.0", - "leven": "^3.1.0", - "lodash": "^4.17.21", - "open": "^8.4.0", - "p-map": "^4.0.0", - "prompts": "^2.4.2", - "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", - "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", - "react-loadable-ssr-addon-v5-slorber": "^1.0.1", - "react-router": "^5.3.4", - "react-router-config": "^5.1.1", - "react-router-dom": "^5.3.4", - "semver": "^7.5.4", - "serve-handler": "^6.1.6", - "tinypool": "^1.0.2", - "tslib": "^2.6.0", - "update-notifier": "^6.0.2", - "webpack": "^5.95.0", - "webpack-bundle-analyzer": "^4.10.2", - "webpack-dev-server": "^4.15.2", - "webpack-merge": "^6.0.1" - }, - "bin": { - "docusaurus": "bin/docusaurus.mjs" + "node": ">= 10.0.0" }, - "engines": { - "node": ">=18.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, - "peerDependencies": { - "@mdx-js/react": "^3.0.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" } }, - "node_modules/@docusaurus/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=8" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=10" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=8" - } - }, - "node_modules/@docusaurus/cssnano-preset": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.8.1.tgz", - "integrity": "sha512-G7WyR2N6SpyUotqhGznERBK+x84uyhfMQM2MmDLs88bw4Flom6TY46HzkRkSEzaP9j80MbTN8naiL1fR17WQug==", - "license": "MIT", - "dependencies": { - "cssnano-preset-advanced": "^6.1.2", - "postcss": "^8.5.4", - "postcss-sort-media-queries": "^5.2.0", - "tslib": "^2.6.0" + "node": ">= 10.0.0" }, - "engines": { - "node": ">=18.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/faster": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/faster/-/faster-3.8.1.tgz", - "integrity": "sha512-XYrj3qnTm+o2d5ih5drCq9s63GJoM8vZ26WbLG5FZhURsNxTSXgHJcx11Qo7nWPUStCQkuqk1HvItzscCUnd4A==", - "devOptional": true, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/types": "3.8.1", - "@rspack/core": "^1.3.15", - "@swc/core": "^1.7.39", - "@swc/html": "^1.7.39", - "browserslist": "^4.24.2", - "lightningcss": "^1.27.0", - "swc-loader": "^0.2.6", - "tslib": "^2.6.0", - "webpack": "^5.95.0" - }, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "@docusaurus/types": "*" - } - }, - "node_modules/@docusaurus/logger": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.8.1.tgz", - "integrity": "sha512-2wjeGDhKcExEmjX8k1N/MRDiPKXGF2Pg+df/bDDPnnJWHXnVEZxXj80d6jcxp1Gpnksl0hF8t/ZQw9elqj2+ww==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2", - "tslib": "^2.6.0" + "node": ">= 10.0.0" }, - "engines": { - "node": ">=18.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/logger/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=8" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/logger/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=10" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/logger/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=8" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/mdx-loader": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.8.1.tgz", - "integrity": "sha512-DZRhagSFRcEq1cUtBMo4TKxSNo/W6/s44yhr8X+eoXqCLycFQUylebOMPseHi5tc4fkGJqwqpWJLz6JStU9L4w==", + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/logger": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "@mdx-js/mdx": "^3.0.0", - "@slorber/remark-comment": "^1.0.0", - "escape-html": "^1.0.3", - "estree-util-value-to-estree": "^3.0.1", - "file-loader": "^6.2.0", - "fs-extra": "^11.1.1", - "image-size": "^2.0.2", - "mdast-util-mdx": "^3.0.0", - "mdast-util-to-string": "^4.0.0", - "rehype-raw": "^7.0.0", - "remark-directive": "^3.0.0", - "remark-emoji": "^4.0.0", - "remark-frontmatter": "^5.0.0", - "remark-gfm": "^4.0.0", - "stringify-object": "^3.3.0", - "tslib": "^2.6.0", - "unified": "^11.0.3", - "unist-util-visit": "^5.0.0", - "url-loader": "^4.1.1", - "vfile": "^6.0.1", - "webpack": "^5.88.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=18.0" + "node": ">= 10.0.0" }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/module-type-aliases": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.8.1.tgz", - "integrity": "sha512-6xhvAJiXzsaq3JdosS7wbRt/PwEPWHr9eM4YNYqVlbgG1hSK3uQDXTVvQktasp3VO6BmfYWPozueLWuj4gB+vg==", + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/types": "3.8.1", - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router-config": "*", - "@types/react-router-dom": "*", - "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", - "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" }, - "peerDependencies": { - "react": "*", - "react-dom": "*" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/plugin-client-redirects": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.8.1.tgz", - "integrity": "sha512-F+86R7PBn6VNgy/Ux8w3ZRypJGJEzksbejQKlbTC8u6uhBUhfdXWkDp6qdOisIoW0buY5nLqucvZt1zNJzhJhA==", + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/logger": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-common": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "eta": "^2.2.0", - "fs-extra": "^11.1.1", - "lodash": "^4.17.21", - "tslib": "^2.6.0" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=18.0" + "node": ">= 10.0.0" }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/plugin-content-blog": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.8.1.tgz", - "integrity": "sha512-vNTpMmlvNP9n3hGEcgPaXyvTljanAKIUkuG9URQ1DeuDup0OR7Ltvoc8yrmH+iMZJbcQGhUJF+WjHLwuk8HSdw==", - "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/logger": "3.8.1", - "@docusaurus/mdx-loader": "3.8.1", - "@docusaurus/theme-common": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-common": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "cheerio": "1.0.0-rc.12", - "feed": "^4.2.2", - "fs-extra": "^11.1.1", - "lodash": "^4.17.21", - "schema-dts": "^1.1.2", - "srcset": "^4.0.0", - "tslib": "^2.6.0", - "unist-util-visit": "^5.0.0", - "utility-types": "^3.10.0", - "webpack": "^5.88.1" - }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=18.0" + "node": ">= 10.0.0" }, - "peerDependencies": { - "@docusaurus/plugin-content-docs": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/plugin-content-docs": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.8.1.tgz", - "integrity": "sha512-oByRkSZzeGNQByCMaX+kif5Nl2vmtj2IHQI2fWjCfCootsdKZDPFLonhIp5s3IGJO7PLUfe0POyw0Xh/RrGXJA==", - "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/logger": "3.8.1", - "@docusaurus/mdx-loader": "3.8.1", - "@docusaurus/module-type-aliases": "3.8.1", - "@docusaurus/theme-common": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-common": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "@types/react-router-config": "^5.0.7", - "combine-promises": "^1.1.0", - "fs-extra": "^11.1.1", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "schema-dts": "^1.1.2", - "tslib": "^2.6.0", - "utility-types": "^3.10.0", - "webpack": "^5.88.1" - }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=18.0" + "node": ">= 10.0.0" }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/plugin-content-pages": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.8.1.tgz", - "integrity": "sha512-a+V6MS2cIu37E/m7nDJn3dcxpvXb6TvgdNI22vJX8iUTp8eoMoPa0VArEbWvCxMY/xdC26WzNv4wZ6y0iIni/w==", + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/mdx-loader": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "fs-extra": "^11.1.1", - "tslib": "^2.6.0", - "webpack": "^5.88.1" - }, + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=18.0" + "node": ">= 10.0.0" }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@docusaurus/plugin-css-cascade-layers": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.8.1.tgz", - "integrity": "sha512-VQ47xRxfNKjHS5ItzaVXpxeTm7/wJLFMOPo1BkmoMG4Cuz4nuI+Hs62+RMk1OqVog68Swz66xVPK8g9XTrBKRw==", - "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "tslib": "^2.6.0" + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "bin": { + "detect-libc": "bin/detect-libc.js" }, "engines": { - "node": ">=18.0" + "node": ">=0.10" } }, - "node_modules/@docusaurus/plugin-debug": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.8.1.tgz", - "integrity": "sha512-nT3lN7TV5bi5hKMB7FK8gCffFTBSsBsAfV84/v293qAmnHOyg1nr9okEw8AiwcO3bl9vije5nsUvP0aRl2lpaw==", - "license": "MIT", + "node_modules/@pierre/diffs": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@pierre/diffs/-/diffs-1.2.12.tgz", + "integrity": "sha512-pY/gmgWL03WnagqCyCnBi3QtRXUv4hCIY6FYqd5b1ZGaoI6a4Bsji8j+yRl2RfzPh/8Hf19rCl1GE80G6a1cLQ==", + "license": "apache-2.0", "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils": "3.8.1", - "fs-extra": "^11.1.1", - "react-json-view-lite": "^2.3.0", - "tslib": "^2.6.0" - }, - "engines": { - "node": ">=18.0" + "@pierre/theme": "1.1.0", + "@pierre/theming": "0.0.2", + "@shikijs/transformers": "^3.0.0 || ^4.0.0", + "diff": "9.0.0", + "hast-util-to-html": "9.0.5", + "lru_map": "0.4.1", + "shiki": "^3.0.0 || ^4.0.0" }, "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "react": "^18.3.1 || ^19.0.0", + "react-dom": "^18.3.1 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-google-analytics": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.8.1.tgz", - "integrity": "sha512-Hrb/PurOJsmwHAsfMDH6oVpahkEGsx7F8CWMjyP/dw1qjqmdS9rcV1nYCGlM8nOtD3Wk/eaThzUB5TSZsGz+7Q==", + "node_modules/@pierre/theme": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pierre/theme/-/theme-1.1.0.tgz", + "integrity": "sha512-GC2OWTAfTIIWWYhPCygwG8t2EtePQkRfON4MI2rwIkJylmiyqIttJID2dCL8sUD8cNdEvYkEyfEHHKMeCiDLoQ==", "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "tslib": "^2.6.0" - }, "engines": { - "node": ">=18.0" - }, + "vscode": "^1.0.0" + } + }, + "node_modules/@pierre/theming": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@pierre/theming/-/theming-0.0.2.tgz", + "integrity": "sha512-QM1M4stXfnzfaE8I8YbjXSApV8c+2dBsXJj8eYg9WTpBR/cTmCZIcfGnN4p13iRrYu2Br/R/OJfEL7uR8Qjctw==", + "license": "apache-2.0", "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "@pierre/theme": "^1.1.0", + "@shikijs/themes": "^3.0.0 || ^4.0.0", + "react": "^18.3.1 || ^19.0.0", + "react-dom": "^18.3.1 || ^19.0.0", + "shiki": "^3.0.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "@pierre/theme": { + "optional": true + }, + "@shikijs/themes": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "shiki": { + "optional": true + } } }, - "node_modules/@docusaurus/plugin-google-gtag": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.8.1.tgz", - "integrity": "sha512-tKE8j1cEZCh8KZa4aa80zpSTxsC2/ZYqjx6AAfd8uA8VHZVw79+7OTEP2PoWi0uL5/1Is0LF5Vwxd+1fz5HlKg==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", + "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "@types/gtag.js": "^0.0.12", - "tslib": "^2.6.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/plugin-google-tag-manager": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.8.1.tgz", - "integrity": "sha512-iqe3XKITBquZq+6UAXdb1vI0fPY5iIOitVjPQ581R1ZKpHr0qe+V6gVOrrcOHixPDD/BUKdYwkxFjpNiEN+vBw==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", + "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "tslib": "^2.6.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/plugin-sitemap": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.8.1.tgz", - "integrity": "sha512-+9YV/7VLbGTq8qNkjiugIelmfUEVkTyLe6X8bWq7K5qPvGXAjno27QAfFq63mYfFFbJc7z+pudL63acprbqGzw==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", + "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/logger": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-common": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "fs-extra": "^11.1.1", - "sitemap": "^7.1.1", - "tslib": "^2.6.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/plugin-svgr": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.8.1.tgz", - "integrity": "sha512-rW0LWMDsdlsgowVwqiMb/7tANDodpy1wWPwCcamvhY7OECReN3feoFwLjd/U4tKjNY3encj0AJSTxJA+Fpe+Gw==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", + "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "@svgr/core": "8.1.0", - "@svgr/webpack": "^8.1.0", - "tslib": "^2.6.0", - "webpack": "^5.88.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/preset-classic": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.8.1.tgz", - "integrity": "sha512-yJSjYNHXD8POMGc2mKQuj3ApPrN+eG0rO1UPgSx7jySpYU+n4WjBikbrA2ue5ad9A7aouEtMWUoiSRXTH/g7KQ==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", + "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/plugin-content-blog": "3.8.1", - "@docusaurus/plugin-content-docs": "3.8.1", - "@docusaurus/plugin-content-pages": "3.8.1", - "@docusaurus/plugin-css-cascade-layers": "3.8.1", - "@docusaurus/plugin-debug": "3.8.1", - "@docusaurus/plugin-google-analytics": "3.8.1", - "@docusaurus/plugin-google-gtag": "3.8.1", - "@docusaurus/plugin-google-tag-manager": "3.8.1", - "@docusaurus/plugin-sitemap": "3.8.1", - "@docusaurus/plugin-svgr": "3.8.1", - "@docusaurus/theme-classic": "3.8.1", - "@docusaurus/theme-common": "3.8.1", - "@docusaurus/theme-search-algolia": "3.8.1", - "@docusaurus/types": "3.8.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/theme-classic": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.8.1.tgz", - "integrity": "sha512-bqDUCNqXeYypMCsE1VcTXSI1QuO4KXfx8Cvl6rYfY0bhhqN6d2WZlRkyLg/p6pm+DzvanqHOyYlqdPyP0iz+iw==", - "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.8.1", - "@docusaurus/logger": "3.8.1", - "@docusaurus/mdx-loader": "3.8.1", - "@docusaurus/module-type-aliases": "3.8.1", - "@docusaurus/plugin-content-blog": "3.8.1", - "@docusaurus/plugin-content-docs": "3.8.1", - "@docusaurus/plugin-content-pages": "3.8.1", - "@docusaurus/theme-common": "3.8.1", - "@docusaurus/theme-translations": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-common": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "@mdx-js/react": "^3.0.0", - "clsx": "^2.0.0", - "copy-text-to-clipboard": "^3.2.0", - "infima": "0.2.0-alpha.45", - "lodash": "^4.17.21", - "nprogress": "^0.2.0", - "postcss": "^8.5.4", - "prism-react-renderer": "^2.3.0", - "prismjs": "^1.29.0", - "react-router-dom": "^5.3.4", - "rtlcss": "^4.1.0", - "tslib": "^2.6.0", - "utility-types": "^3.10.0" - }, - "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - } - }, - "node_modules/@docusaurus/theme-common": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.8.1.tgz", - "integrity": "sha512-UswMOyTnPEVRvN5Qzbo+l8k4xrd5fTFu2VPPfD6FcW/6qUtVLmJTQCktbAL3KJ0BVXGm5aJXz/ZrzqFuZERGPw==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", + "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/mdx-loader": "3.8.1", - "@docusaurus/module-type-aliases": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-common": "3.8.1", - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router-config": "*", - "clsx": "^2.0.0", - "parse-numeric-range": "^1.3.0", - "prism-react-renderer": "^2.3.0", - "tslib": "^2.6.0", - "utility-types": "^3.10.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "@docusaurus/plugin-content-docs": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - } - }, - "node_modules/@docusaurus/theme-search-algolia": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.8.1.tgz", - "integrity": "sha512-NBFH5rZVQRAQM087aYSRKQ9yGEK9eHd+xOxQjqNpxMiV85OhJDD4ZGz6YJIod26Fbooy54UWVdzNU0TFeUUUzQ==", - "license": "MIT", - "dependencies": { - "@docsearch/react": "^3.9.0", - "@docusaurus/core": "3.8.1", - "@docusaurus/logger": "3.8.1", - "@docusaurus/plugin-content-docs": "3.8.1", - "@docusaurus/theme-common": "3.8.1", - "@docusaurus/theme-translations": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-validation": "3.8.1", - "algoliasearch": "^5.17.1", - "algoliasearch-helper": "^3.22.6", - "clsx": "^2.0.0", - "eta": "^2.2.0", - "fs-extra": "^11.1.1", - "lodash": "^4.17.21", - "tslib": "^2.6.0", - "utility-types": "^3.10.0" - }, - "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/theme-translations": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.8.1.tgz", - "integrity": "sha512-OTp6eebuMcf2rJt4bqnvuwmm3NVXfzfYejL+u/Y1qwKhZPrjPoKWfk1CbOP5xH5ZOPkiAsx4dHdQBRJszK3z2g==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", + "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "fs-extra": "^11.1.1", - "tslib": "^2.6.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/tsconfig": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.8.1.tgz", - "integrity": "sha512-XBWCcqhRHhkhfolnSolNL+N7gj3HVE3CoZVqnVjfsMzCoOsuQw2iCLxVVHtO+rePUUfouVZHURDgmqIySsF66A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@docusaurus/types": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.8.1.tgz", - "integrity": "sha512-ZPdW5AB+pBjiVrcLuw3dOS6BFlrG0XkS2lDGsj8TizcnREQg3J8cjsgfDviszOk4CweNfwo1AEELJkYaMUuOPg==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", + "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "@mdx-js/mdx": "^3.0.0", - "@types/history": "^4.7.11", - "@types/react": "*", - "commander": "^5.1.0", - "joi": "^17.9.2", - "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", - "utility-types": "^3.10.0", - "webpack": "^5.95.0", - "webpack-merge": "^5.9.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/types/node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", + "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", + "cpu": [ + "s390x" + ], "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/utils": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.8.1.tgz", - "integrity": "sha512-P1ml0nvOmEFdmu0smSXOqTS1sxU5tqvnc0dA4MTKV39kye+bhQnjkIKEE18fNOvxjyB86k8esoCIFM3x4RykOQ==", - "license": "MIT", - "dependencies": { - "@docusaurus/logger": "3.8.1", - "@docusaurus/types": "3.8.1", - "@docusaurus/utils-common": "3.8.1", - "escape-string-regexp": "^4.0.0", - "execa": "5.1.1", - "file-loader": "^6.2.0", - "fs-extra": "^11.1.1", - "github-slugger": "^1.5.0", - "globby": "^11.1.0", - "gray-matter": "^4.0.3", - "jiti": "^1.20.0", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "micromatch": "^4.0.5", - "p-queue": "^6.6.2", - "prompts": "^2.4.2", - "resolve-pathname": "^3.0.0", - "tslib": "^2.6.0", - "url-loader": "^4.1.1", - "utility-types": "^3.10.0", - "webpack": "^5.88.1" - }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", + "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/utils-common": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.8.1.tgz", - "integrity": "sha512-zTZiDlvpvoJIrQEEd71c154DkcriBecm4z94OzEE9kz7ikS3J+iSlABhFXM45mZ0eN5pVqqr7cs60+ZlYLewtg==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", + "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/types": "3.8.1", - "tslib": "^2.6.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@docusaurus/utils-validation": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.8.1.tgz", - "integrity": "sha512-gs5bXIccxzEbyVecvxg6upTwaUbfa0KMmTj7HhHzc016AGyxH2o73k1/aOD0IFrdCsfJNt37MqNI47s2MgRZMA==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", + "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@docusaurus/logger": "3.8.1", - "@docusaurus/utils": "3.8.1", - "@docusaurus/utils-common": "3.8.1", - "fs-extra": "^11.2.0", - "joi": "^17.9.2", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "tslib": "^2.6.0" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=18.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@emnapi/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", - "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", - "dev": true, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", + "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", + "cpu": [ + "wasm32" + ], "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.1.0", - "tslib": "^2.4.0" + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@emnapi/runtime": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", - "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", - "dev": true, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", "license": "MIT", "optional": true, "dependencies": { + "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", "license": "MIT", "optional": true, "dependencies": { "tslib": "^2.4.0" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", - "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", + "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", "cpu": [ - "ppc64" + "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "aix" + "win32" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", - "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", + "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", "cpu": [ - "arm" + "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "android" + "win32" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", - "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "license": "MIT" + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz", + "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==", "cpu": [ - "arm64" + "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", - "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz", + "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==", "cpu": [ - "x64" + "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", - "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz", + "integrity": "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", - "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz", + "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", - "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz", + "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", - "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz", + "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", - "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz", + "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", - "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.0.tgz", + "integrity": "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==", "cpu": [ - "arm64" + "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", - "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.0.tgz", + "integrity": "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==", "cpu": [ - "ia32" + "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", - "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.0.tgz", + "integrity": "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==", "cpu": [ - "loong64" + "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", - "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.0.tgz", + "integrity": "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==", "cpu": [ - "mips64el" + "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", - "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.0.tgz", + "integrity": "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", - "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.0.tgz", + "integrity": "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==", "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", - "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.0.tgz", + "integrity": "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==", "cpu": [ - "s390x" + "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", - "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.0.tgz", + "integrity": "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==", "cpu": [ - "x64" + "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", - "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.0.tgz", + "integrity": "sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==", "cpu": [ - "arm64" + "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } + "linux" + ] }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", - "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.0.tgz", + "integrity": "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } + "linux" + ] }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", - "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.0.tgz", + "integrity": "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } + "openharmony" + ] }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", - "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.0.tgz", + "integrity": "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==", "cpu": [ - "x64" + "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } + "win32" + ] }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", - "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.0.tgz", + "integrity": "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==", "cpu": [ - "arm64" + "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } + "win32" + ] }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", - "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.0.tgz", + "integrity": "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "sunos" - ], + "win32" + ] + }, + "node_modules/@scalar/astro": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@scalar/astro/-/astro-0.4.11.tgz", + "integrity": "sha512-iZHZrLb0bx/s9efUkn5JKdZeyawODmfnoJl5hTu1uJxUwjKtAVtx8MFVXo8JkyC3/s8XFXGGs66d+S/Ji8eYJg==", + "license": "MIT", + "dependencies": { + "@scalar/client-side-rendering": "0.3.4" + }, "engines": { - "node": ">=18" + "node": ">=22" + }, + "peerDependencies": { + "astro": "^4.0.0 || ^5.0.0" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", - "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@scalar/client-side-rendering": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@scalar/client-side-rendering/-/client-side-rendering-0.3.4.tgz", + "integrity": "sha512-kb3B+FGjvAUr2DU0fe9dVKBLwot1TjOO+iHCTmY8r8FUJySmYKGQYCicRzzilOyTjvKspiZBCEr03PWaWW+1gw==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@scalar/schemas": "0.7.4", + "@scalar/types": "0.16.4", + "@scalar/validation": "0.6.2" + }, "engines": { - "node": ">=18" + "node": ">=22" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", - "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", - "cpu": [ - "ia32" - ], - "dev": true, + "node_modules/@scalar/client-side-rendering/node_modules/@scalar/helpers": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.9.2.tgz", + "integrity": "sha512-hjyMpMZjTBZQhyByZmz5oUgRKUQJO5V5AOiJxsVEGbUmgA7sJRQeTrXLB+BEwzaKS5nm2opJeNyMBYLFNK4hiQ==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=18" + "node": ">=22" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", - "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@scalar/client-side-rendering/node_modules/@scalar/types": { + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.16.4.tgz", + "integrity": "sha512-fLf0ANAC3iQq0sIVdmH6aGM+pFSLyD8GfGBxSWcLpI0jE0iFAzX2A3p0qVZm7vqBT4TQnn0fSwg5U+h+FZ52BA==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@scalar/helpers": "0.9.2", + "nanoid": "^5.1.6", + "type-fest": "^5.3.1", + "zod": "^4.3.5" + }, "engines": { - "node": ">=18" + "node": ">=22" } }, - "node_modules/@floating-ui/core": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", - "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "node_modules/@scalar/client-side-rendering/node_modules/nanoid": { + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.16.tgz", + "integrity": "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.10" + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" } }, - "node_modules/@floating-ui/dom": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", - "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", - "license": "MIT", + "node_modules/@scalar/client-side-rendering/node_modules/type-fest": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.8.0.tgz", + "integrity": "sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==", + "license": "(MIT OR CC0-1.0)", "dependencies": { - "@floating-ui/core": "^1.7.3", - "@floating-ui/utils": "^0.2.10" + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", - "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "node_modules/@scalar/openapi-parser": { + "version": "0.28.10", + "resolved": "https://registry.npmjs.org/@scalar/openapi-parser/-/openapi-parser-0.28.10.tgz", + "integrity": "sha512-jn3ftvtNTcWOgxf7XVn9CvJGMjFS7QU1b6FiGmibzAlR/6pOP3Ei7sBBnfIY4PBwHjHgMAGBoGApfOV8h75gPQ==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.7.4" + "@scalar/helpers": "0.9.2", + "@scalar/json-magic": "0.12.19", + "@scalar/openapi-types": "0.9.3", + "@scalar/openapi-upgrader": "0.2.11", + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "ajv-formats": "^3.0.1", + "jsonpointer": "^5.0.1", + "leven": "^4.0.0", + "yaml": "^2.8.3" }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "engines": { + "node": ">=22" } }, - "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", - "license": "MIT" + "node_modules/@scalar/openapi-parser/node_modules/@scalar/helpers": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.9.2.tgz", + "integrity": "sha512-hjyMpMZjTBZQhyByZmz5oUgRKUQJO5V5AOiJxsVEGbUmgA7sJRQeTrXLB+BEwzaKS5nm2opJeNyMBYLFNK4hiQ==", + "license": "MIT", + "engines": { + "node": ">=22" + } }, - "node_modules/@floating-ui/vue": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@floating-ui/vue/-/vue-1.1.9.tgz", - "integrity": "sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==", + "node_modules/@scalar/openapi-parser/node_modules/@scalar/json-magic": { + "version": "0.12.19", + "resolved": "https://registry.npmjs.org/@scalar/json-magic/-/json-magic-0.12.19.tgz", + "integrity": "sha512-1T4QoFYZ1nKt25xFeHtghAuZzaLq2X4CpCSLFXG0Fjcz6K2HIZqo+RtywfI0WD8RRRRgS34keo7X4Gv1BQUNoQ==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.7.4", - "@floating-ui/utils": "^0.2.10", - "vue-demi": ">=0.13.0" + "@scalar/helpers": "0.9.2", + "pathe": "^2.0.3", + "yaml": "^2.8.3" + }, + "engines": { + "node": ">=22" } }, - "node_modules/@floating-ui/vue/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, + "node_modules/@scalar/openapi-parser/node_modules/leven": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-4.0.0.tgz", + "integrity": "sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw==", "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, "engines": { - "node": ">=12" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@gerrit0/mini-shiki": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.12.1.tgz", - "integrity": "sha512-qA9/VGm7No0kxb7k0oKFT0DSJ6BtuMMtC7JQdZn9ElMALE9hjbyoaS13Y8OWr0qHwzh07KHt3Wbw34az/FLsrg==", - "dev": true, + "node_modules/@scalar/openapi-types": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.9.3.tgz", + "integrity": "sha512-34qglt5jSo55iZfH9i7EhjQCdE0Po2xZeh8wytQKolSnXrxsYMSyFDJEBxz1Gaew4on9N3XIWsd0QpwKVA5CSA==", "license": "MIT", - "dependencies": { - "@shikijs/engine-oniguruma": "^3.12.1", - "@shikijs/langs": "^3.12.1", - "@shikijs/themes": "^3.12.1", - "@shikijs/types": "^3.12.1", - "@shikijs/vscode-textmate": "^10.0.2" + "engines": { + "node": ">=22" } }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", - "license": "BSD-3-Clause" + "node_modules/@scalar/openapi-upgrader": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@scalar/openapi-upgrader/-/openapi-upgrader-0.2.11.tgz", + "integrity": "sha512-eYEFBO8mZfgXEO/hv8rdL5OA4oOB8orFT5kXNK4I/x9xca2D7A4BteuFXqRaw9lE1CIjtG+StlAUYVz5omTXew==", + "license": "MIT", + "dependencies": { + "@scalar/openapi-types": "0.9.3" + }, + "engines": { + "node": ">=22" + } }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "license": "BSD-3-Clause", + "node_modules/@scalar/schemas": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@scalar/schemas/-/schemas-0.7.4.tgz", + "integrity": "sha512-Or31zxR+ceGGhkVU5XBO2Zv7oyGDtjsJOjM2Rr0WRZ1/tRsQc2/FsVv+9kPmCA7sqFL8BKWlNfTXcPITI7WRHw==", + "license": "MIT", "dependencies": { - "@hapi/hoek": "^9.0.0" + "@scalar/helpers": "0.9.2", + "@scalar/validation": "0.6.2" + }, + "engines": { + "node": ">=22" } }, - "node_modules/@headlessui/tailwindcss": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.2.tgz", - "integrity": "sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==", + "node_modules/@scalar/schemas/node_modules/@scalar/helpers": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.9.2.tgz", + "integrity": "sha512-hjyMpMZjTBZQhyByZmz5oUgRKUQJO5V5AOiJxsVEGbUmgA7sJRQeTrXLB+BEwzaKS5nm2opJeNyMBYLFNK4hiQ==", "license": "MIT", "engines": { - "node": ">=10" - }, - "peerDependencies": { - "tailwindcss": "^3.0 || ^4.0" + "node": ">=22" } }, - "node_modules/@headlessui/vue": { - "version": "1.7.23", - "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.23.tgz", - "integrity": "sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg==", + "node_modules/@scalar/validation": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@scalar/validation/-/validation-0.6.2.tgz", + "integrity": "sha512-Sc1TkcwGV6aVCO51AyKeaGiP8gpwAHxEtO5d3tZzPV+KsnlC/YokQxFxwBrbIXw73k9hmcExnJyGu3k5i6n6VA==", "license": "MIT", - "dependencies": { - "@tanstack/vue-virtual": "^3.0.0-beta.60" - }, "engines": { - "node": ">=10" - }, - "peerDependencies": { - "vue": "^3.2.0" + "node": ">=20" } }, - "node_modules/@hyperjump/browser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@hyperjump/browser/-/browser-1.3.1.tgz", - "integrity": "sha512-Le5XZUjnVqVjkgLYv6yyWgALat/0HpB1XaCPuCZ+GCFki9NvXloSZITIJ0H+wRW7mb9At1SxvohKBbNQbrr/cw==", + "node_modules/@shikijs/core": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.3.1.tgz", + "integrity": "sha512-ANMDxuaPsNMdDC1m4vfvhlDmJweMwkE5XitTwrq2rWHx5jM+dlm4MmHt2PP6t0uejfR77SuhrhJ0zEijIF/uhA==", "license": "MIT", "dependencies": { - "@hyperjump/json-pointer": "^1.1.0", - "@hyperjump/uri": "^1.2.0", - "content-type": "^1.0.5", - "just-curry-it": "^5.3.0" + "@shikijs/primitive": "4.3.1", + "@shikijs/types": "4.3.1", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" }, "engines": { - "node": ">=18.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jdesrosiers" + "node": ">=20" } }, - "node_modules/@hyperjump/json-pointer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@hyperjump/json-pointer/-/json-pointer-1.1.1.tgz", - "integrity": "sha512-M0T3s7TC2JepoWPMZQn1W6eYhFh06OXwpMqL+8c5wMVpvnCKNsPgpu9u7WyCI03xVQti8JAeAy4RzUa6SYlJLA==", + "node_modules/@shikijs/core/node_modules/@shikijs/types": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.1.tgz", + "integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jdesrosiers" + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" } }, - "node_modules/@hyperjump/json-schema": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/@hyperjump/json-schema/-/json-schema-1.16.2.tgz", - "integrity": "sha512-MJNvaEFc79+h5rvBPgAJK4OHEUr0RqsKcLC5rc3V9FEsJyQAjnP910deRFoZCE068kX/NrAPPhunMgUMwonPtg==", + "node_modules/@shikijs/engine-javascript": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.3.1.tgz", + "integrity": "sha512-JBItcnPuYq7jVJdZo/vMj94r+szT7XEjHFX+mvFDGSEIbVAXAGyHAHzhbWzpGOwYidCZrErJLLgn2PVeiokHnQ==", "license": "MIT", "dependencies": { - "@hyperjump/json-pointer": "^1.1.0", - "@hyperjump/pact": "^1.2.0", - "@hyperjump/uri": "^1.2.0", - "content-type": "^1.0.4", - "json-stringify-deterministic": "^1.0.12", - "just-curry-it": "^5.3.0", - "uuid": "^9.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jdesrosiers" + "@shikijs/types": "4.3.1", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.6" }, - "peerDependencies": { - "@hyperjump/browser": "^1.1.0" + "engines": { + "node": ">=20" } }, - "node_modules/@hyperjump/json-schema/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], + "node_modules/@shikijs/engine-javascript/node_modules/@shikijs/types": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.1.tgz", + "integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==", "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" } }, - "node_modules/@hyperjump/pact": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@hyperjump/pact/-/pact-1.4.0.tgz", - "integrity": "sha512-01Q7VY6BcAkp9W31Fv+ciiZycxZHGlR2N6ba9BifgyclHYHdbaZgITo0U6QMhYRlem4k8pf8J31/tApxvqAz8A==", + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", + "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jdesrosiers" + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2" } }, - "node_modules/@hyperjump/uri": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@hyperjump/uri/-/uri-1.3.1.tgz", - "integrity": "sha512-2ecKymxf6prQMgrNpAvlx4RhsuM5+PFT6oh6uUTZdv5qmBv0RZvxv8LJ7oR30ZxGhdPdZAl4We/1NFc0nqHeAw==", + "node_modules/@shikijs/langs": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", + "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jdesrosiers" - } - }, - "node_modules/@internationalized/date": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.9.0.tgz", - "integrity": "sha512-yaN3brAnHRD+4KyyOsJyk49XUvj2wtbNACSqg0bz3u8t2VuzhC8Q5dfRnrSxjnnbDb+ienBnkn1TzQfE154vyg==", - "license": "Apache-2.0", "dependencies": { - "@swc/helpers": "^0.5.0" + "@shikijs/types": "3.23.0" } }, - "node_modules/@internationalized/number": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.5.tgz", - "integrity": "sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==", - "license": "Apache-2.0", + "node_modules/@shikijs/primitive": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.3.1.tgz", + "integrity": "sha512-CXQRQOYy1leqQ8ceTeJdmXv/bsUY++6QyLpXJ94LZAAYj5X2SKRdc5ipguv4NPyGVKItB2PPwUpRNe0Sjh5S1A==", + "license": "MIT", "dependencies": { - "@swc/helpers": "^0.5.0" + "@shikijs/types": "4.3.1", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" } }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "node_modules/@shikijs/primitive/node_modules/@shikijs/types": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.1.tgz", + "integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==", "license": "MIT", "dependencies": { - "@sinclair/typebox": "^0.27.8" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=20" } }, - "node_modules/@jest/schemas/node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "license": "MIT" + "node_modules/@shikijs/themes": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", + "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0" + } }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "node_modules/@shikijs/transformers": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-4.3.1.tgz", + "integrity": "sha512-z6ir0bGDgWcF2FduktEfPgIsdOtIlDiLAjFBgBzE42Q9xHbkkIXZtORHzlLVB71iZP9elEcqKg6keajvOUwE2A==", "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" + "@shikijs/core": "4.3.1", + "@shikijs/types": "4.3.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=20" } }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@shikijs/transformers/node_modules/@shikijs/types": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.1.tgz", + "integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=20" } }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@shikijs/twoslash": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/twoslash/-/twoslash-4.3.1.tgz", + "integrity": "sha512-xK8inH/gK++1V4rTxrwCwjvaNwkkJ7oDjOIpdqONVxIpAFnVC3gzqjH5KiXGTelUcxpUJ3PtOKWct1YQ0kAloA==", "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@shikijs/core": "4.3.1", + "@shikijs/types": "4.3.1", + "twoslash": "^0.3.9" }, "engines": { - "node": ">=10" + "node": ">=20" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "typescript": ">=5.5.0" } }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@shikijs/twoslash/node_modules/@shikijs/types": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.1.tgz", + "integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==", "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" }, "engines": { - "node": ">=8" + "node": ">=20" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@shikijs/types": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", + "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.1", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.3" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.30", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", - "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "license": "MIT" - }, - "node_modules/@lezer/common": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", - "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", - "license": "MIT" - }, - "node_modules/@lezer/css": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz", - "integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.3.0" - } - }, - "node_modules/@lezer/highlight": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", - "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@lezer/html": { - "version": "1.3.10", - "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz", - "integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "node_modules/@lezer/javascript": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz", - "integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.1.3", - "@lezer/lr": "^1.3.0" - } - }, - "node_modules/@lezer/json": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz", - "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "node_modules/@lezer/lr": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", - "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@lezer/xml": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz", - "integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "node_modules/@lezer/yaml": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.3.tgz", - "integrity": "sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.4.0" - } - }, - "node_modules/@marijn/find-cluster-break": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", - "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", - "license": "MIT" - }, - "node_modules/@mdx-js/mdx": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", - "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdx": "^2.0.0", - "acorn": "^8.0.0", - "collapse-white-space": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "estree-util-scope": "^1.0.0", - "estree-walker": "^3.0.0", - "hast-util-to-jsx-runtime": "^2.0.0", - "markdown-extensions": "^2.0.0", - "recma-build-jsx": "^1.0.0", - "recma-jsx": "^1.0.0", - "recma-stringify": "^1.0.0", - "rehype-recma": "^1.0.0", - "remark-mdx": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "source-map": "^0.7.0", - "unified": "^11.0.0", - "unist-util-position-from-estree": "^2.0.0", - "unist-util-stringify-position": "^4.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/react": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", - "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", - "license": "MIT", - "dependencies": { - "@types/mdx": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=16", - "react": ">=16" - } - }, - "node_modules/@module-federation/error-codes": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.18.0.tgz", - "integrity": "sha512-Woonm8ehyVIUPXChmbu80Zj6uJkC0dD9SJUZ/wOPtO8iiz/m+dkrOugAuKgoiR6qH4F+yorWila954tBz4uKsQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@module-federation/runtime": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.18.0.tgz", - "integrity": "sha512-+C4YtoSztM7nHwNyZl6dQKGUVJdsPrUdaf3HIKReg/GQbrt9uvOlUWo2NXMZ8vDAnf/QRrpSYAwXHmWDn9Obaw==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@module-federation/error-codes": "0.18.0", - "@module-federation/runtime-core": "0.18.0", - "@module-federation/sdk": "0.18.0" - } - }, - "node_modules/@module-federation/runtime-core": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.18.0.tgz", - "integrity": "sha512-ZyYhrDyVAhUzriOsVfgL6vwd+5ebYm595Y13KeMf6TKDRoUHBMTLGQ8WM4TDj8JNsy7LigncK8C03fn97of0QQ==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@module-federation/error-codes": "0.18.0", - "@module-federation/sdk": "0.18.0" - } - }, - "node_modules/@module-federation/runtime-tools": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.18.0.tgz", - "integrity": "sha512-fSga9o4t1UfXNV/Kh6qFvRyZpPp3EHSPRISNeyT8ZoTpzDNiYzhtw0BPUSSD8m6C6XQh2s/11rI4g80UY+d+hA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@module-federation/runtime": "0.18.0", - "@module-federation/webpack-bundler-runtime": "0.18.0" - } - }, - "node_modules/@module-federation/sdk": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.18.0.tgz", - "integrity": "sha512-Lo/Feq73tO2unjmpRfyyoUkTVoejhItXOk/h5C+4cistnHbTV8XHrW/13fD5e1Iu60heVdAhhelJd6F898Ve9A==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@module-federation/webpack-bundler-runtime": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.18.0.tgz", - "integrity": "sha512-TEvErbF+YQ+6IFimhUYKK3a5wapD90d90sLsNpcu2kB3QGT7t4nIluE25duXuZDVUKLz86tEPrza/oaaCWTpvQ==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@module-federation/runtime": "0.18.0", - "@module-federation/sdk": "0.18.0" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.3.tgz", - "integrity": "sha512-rZxtMsLwjdXkMUGC3WwsPwLNVqVqnTJT6MNIB6e+5fhMcSCPP0AOsNWuMQ5mdCq6HNjs/ZeWAEchpqeprqBD2Q==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.4.5", - "@emnapi/runtime": "^1.4.5", - "@tybys/wasm-util": "^0.10.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@tailwindcss/node/node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" + "bin": { + "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/@parcel/watcher": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", - "hasInstallScript": true, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^1.0.3", - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" - }, "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" - } - }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", "cpu": [ "arm64" ], @@ -5780,17 +4745,13 @@ "android" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", "cpu": [ "arm64" ], @@ -5800,17 +4761,13 @@ "darwin" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", "cpu": [ "x64" ], @@ -5820,17 +4777,13 @@ "darwin" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", "cpu": [ "x64" ], @@ -5840,17 +4793,13 @@ "freebsd" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", "cpu": [ "arm" ], @@ -5860,19 +4809,15 @@ "linux" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", "cpu": [ - "arm" + "arm64" ], "license": "MIT", "optional": true, @@ -5880,17 +4825,13 @@ "linux" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", "cpu": [ "arm64" ], @@ -5900,19 +4841,15 @@ "linux" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", "cpu": [ - "arm64" + "x64" ], "license": "MIT", "optional": true, @@ -5920,17 +4857,13 @@ "linux" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", "cpu": [ "x64" ], @@ -5940,37 +4873,42 @@ "linux" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], "cpu": [ - "x64" + "wasm32" ], "license": "MIT", "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", "cpu": [ "arm64" ], @@ -5980,19 +4918,15 @@ "win32" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", "cpu": [ - "ia32" + "x64" ], "license": "MIT", "optional": true, @@ -6000,16949 +4934,11335 @@ "win32" ], "engines": { - "node": ">= 10.0.0" + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.20.tgz", + "integrity": "sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "6.0.10" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >=4.0.0 || insiders" } }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "node_modules/@tailwindcss/vite": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz", + "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "tailwindcss": "4.3.3" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@takumi-rs/core": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/core/-/core-2.5.3.tgz", + "integrity": "sha512-Jl9mAcVPOSBlB4BoYliBfG17Jvvj2Ar1DCyj/UDK5ZPMSQrltq/BymFeGvxjPZ2gmT/dcRkle1/etCoCCOANMw==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@takumi-rs/helpers": "2.5.3" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@takumi-rs/core-darwin-arm64": "2.5.3", + "@takumi-rs/core-darwin-x64": "2.5.3", + "@takumi-rs/core-linux-arm64-gnu": "2.5.3", + "@takumi-rs/core-linux-arm64-musl": "2.5.3", + "@takumi-rs/core-linux-x64-gnu": "2.5.3", + "@takumi-rs/core-linux-x64-musl": "2.5.3", + "@takumi-rs/core-win32-arm64-msvc": "2.5.3", + "@takumi-rs/core-win32-x64-msvc": "2.5.3" + }, + "peerDependencies": { + "csstype": "*" + }, + "peerDependenciesMeta": { + "csstype": { + "optional": true + } + } + }, + "node_modules/@takumi-rs/core-darwin-arm64": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/core-darwin-arm64/-/core-darwin-arm64-2.5.3.tgz", + "integrity": "sha512-l+ZL9pwOK5SJkRl1ghNr4xPQ8V1Kkz3xnRtqm3bwKZ+ATGkNsvdPI/YdJ3TQL1AHncHviqGw6ShxpDzV7lz08g==", "cpu": [ - "x64" + "arm64" ], - "license": "MIT", + "license": "(MIT OR Apache-2.0)", "optional": true, "os": [ - "win32" + "darwin" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">=18" } }, - "node_modules/@parcel/watcher/node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "license": "Apache-2.0", + "node_modules/@takumi-rs/core-darwin-x64": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/core-darwin-x64/-/core-darwin-x64-2.5.3.tgz", + "integrity": "sha512-6HW+Ier5Jpg/hbPCmgFEHXyNYjlGQcwzKJIDdYPQblAu+ReDmB2RtHqCwptvsRoNb0iK1Uvy5AI9e+qUKowcww==", + "cpu": [ + "x64" + ], + "license": "(MIT OR Apache-2.0)", "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.10" + "node": ">=18" } }, - "node_modules/@phosphor-icons/core": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@phosphor-icons/core/-/core-2.1.1.tgz", - "integrity": "sha512-v4ARvrip4qBCImOE5rmPUylOEK4iiED9ZyKjcvzuezqMaiRASCHKcRIuvvxL/twvLpkfnEODCOJp5dM4eZilxQ==", - "license": "MIT" - }, - "node_modules/@pnpm/config.env-replace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", - "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", - "license": "MIT", + "node_modules/@takumi-rs/core-linux-arm64-gnu": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/core-linux-arm64-gnu/-/core-linux-arm64-gnu-2.5.3.tgz", + "integrity": "sha512-a6lx7f7d4h+Cs1tD0w3DP4VcMORDtQ6owddYgsiHhcjFEs+l0V0AkR0NNNWYiD7m0CPVh8AF2q3glQQELX24nQ==", + "cpu": [ + "arm64" + ], + "license": "(MIT OR Apache-2.0)", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12.22.0" + "node": ">=18" } }, - "node_modules/@pnpm/network.ca-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", - "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", - "license": "MIT", - "dependencies": { - "graceful-fs": "4.2.10" - }, + "node_modules/@takumi-rs/core-linux-arm64-musl": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/core-linux-arm64-musl/-/core-linux-arm64-musl-2.5.3.tgz", + "integrity": "sha512-9kPuiMoY/ceio8rgrO0Qp+d63emeAZdp10Tyy0WFzY4PUcle4B0SbYJ7+BEhJePFb/h1URk0xr5jkp2jJec44g==", + "cpu": [ + "arm64" + ], + "license": "(MIT OR Apache-2.0)", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12.22.0" + "node": ">=18" } }, - "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "license": "ISC" - }, - "node_modules/@pnpm/npm-conf": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", - "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", - "license": "MIT", - "dependencies": { - "@pnpm/config.env-replace": "^1.1.0", - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" - }, + "node_modules/@takumi-rs/core-linux-x64-gnu": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/core-linux-x64-gnu/-/core-linux-x64-gnu-2.5.3.tgz", + "integrity": "sha512-zpyomkKKuoqWQE04M2o9z5WeL8Ej0AwbL86pU3fRDH+FM2L9J+poN1OX4jMcQoXeE0cWvBLmWSmsEHo/Fox80w==", + "cpu": [ + "x64" + ], + "license": "(MIT OR Apache-2.0)", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@polka/url": { - "version": "1.0.0-next.29", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", - "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", - "license": "MIT" - }, - "node_modules/@radix-ui/colors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-3.0.0.tgz", - "integrity": "sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==", - "license": "MIT" + "node_modules/@takumi-rs/core-linux-x64-musl": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/core-linux-x64-musl/-/core-linux-x64-musl-2.5.3.tgz", + "integrity": "sha512-QDb7PC63H5NnkoYIXyveycvNGVoOmUiaSDC3HJ7h6UmgZo99I2KsGXdvTQfWEQua1HqWFggD2uAJPFEG16CZqQ==", + "cpu": [ + "x64" + ], + "license": "(MIT OR Apache-2.0)", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@radix-ui/number": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", - "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", - "license": "MIT" + "node_modules/@takumi-rs/core-win32-arm64-msvc": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/core-win32-arm64-msvc/-/core-win32-arm64-msvc-2.5.3.tgz", + "integrity": "sha512-GQ4194HDOKm+Q69sq7AFoaLs3psRxbIeV+6wFRPCgq+JSdfWRETyy6Hli84p7KVT6ktl6Xu7W0eVOnXx3qciVg==", + "cpu": [ + "arm64" + ], + "license": "(MIT OR Apache-2.0)", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", - "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", - "license": "MIT" + "node_modules/@takumi-rs/core-win32-x64-msvc": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/core-win32-x64-msvc/-/core-win32-x64-msvc-2.5.3.tgz", + "integrity": "sha512-BuOBq4XFS70ij+GuDCQQF/A0UAIt7/i5f6TTWPKdFP/ihueyMrgu7QSM87zUvKyM9XcravT8wrbOh6s15lIchA==", + "cpu": [ + "x64" + ], + "license": "(MIT OR Apache-2.0)", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@radix-ui/react-accessible-icon": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz", - "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-visually-hidden": "1.2.3" + "node_modules/@takumi-rs/helpers": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/helpers/-/helpers-2.5.3.tgz", + "integrity": "sha512-cIyXo7SludeAWoEO5EQojq4UpVM4Oe/aKGCmkW5eDHpRFJSrq5VcEeMFURfh9gngp0l3apBDDb+liO5CF5pZjA==", + "license": "(MIT OR Apache-2.0)", + "engines": { + "node": ">=18" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "preact": "^10.0.0", + "react": "^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { - "@types/react": { + "preact": { "optional": true }, - "@types/react-dom": { + "react": { "optional": true } } }, - "node_modules/@radix-ui/react-accordion": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", - "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", - "license": "MIT", + "node_modules/@takumi-rs/wasm": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@takumi-rs/wasm/-/wasm-2.5.3.tgz", + "integrity": "sha512-H3FAJft1QCcuMgjMUTW0IJZMNXkg8veJDwzsMAAn98Z3Z0XBeK9d5DZGYJSrvUcFDoV0NU2AFGACOYPX3DH59A==", + "license": "(MIT OR Apache-2.0)", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collapsible": "1.1.12", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@takumi-rs/helpers": "2.5.3" + }, + "engines": { + "node": ">=18" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "csstype": "*" }, "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { + "csstype": { "optional": true } } }, - "node_modules/@radix-ui/react-alert-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", - "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", "license": "MIT", + "optional": true, "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dialog": "1.1.15", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "tslib": "^2.4.0" } }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "node_modules/@radix-ui/react-aspect-ratio": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz", - "integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-avatar": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", - "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "license": "MIT", "dependencies": { - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@babel/types": "^7.0.0" } }, - "node_modules/@radix-ui/react-checkbox": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", - "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", - "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@babel/types": "^7.28.2" } }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "node_modules/@types/bun": { + "version": "1.2.21", + "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.2.21.tgz", + "integrity": "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "bun-types": "1.2.21" } }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" }, - "node_modules/@radix-ui/react-context-menu": { - "version": "2.2.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", - "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/d3-selection": "*" } }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", - "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/d3-selection": "*" } }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", - "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", - "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/d3-array": "*", + "@types/geojson": "*" } }, - "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", - "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/d3-selection": "*" } }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", - "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/d3-dsv": "*" } }, - "node_modules/@radix-ui/react-form": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz", - "integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==", + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-label": "2.1.7", - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/geojson": "*" } }, - "node_modules/@radix-ui/react-hover-card": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", - "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/d3-color": "*" } }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", - "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.4.tgz", + "integrity": "sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "@types/d3-time": "*" } }, - "node_modules/@radix-ui/react-label": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", - "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/d3-path": "*" } }, - "node_modules/@radix-ui/react-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", - "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" }, - "node_modules/@radix-ui/react-menubar": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", - "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/d3-selection": "*" } }, - "node_modules/@radix-ui/react-navigation-menu": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", - "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" } }, - "node_modules/@radix-ui/react-one-time-password-field": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.8.tgz", - "integrity": "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==", - "license": "MIT", - "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-password-toggle-field": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.3.tgz", - "integrity": "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==", + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-is-hydrated": "0.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/ms": "*" } }, - "node_modules/@radix-ui/react-popover": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", - "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" }, - "node_modules/@radix-ui/react-popper": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", - "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", "license": "MIT", "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/estree": "*" } }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "node_modules/@types/fs-extra": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", + "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/jsonfile": "*", + "@types/node": "*" } }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", - "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/unist": "*" } }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@types/jsonfile": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", + "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/node": "*" } }, - "node_modules/@radix-ui/react-progress": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", - "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", + "node_modules/@types/md5": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@types/md5/-/md5-2.3.6.tgz", + "integrity": "sha512-WD69gNXtRBnpknfZcb4TRQ0XJQbUPZcai/Qdhmka3sxUR3Et8NrXoeAoknG/LghYHTf4ve795rInVYHBTQdNVA==", + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", "license": "MIT", "dependencies": { - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/unist": "*" } }, - "node_modules/@radix-ui/react-radio-group": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", - "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/unist": "*" } }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", - "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "node_modules/@types/node": { + "version": "22.18.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.0.tgz", + "integrity": "sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ==", + "devOptional": true, "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "undici-types": "~6.21.0" } }, - "node_modules/@radix-ui/react-scroll-area": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", - "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "csstype": "^3.2.2" } }, - "node_modules/@radix-ui/react-select": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", - "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "license": "MIT", "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@types/react": "^19.2.0" } }, - "node_modules/@radix-ui/react-separator": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", - "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@typescript/vfs": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.4.tgz", + "integrity": "sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" + "debug": "^4.4.3" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "typescript": "*" } }, - "node_modules/@radix-ui/react-slider": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", - "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, + "node_modules/@vercel/cli-config": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@vercel/cli-config/-/cli-config-0.2.1.tgz", + "integrity": "sha512-RhfyXmRLHdbnry8RJqHDc+5rGxMZ0bu+fpysZjtv3bE+BubpuwxTancHOKiH5zKQREsdwFVr3mOI2kOvxlOyxA==", + "license": "Apache-2.0", "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "xdg-app-paths": "5", + "zod": "4.1.11" } }, - "node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "node_modules/@vercel/cli-config/node_modules/zod": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.11.tgz", + "integrity": "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==", "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@vercel/cli-exec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@vercel/cli-exec/-/cli-exec-1.0.0.tgz", + "integrity": "sha512-kQF8LGie/Hbdq9/psJxLE7owRTcqMQMhgybU04gCeR7cbQAr5t8OrjefDNColJv1QSSucFt4pLwRiARVmlOnug==", + "license": "Apache-2.0", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "execa": "5.1.1" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "engines": { + "node": ">= 18" } }, - "node_modules/@radix-ui/react-switch": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", - "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", - "license": "MIT", + "node_modules/@vercel/functions": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@vercel/functions/-/functions-3.7.6.tgz", + "integrity": "sha512-QKlSfrgvo4pGEnzHw8Dha9GRTb5hhLBbImKi4rL4CmxClaVs+36hxgjW0MOqez57wWShstpKOWZY/mU8KuYoUQ==", + "license": "Apache-2.0", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" + "@vercel/oidc": "3.8.1" + }, + "engines": { + "node": ">= 20" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@aws-sdk/credential-provider-web-identity": "*", + "ws": ">=8" }, "peerDependenciesMeta": { - "@types/react": { + "@aws-sdk/credential-provider-web-identity": { "optional": true }, - "@types/react-dom": { + "ws": { "optional": true } } }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", - "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", - "license": "MIT", + "node_modules/@vercel/microfrontends": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@vercel/microfrontends/-/microfrontends-2.4.0.tgz", + "integrity": "sha512-dpUzyjpLtE40gB+vxU3AWy5Dlkx/O91joVc/Q7PTYTtHVmw7ZkKgbR0QFEQJC0kw6SXOb35q46QN1BVwVRL5DQ==", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@next/env": "16.0.10", + "@types/md5": "^2.3.5", + "ajv": "^8.17.1", + "commander": "^12.1.0", + "cookie": "1.0.2", + "fast-glob": "^3.3.2", + "http-proxy": "^1.18.1", + "jsonc-parser": "^3.3.1", + "md5": "^2.3.0", + "nanoid": "^3.3.9", + "path-to-regexp": "6.3.0", + "semver": "^7.7.2" + }, + "bin": { + "microfrontends": "cli/index.cjs" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@sveltejs/kit": ">=1", + "@vercel/analytics": ">=1.5.0", + "@vercel/speed-insights": ">=1.2.0", + "next": ">=13", + "react": ">=17.0.0", + "react-dom": ">=17.0.0", + "vite": ">=5" }, "peerDependenciesMeta": { - "@types/react": { + "@sveltejs/kit": { "optional": true }, - "@types/react-dom": { + "@vercel/analytics": { "optional": true - } - } - }, - "node_modules/@radix-ui/react-toast": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", - "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { + }, + "@vercel/speed-insights": { + "optional": true + }, + "next": { "optional": true }, - "@types/react-dom": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "vite": { "optional": true } } }, - "node_modules/@radix-ui/react-toggle": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", - "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "node_modules/@vercel/microfrontends/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "engines": { + "node": ">=18" } }, - "node_modules/@radix-ui/react-toggle-group": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", - "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", + "node_modules/@vercel/microfrontends/node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, + "node_modules/@vercel/nft": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.10.2.tgz", + "integrity": "sha512-w+WyX5Ulmj4dtTZrxaulqrjaLZHSbnPzx75SJsTNYmotKsqn1JlLnDJa+lz5hn90HJofhl/2MAtw0mCrgM3qYw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-toggle": "1.1.10", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@mapbox/node-pre-gyp": "^2.0.0", + "@rollup/pluginutils": "^5.1.3", + "acorn": "^8.6.0", + "acorn-import-attributes": "^1.9.5", + "async-sema": "^3.1.1", + "bindings": "^1.4.0", + "estree-walker": "2.0.2", + "glob": "^13.0.0", + "graceful-fs": "^4.2.9", + "node-gyp-build": "^4.2.2", + "picomatch": "^4.0.2", + "resolve-from": "^5.0.0" }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "bin": { + "nft": "out/cli.js" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "engines": { + "node": ">=20" } }, - "node_modules/@radix-ui/react-toolbar": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz", - "integrity": "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==", - "license": "MIT", + "node_modules/@vercel/nft/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vercel/nft/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-separator": "1.1.7", - "@radix-ui/react-toggle-group": "1.1.11" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "engines": { + "node": "18 || 20 || >=22" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@radix-ui/react-tooltip": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", - "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-visually-hidden": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "node_modules/@vercel/nft/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@vercel/oidc": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.8.1.tgz", + "integrity": "sha512-ufdalm2MWOYksyj8KVpWjoOFPJO6zoYpuyvIggIQ2bB0CFCjTCiTkGXHqAKwG77GVRjOaN3/8S5ITlZpXWmqOw==", + "license": "Apache-2.0", + "dependencies": { + "@vercel/cli-config": "0.2.1", + "@vercel/cli-exec": "1.0.0", + "jose": "^5.9.6" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "engines": { + "node": ">= 20" } }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", - "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "node_modules/@vercel/oidc/node_modules/jose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/@vercel/routing-utils": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@vercel/routing-utils/-/routing-utils-5.3.3.tgz", + "integrity": "sha512-KYm2sLNUD48gDScv8ob4ejc3Gww2jcJyW80hTdYlenAPz/5BQar1Gyh38xrUuZ532TUwSb5mV1uRbAuiykq0EQ==", + "license": "Apache-2.0", + "dependencies": { + "path-to-regexp": "6.1.0", + "path-to-regexp-updated": "npm:path-to-regexp@6.3.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "optionalDependencies": { + "ajv": "^6.12.3" } }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "node_modules/@vercel/routing-utils/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "license": "MIT", + "optional": true, "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", - "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "node_modules/@vercel/routing-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT", + "optional": true + }, + "node_modules/@vercel/routing-utils/node_modules/path-to-regexp": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.1.0.tgz", + "integrity": "sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz", + "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "engines": { + "node": "^20.19.0 || >=22.12.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", - "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@radix-ui/react-use-is-hydrated": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", - "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "dev": true, "license": "MIT", "dependencies": { - "use-sync-external-store": "^1.5.0" + "@vitest/spy": "4.1.10", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { - "@types/react": { + "msw": { + "optional": true + }, + "vite": { "optional": true } } }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "dev": true, "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "dependencies": { + "tinyrainbow": "^3.1.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@radix-ui/react-use-previous": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", - "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "dev": true, "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "dependencies": { + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@radix-ui/react-use-rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", - "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@radix-ui/react-use-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", - "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", - "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "node_modules/@volar/kit": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/kit/-/kit-2.4.28.tgz", + "integrity": "sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" + "@volar/language-service": "2.4.28", + "@volar/typescript": "2.4.28", + "typesafe-path": "^0.2.2", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "typescript": "*" } }, - "node_modules/@radix-ui/rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", - "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", - "license": "MIT" + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } }, - "node_modules/@radix-ui/themes": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@radix-ui/themes/-/themes-3.2.1.tgz", - "integrity": "sha512-WJL2YKAGItkunwm3O4cLTFKCGJTfAfF6Hmq7f5bCo1ggqC9qJQ/wfg/25AAN72aoEM1yqXZQ+pslsw48AFR0Xg==", + "node_modules/@volar/language-server": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-server/-/language-server-2.4.28.tgz", + "integrity": "sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==", "license": "MIT", "dependencies": { - "@radix-ui/colors": "^3.0.0", - "classnames": "^2.3.2", - "radix-ui": "^1.1.3", - "react-remove-scroll-bar": "^2.3.8" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@volar/language-core": "2.4.28", + "@volar/language-service": "2.4.28", + "@volar/typescript": "2.4.28", + "path-browserify": "^1.0.1", + "request-light": "^0.7.0", + "vscode-languageserver": "^9.0.1", + "vscode-languageserver-protocol": "^3.17.5", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" } }, - "node_modules/@replit/codemirror-css-color-picker": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@replit/codemirror-css-color-picker/-/codemirror-css-color-picker-6.3.0.tgz", - "integrity": "sha512-19biDANghUm7Fz7L1SNMIhK48tagaWuCOHj4oPPxc7hxPGkTVY2lU/jVZ8tsbTKQPVG7BO2CBDzs7CBwb20t4A==", + "node_modules/@volar/language-service": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-service/-/language-service-2.4.28.tgz", + "integrity": "sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==", "license": "MIT", - "peerDependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" + "dependencies": { + "@volar/language-core": "2.4.28", + "vscode-languageserver-protocol": "^3.17.5", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", "license": "MIT" }, - "node_modules/@rollup/plugin-replace": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz", - "integrity": "sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==", + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.30.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" } }, - "node_modules/@rollup/pluginutils": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", - "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", + "node_modules/@vscode/emmet-helper": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.11.0.tgz", + "integrity": "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", + "emmet": "^2.4.3", + "jsonc-parser": "^2.3.0", + "vscode-languageserver-textdocument": "^1.0.1", + "vscode-languageserver-types": "^3.15.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vscode/l10n": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", + "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==", + "license": "MIT" + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.20.tgz", + "integrity": "sha512-8TWXUyiqFd3GmP4JTX9hbiTFRwYHgVL/vr3cqhr4YQ258+9FADwvj7golk2sWNGHR67QgmCZ8gz80nQcMokhwg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.28.3", + "@vue/shared": "3.5.20", + "entities": "^4.5.0", "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "source-map-js": "^1.2.1" } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "node_modules/@vue/compiler-core/node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz", - "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@vue/compiler-dom": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.20.tgz", + "integrity": "sha512-whB44M59XKjqUEYOMPYU0ijUV0G+4fdrHVKDe32abNdX/kJe1NUEMqsi4cwzXa9kyM9w5S8WqFsrfo1ogtBZGQ==", "license": "MIT", "optional": true, - "os": [ - "android" - ] + "peer": true, + "dependencies": { + "@vue/compiler-core": "3.5.20", + "@vue/shared": "3.5.20" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz", - "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.20.tgz", + "integrity": "sha512-SFcxapQc0/feWiSBfkGsa1v4DOrnMAQSYuvDMpEaxbpH5dKbnEM5KobSNSgU+1MbHCl+9ftm7oQWxvwDB6iBfw==", "license": "MIT", "optional": true, - "os": [ - "android" - ] + "peer": true, + "dependencies": { + "@babel/parser": "^7.28.3", + "@vue/compiler-core": "3.5.20", + "@vue/compiler-dom": "3.5.20", + "@vue/compiler-ssr": "3.5.20", + "@vue/shared": "3.5.20", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.17", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz", - "integrity": "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT", "optional": true, - "os": [ - "darwin" - ] + "peer": true }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz", - "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.20.tgz", + "integrity": "sha512-RSl5XAMc5YFUXpDQi+UQDdVjH9FnEpLDHIALg5J0ITHxkEzJ8uQLlo7CIbjPYqmZtt6w0TsIPbo1izYXwDG7JA==", "license": "MIT", "optional": true, - "os": [ - "darwin" - ] + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.5.20", + "@vue/shared": "3.5.20" + } }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz", - "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", "license": "MIT", "optional": true, - "os": [ - "freebsd" - ] + "peer": true }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz", - "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@vue/reactivity": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.20.tgz", + "integrity": "sha512-hS8l8x4cl1fmZpSQX/NXlqWKARqEsNmfkwOIYqtR2F616NGfsLUm0G6FQBK6uDKUCVyi1YOL8Xmt/RkZcd/jYQ==", "license": "MIT", "optional": true, - "os": [ - "freebsd" - ] + "peer": true, + "dependencies": { + "@vue/shared": "3.5.20" + } }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz", - "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@vue/runtime-core": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.20.tgz", + "integrity": "sha512-vyQRiH5uSZlOa+4I/t4Qw/SsD/gbth0SW2J7oMeVlMFMAmsG1rwDD6ok0VMmjXY3eI0iHNSSOBilEDW98PLRKw==", "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "peer": true, + "dependencies": { + "@vue/reactivity": "3.5.20", + "@vue/shared": "3.5.20" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.0.tgz", - "integrity": "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@vue/runtime-dom": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.20.tgz", + "integrity": "sha512-KBHzPld/Djw3im0CQ7tGCpgRedryIn4CcAl047EhFTCCPT2xFf4e8j6WeKLgEEoqPSl9TYqShc3Q6tpWpz/Xgw==", "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "peer": true, + "dependencies": { + "@vue/reactivity": "3.5.20", + "@vue/runtime-core": "3.5.20", + "@vue/shared": "3.5.20", + "csstype": "^3.1.3" + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.0.tgz", - "integrity": "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@vue/server-renderer": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.20.tgz", + "integrity": "sha512-HthAS0lZJDH21HFJBVNTtx+ULcIbJQRpjSVomVjfyPkFSpCwvsPTA+jIzOaUm3Hrqx36ozBHePztQFg6pj5aKg==", "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "peer": true, + "dependencies": { + "@vue/compiler-ssr": "3.5.20", + "@vue/shared": "3.5.20" + }, + "peerDependencies": { + "vue": "3.5.20" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.0.tgz", - "integrity": "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@vue/shared": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.20.tgz", + "integrity": "sha512-SoRGP596KU/ig6TfgkCMbXkr4YJ91n/QSdMuqeP5r3hVIYA3CPHUBCc7Skak0EAKV+5lL4KyIh61VA/pK1CIAA==", "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "peer": true }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.0.tgz", - "integrity": "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==", - "cpu": [ - "loong64" - ], - "dev": true, + "node_modules/abbrev": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.0.tgz", - "integrity": "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==", - "cpu": [ - "ppc64" - ], - "dev": true, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.0.tgz", - "integrity": "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==", - "cpu": [ - "riscv64" - ], - "dev": true, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">= 0.6" + } }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.0.tgz", - "integrity": "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==", - "cpu": [ - "riscv64" - ], - "dev": true, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.0.tgz", - "integrity": "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==", - "cpu": [ - "s390x" - ], - "dev": true, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.0.tgz", - "integrity": "sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "peerDependencies": { + "acorn": "^8" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.0.tgz", - "integrity": "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.0.tgz", - "integrity": "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] + "engines": { + "node": ">= 14" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.0.tgz", - "integrity": "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.0.tgz", - "integrity": "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==", - "cpu": [ - "ia32" - ], - "dev": true, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.0.tgz", - "integrity": "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } }, - "node_modules/@rspack/binding": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.5.2.tgz", - "integrity": "sha512-NKiBcsxmAzFDYRnK2ZHWbTtDFVT5/704eK4OfpgsDXPMkaMnBKijMKNgP5pbe18X4rUlz+8HnGm4+Xllo9EESw==", - "devOptional": true, - "license": "MIT", - "optionalDependencies": { - "@rspack/binding-darwin-arm64": "1.5.2", - "@rspack/binding-darwin-x64": "1.5.2", - "@rspack/binding-linux-arm64-gnu": "1.5.2", - "@rspack/binding-linux-arm64-musl": "1.5.2", - "@rspack/binding-linux-x64-gnu": "1.5.2", - "@rspack/binding-linux-x64-musl": "1.5.2", - "@rspack/binding-wasm32-wasi": "1.5.2", - "@rspack/binding-win32-arm64-msvc": "1.5.2", - "@rspack/binding-win32-ia32-msvc": "1.5.2", - "@rspack/binding-win32-x64-msvc": "1.5.2" - } - }, - "node_modules/@rspack/binding-darwin-arm64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.5.2.tgz", - "integrity": "sha512-aO76T6VQvAFt1LJNRA5aPOJ+szeTLlzC5wubsnxgWWjG53goP+Te35kFjDIDe+9VhKE/XqRId6iNAymaEsN+Uw==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/ajv-i18n": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ajv-i18n/-/ajv-i18n-4.2.0.tgz", + "integrity": "sha512-v/ei2UkCEeuKNXh8RToiFsUclmU+G57LO1Oo22OagNMENIw+Yb8eMwvHu7Vn9fmkjJyv6XclhJ8TbuigSglPkg==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "peerDependencies": { + "ajv": "^8.0.0-beta.0" + } }, - "node_modules/@rspack/binding-darwin-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.5.2.tgz", - "integrity": "sha512-XNSmUOwdGs2PEdCKTFCC0/vu/7U9nMhAlbHJKlmdt0V4iPvFyaNWxkNdFqzLc05jlJOfgDdwbwRb91y9IcIIFQ==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/algoliasearch": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.56.0.tgz", + "integrity": "sha512-PrqppUmhT4ENdas2pH9caE7efUcxy6EcSFhWzosiVuQBzu2tQ5yLTI6jwomT/1cuBnivzGfxiJCqDNN9FRRh+Q==", "license": "MIT", "optional": true, - "os": [ - "darwin" - ] + "peer": true, + "dependencies": { + "@algolia/abtesting": "1.22.0", + "@algolia/client-abtesting": "5.56.0", + "@algolia/client-analytics": "5.56.0", + "@algolia/client-common": "5.56.0", + "@algolia/client-insights": "5.56.0", + "@algolia/client-personalization": "5.56.0", + "@algolia/client-query-suggestions": "5.56.0", + "@algolia/client-search": "5.56.0", + "@algolia/ingestion": "1.56.0", + "@algolia/monitoring": "1.56.0", + "@algolia/recommend": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } }, - "node_modules/@rspack/binding-linux-arm64-gnu": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.5.2.tgz", - "integrity": "sha512-rNxRfgC5khlrhyEP6y93+45uQ4TI7CdtWqh5PKsaR6lPepG1rH4L8VE+etejSdhzXH6wQ76Rw4wzb96Hx+5vuQ==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/am-i-vibing": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.4.0.tgz", + "integrity": "sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "process-ancestry": "^0.1.0" + }, + "bin": { + "am-i-vibing": "dist/cli.mjs" + } }, - "node_modules/@rspack/binding-linux-arm64-musl": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.5.2.tgz", - "integrity": "sha512-kTFX+KsGgArWC5q+jJWz0K/8rfVqZOn1ojv1xpCCcz/ogWRC/qhDGSOva6Wandh157BiR93Vfoe1gMvgjpLe5g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^4.1.0" + } }, - "node_modules/@rspack/binding-linux-x64-gnu": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.5.2.tgz", - "integrity": "sha512-Lh/6WZGq30lDV6RteQQu7Phw0RH2Z1f4kGR+MsplJ6X4JpnziDow+9oxKdu6FvFHWxHByncpveVeInusQPmL7Q==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "peer": true }, - "node_modules/@rspack/binding-linux-x64-musl": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.5.2.tgz", - "integrity": "sha512-CsLC/SIOIFs6CBmusSAF0FECB62+J36alMdwl7j6TgN6nX3UQQapnL1aVWuQaxU6un/1Vpim0V/EZbUYIdJQ4g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-wasm32-wasi": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.5.2.tgz", - "integrity": "sha512-cuVbGr1b4q0Z6AtEraI3becZraPMMgZtZPRaIsVLeDXCmxup/maSAR3T6UaGf4Q2SNcFfjw4neGz5UJxPK8uvA==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.1" - } - }, - "node_modules/@rspack/binding-win32-arm64-msvc": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.5.2.tgz", - "integrity": "sha512-4vJQdzRTSuvmvL3vrOPuiA7f9v9frNc2RFWDxqg+GYt0YAjDStssp+lkVbRYyXnTYVJkARSuO6N+BOiI+kLdsQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rspack/binding-win32-ia32-msvc": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.5.2.tgz", - "integrity": "sha512-zPbu3lx/NrNxdjZzTIjwD0mILUOpfhuPdUdXIFiOAO8RiWSeQpYOvyI061s/+bNOmr4A+Z0uM0dEoOClfkhUFg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rspack/binding-win32-x64-msvc": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.5.2.tgz", - "integrity": "sha512-duLNUTshX38xhC10/W9tpkPca7rOifP2begZjdb1ikw7C4AI0I7VnBnYt8qPSxGISoclmhOBxU/LuAhS8jMMlg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rspack/core": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.5.2.tgz", - "integrity": "sha512-ifjHqLczC81d1xjXPXCzxTFKNOFsEzuuLN44cMnyzQ/GWi4B48fyX7JHndWE7Lxd54cW1O9Ik7AdBN3Gq891EA==", - "devOptional": true, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", + "peer": true, "dependencies": { - "@module-federation/runtime-tools": "0.18.0", - "@rspack/binding": "1.5.2", - "@rspack/lite-tapable": "1.0.1" - }, - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "@swc/helpers": ">=0.5.1" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/@rspack/lite-tapable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.0.1.tgz", - "integrity": "sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@scalar/api-client": { - "version": "2.5.26", - "resolved": "https://registry.npmjs.org/@scalar/api-client/-/api-client-2.5.26.tgz", - "integrity": "sha512-f5NWAr8aRBpANLAWVhIXlO3ehe/lY47nufoltnpR4QLu0xSNwAa8MdL9hQuU9Cka6cGp/h9NE60ad1qM1m/eFA==", - "license": "MIT", - "dependencies": { - "@headlessui/tailwindcss": "^0.2.2", - "@headlessui/vue": "^1.7.23", - "@scalar/components": "0.14.27", - "@scalar/draggable": "0.2.0", - "@scalar/helpers": "0.0.8", - "@scalar/icons": "0.4.7", - "@scalar/import": "0.4.19", - "@scalar/oas-utils": "0.4.22", - "@scalar/object-utils": "1.2.4", - "@scalar/openapi-parser": "0.20.1", - "@scalar/openapi-types": "0.3.7", - "@scalar/postman-to-openapi": "0.3.25", - "@scalar/snippetz": "0.4.7", - "@scalar/themes": "0.13.14", - "@scalar/types": "0.2.13", - "@scalar/use-codemirror": "0.12.28", - "@scalar/use-hooks": "0.2.4", - "@scalar/use-toasts": "0.8.0", - "@types/har-format": "^1.2.15", - "@vueuse/core": "^11.2.0", - "@vueuse/integrations": "^11.2.0", - "focus-trap": "^7", - "fuse.js": "^7.1.0", - "microdiff": "^1.5.0", - "nanoid": "5.1.5", - "pretty-bytes": "^6.1.1", - "pretty-ms": "^8.0.0", - "shell-quote": "^1.8.1", - "type-fest": "4.41.0", - "vue": "^3.5.17", - "vue-router": "^4.3.0", - "whatwg-mimetype": "^4.0.0", - "yaml": "2.8.0", - "zod": "3.24.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=20" + "node": ">=8" } }, - "node_modules/@scalar/api-client-react": { - "version": "1.3.31", - "resolved": "https://registry.npmjs.org/@scalar/api-client-react/-/api-client-react-1.3.31.tgz", - "integrity": "sha512-k4XJrS6vNgOVGPJUhpNw1xtcAP8rpZiDEU+RjTzkMb1HuFLVKb/kb/r9I1PjXZo38hywnSF220RBGfLv9XiypA==", + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", + "peer": true, "dependencies": { - "@scalar/api-client": "2.5.26", - "@scalar/types": "0.2.13", - "vue": "^3.5.17" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=20" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0" + "node": ">=8" } }, - "node_modules/@scalar/api-client/node_modules/@scalar/openapi-parser": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@scalar/openapi-parser/-/openapi-parser-0.20.1.tgz", - "integrity": "sha512-rxtuBQ90YsUEDefWU3GAEmvjYr1CvGO6nkDVzbjmWv2aPB3mtK80bCRBgQGTdIdW5XQEWAAmflSKEhcj2Xo5QA==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", - "dependencies": { - "@scalar/json-magic": "0.3.1", - "@scalar/openapi-types": "0.3.7", - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", - "ajv-formats": "^3.0.1", - "jsonpointer": "^5.0.1", - "leven": "^4.0.0", - "yaml": "2.8.0" - }, + "peer": true, "engines": { - "node": ">=20" + "node": ">=8" } }, - "node_modules/@scalar/api-client/node_modules/@scalar/openapi-types": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.3.7.tgz", - "integrity": "sha512-QHSvHBVDze3+dUwAhIGq6l1iOev4jdoqdBK7QpfeN1Q4h+6qpVEw3EEqBiH0AXUSh/iWwObBv4uMgfIx0aNZ5g==", - "license": "MIT", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", "dependencies": { - "zod": "3.24.1" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">=20" + "node": ">= 8" } }, - "node_modules/@scalar/api-client/node_modules/leven": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-4.0.0.tgz", - "integrity": "sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw==", + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@scalar/api-client/node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-iterate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", "license": "MIT", "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/@scalar/api-reference": { - "version": "1.34.6", - "resolved": "https://registry.npmjs.org/@scalar/api-reference/-/api-reference-1.34.6.tgz", - "integrity": "sha512-QOLca2cM9yrbLs+Wy/OGIakit2JJXG4yPJDzUcCxXdVXaKJGb2dax3anUITPl9PObW9UBEKCy27ClJFDJSlXkw==", - "license": "MIT", - "dependencies": { - "@floating-ui/vue": "^1.1.7", - "@headlessui/vue": "^1.7.23", - "@scalar/api-client": "2.5.26", - "@scalar/code-highlight": "0.1.9", - "@scalar/components": "0.14.27", - "@scalar/helpers": "0.0.8", - "@scalar/icons": "0.4.7", - "@scalar/json-magic": "0.3.1", - "@scalar/oas-utils": "0.4.22", - "@scalar/object-utils": "1.2.4", - "@scalar/openapi-parser": "0.20.1", - "@scalar/openapi-types": "0.3.7", - "@scalar/snippetz": "0.4.7", - "@scalar/themes": "0.13.14", - "@scalar/types": "0.2.13", - "@scalar/use-hooks": "0.2.4", - "@scalar/use-toasts": "0.8.0", - "@scalar/workspace-store": "0.14.2", - "@unhead/vue": "^1.11.20", - "@vueuse/core": "^11.2.0", - "flatted": "^3.3.3", - "fuse.js": "^7.1.0", - "github-slugger": "^2.0.0", - "microdiff": "^1.5.0", - "nanoid": "5.1.5", - "vue": "^3.5.17", - "zod": "3.24.1" - }, - "engines": { - "node": ">=20" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@scalar/api-reference-react": { - "version": "0.7.42", - "resolved": "https://registry.npmjs.org/@scalar/api-reference-react/-/api-reference-react-0.7.42.tgz", - "integrity": "sha512-hqy8i7D4DijNbv4MF5ooXP/XkexghBWrtkFf5S9qRUG2VX3JAvhFksyWIqdkpWrOjZ40OPlcashbWKO0s/Hcww==", + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, "license": "MIT", - "dependencies": { - "@scalar/api-reference": "1.34.6", - "@scalar/types": "0.2.13" - }, "engines": { - "node": ">=20" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0" + "node": ">=12" } }, - "node_modules/@scalar/api-reference/node_modules/@scalar/openapi-parser": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@scalar/openapi-parser/-/openapi-parser-0.20.1.tgz", - "integrity": "sha512-rxtuBQ90YsUEDefWU3GAEmvjYr1CvGO6nkDVzbjmWv2aPB3mtK80bCRBgQGTdIdW5XQEWAAmflSKEhcj2Xo5QA==", + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", "license": "MIT", - "dependencies": { - "@scalar/json-magic": "0.3.1", - "@scalar/openapi-types": "0.3.7", - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", - "ajv-formats": "^3.0.1", - "jsonpointer": "^5.0.1", - "leven": "^4.0.0", - "yaml": "2.8.0" - }, - "engines": { - "node": ">=20" + "bin": { + "astring": "bin/astring" } }, - "node_modules/@scalar/api-reference/node_modules/@scalar/openapi-types": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.3.7.tgz", - "integrity": "sha512-QHSvHBVDze3+dUwAhIGq6l1iOev4jdoqdBK7QpfeN1Q4h+6qpVEw3EEqBiH0AXUSh/iWwObBv4uMgfIx0aNZ5g==", + "node_modules/astro": { + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/astro/-/astro-5.18.2.tgz", + "integrity": "sha512-TnFwLnAXty5MXKPDGuKXqK4AMBXG+FH6RUdK7Oyc3gyfNoFIthT+4eRbzOK43bdRlLaZuxgciDSjgtggZ3OtGQ==", "license": "MIT", + "peer": true, "dependencies": { - "zod": "3.24.1" + "@astrojs/compiler": "^2.13.0", + "@astrojs/internal-helpers": "0.7.6", + "@astrojs/markdown-remark": "6.3.11", + "@astrojs/telemetry": "3.3.0", + "@capsizecss/unpack": "^4.0.0", + "@oslojs/encoding": "^1.1.0", + "@rollup/pluginutils": "^5.3.0", + "acorn": "^8.15.0", + "aria-query": "^5.3.2", + "axobject-query": "^4.1.0", + "boxen": "8.0.1", + "ci-info": "^4.3.1", + "clsx": "^2.1.1", + "common-ancestor-path": "^1.0.1", + "cookie": "^1.1.1", + "cssesc": "^3.0.0", + "debug": "^4.4.3", + "deterministic-object-hash": "^2.0.2", + "devalue": "^5.6.2", + "diff": "^8.0.3", + "dlv": "^1.1.3", + "dset": "^3.1.4", + "es-module-lexer": "^1.7.0", + "esbuild": "^0.27.3", + "estree-walker": "^3.0.3", + "flattie": "^1.1.1", + "fontace": "~0.4.0", + "github-slugger": "^2.0.0", + "html-escaper": "3.0.3", + "http-cache-semantics": "^4.2.0", + "import-meta-resolve": "^4.2.0", + "js-yaml": "^4.1.1", + "magic-string": "^0.30.21", + "magicast": "^0.5.1", + "mrmime": "^2.0.1", + "neotraverse": "^0.6.18", + "p-limit": "^6.2.0", + "p-queue": "^8.1.1", + "package-manager-detector": "^1.6.0", + "piccolore": "^0.1.3", + "picomatch": "^4.0.3", + "prompts": "^2.4.2", + "rehype": "^13.0.2", + "semver": "^7.7.3", + "shiki": "^3.21.0", + "smol-toml": "^1.6.0", + "svgo": "^4.0.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tsconfck": "^3.1.6", + "ultrahtml": "^1.6.0", + "unifont": "~0.7.3", + "unist-util-visit": "^5.0.0", + "unstorage": "^1.17.4", + "vfile": "^6.0.3", + "vite": "^6.4.1", + "vitefu": "^1.1.1", + "xxhash-wasm": "^1.1.0", + "yargs-parser": "^21.1.1", + "yocto-spinner": "^0.2.3", + "zod": "^3.25.76", + "zod-to-json-schema": "^3.25.1", + "zod-to-ts": "^1.2.0" + }, + "bin": { + "astro": "astro.js" }, "engines": { - "node": ">=20" - } - }, - "node_modules/@scalar/api-reference/node_modules/github-slugger": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", - "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", - "license": "ISC" - }, - "node_modules/@scalar/api-reference/node_modules/leven": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-4.0.0.tgz", - "integrity": "sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "18.20.8 || ^20.3.0 || >=22.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/astrodotbuild" + }, + "optionalDependencies": { + "sharp": "^0.34.0" } }, - "node_modules/@scalar/api-reference/node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "node_modules/astro/node_modules/@astrojs/internal-helpers": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.6.tgz", + "integrity": "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } + "peer": true }, - "node_modules/@scalar/code-highlight": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/@scalar/code-highlight/-/code-highlight-0.1.9.tgz", - "integrity": "sha512-WUUVDd1Wk7QJVKWXl/Zdn/VINc2pc1NlWW8VJFYZRm3/hKJwBhi0on7+HjVQNKgUaRy7+zluru5Ckl1gcTHHEg==", + "node_modules/astro/node_modules/@astrojs/markdown-remark": { + "version": "6.3.11", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.11.tgz", + "integrity": "sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ==", "license": "MIT", + "peer": true, "dependencies": { + "@astrojs/internal-helpers": "0.7.6", + "@astrojs/prism": "3.3.0", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", - "highlight.js": "^11.9.0", - "highlightjs-curl": "^1.3.0", - "highlightjs-vue": "^1.0.0", - "lowlight": "^3.1.0", - "rehype-external-links": "^3.0.0", - "rehype-format": "^5.0.0", - "rehype-parse": "^9.0.0", + "import-meta-resolve": "^4.2.0", + "js-yaml": "^4.1.1", + "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", - "rehype-sanitize": "^6.0.0", - "rehype-stringify": "^10.0.0", - "remark-gfm": "^4.0.0", + "rehype-stringify": "^10.0.1", + "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", - "remark-rehype": "^11.1.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.4", - "unist-util-visit": "^5.0.0" - }, - "engines": { - "node": ">=20" + "remark-rehype": "^11.1.2", + "remark-smartypants": "^3.0.2", + "shiki": "^3.21.0", + "smol-toml": "^1.6.0", + "unified": "^11.0.5", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.2", + "vfile": "^6.0.3" } }, - "node_modules/@scalar/components": { - "version": "0.14.27", - "resolved": "https://registry.npmjs.org/@scalar/components/-/components-0.14.27.tgz", - "integrity": "sha512-XMm3oaGy9oBKO7XAoI3mLnr5wKGacefj358XYPNjYGGN9qx60burOdGuFPzCGPnhS++th+O0h7drCXy1mznPfQ==", + "node_modules/astro/node_modules/@astrojs/prism": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.3.0.tgz", + "integrity": "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==", "license": "MIT", + "peer": true, "dependencies": { - "@floating-ui/utils": "^0.2.2", - "@floating-ui/vue": "^1.1.7", - "@headlessui/vue": "^1.7.23", - "@scalar/code-highlight": "0.1.9", - "@scalar/helpers": "0.0.8", - "@scalar/icons": "0.4.7", - "@scalar/oas-utils": "0.4.22", - "@scalar/themes": "0.13.14", - "@scalar/use-hooks": "0.2.4", - "@scalar/use-toasts": "0.8.0", - "@vueuse/core": "^11.2.0", - "cva": "1.0.0-beta.2", - "nanoid": "5.1.5", - "pretty-bytes": "^6.1.1", - "radix-vue": "^1.9.3", - "vue": "^3.5.17", - "vue-component-type-helpers": "^3.0.4" + "prismjs": "^1.30.0" }, "engines": { - "node": ">=20" + "node": "18.20.8 || ^20.3.0 || >=22.0.0" } }, - "node_modules/@scalar/draggable": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@scalar/draggable/-/draggable-0.2.0.tgz", - "integrity": "sha512-UetHRB5Bqo5egVYlS21roWBcICmyk8CKh2htsidO+bFGAjl2e7Te+rY0borhNrMclr0xezHlPuLpEs1dvgLS2g==", + "node_modules/astro/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "vue": "^3.5.12" - }, + "optional": true, + "os": [ + "aix" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/helpers": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.0.8.tgz", - "integrity": "sha512-9A1CxL3jV7Kl9wGu86/cR/wiJN6J+3tK4WuW3252s2gF+upXsgQRx9WLhFF3xifOP1irIGusitZBiojiKmUSVg==", + "node_modules/astro/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/icons": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/@scalar/icons/-/icons-0.4.7.tgz", - "integrity": "sha512-0qXPGRdZ180TMfejWCPYy7ILszBrAraq4KBhPtcM12ghc5qkncFWWpTm5yXI/vrbm10t7wvtTK08CLZ36CnXlQ==", + "node_modules/astro/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@phosphor-icons/core": "^2.1.1", - "@types/node": "^22.9.0", - "chalk": "^5.4.1", - "vue": "^3.5.17" - }, + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/import": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/@scalar/import/-/import-0.4.19.tgz", - "integrity": "sha512-Y8BB0/msE/y9U1aiU4ioH/sDIVcvxmcEPDfTr2PGcTNamMmwOnAYN7AcEYQarlDo1CVjyzsIdiaEdrgQyZ4y9A==", + "node_modules/astro/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@scalar/helpers": "0.0.8", - "@scalar/openapi-parser": "0.20.1", - "yaml": "2.8.0" - }, + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/import/node_modules/@scalar/openapi-parser": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@scalar/openapi-parser/-/openapi-parser-0.20.1.tgz", - "integrity": "sha512-rxtuBQ90YsUEDefWU3GAEmvjYr1CvGO6nkDVzbjmWv2aPB3mtK80bCRBgQGTdIdW5XQEWAAmflSKEhcj2Xo5QA==", - "license": "MIT", - "dependencies": { - "@scalar/json-magic": "0.3.1", - "@scalar/openapi-types": "0.3.7", - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", - "ajv-formats": "^3.0.1", - "jsonpointer": "^5.0.1", - "leven": "^4.0.0", - "yaml": "2.8.0" - }, + "node_modules/astro/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/import/node_modules/@scalar/openapi-types": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.3.7.tgz", - "integrity": "sha512-QHSvHBVDze3+dUwAhIGq6l1iOev4jdoqdBK7QpfeN1Q4h+6qpVEw3EEqBiH0AXUSh/iWwObBv4uMgfIx0aNZ5g==", + "node_modules/astro/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "zod": "3.24.1" - }, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/import/node_modules/leven": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-4.0.0.tgz", - "integrity": "sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw==", + "node_modules/astro/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/@scalar/import/node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "node_modules/astro/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" } }, - "node_modules/@scalar/json-magic": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@scalar/json-magic/-/json-magic-0.3.1.tgz", - "integrity": "sha512-vQvl4TckiMT8Txo6S82ETJ4OI+K6iSxLZsjPaq4cEqY+9zVfmIMALFGPj/X5BB8tU3FdluV2yEa8LswsMQ68IA==", + "node_modules/astro/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@scalar/helpers": "0.0.8", - "vue": "^3.5.17", - "yaml": "2.8.0" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/oas-utils": { - "version": "0.4.22", - "resolved": "https://registry.npmjs.org/@scalar/oas-utils/-/oas-utils-0.4.22.tgz", - "integrity": "sha512-a8qvtU9GnHBKPvfflU2UF4mYi61Fc0V626bEgclCicwomrss7ic2MRyrwODmKR72F50Q2jWw0HeKE0DfqOjSPg==", + "node_modules/astro/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@hyperjump/browser": "^1.1.0", - "@hyperjump/json-schema": "^1.9.6", - "@scalar/helpers": "0.0.8", - "@scalar/json-magic": "0.3.1", - "@scalar/object-utils": "1.2.4", - "@scalar/openapi-types": "0.3.7", - "@scalar/themes": "0.13.14", - "@scalar/types": "0.2.13", - "@scalar/workspace-store": "0.14.2", - "@types/har-format": "^1.2.15", - "flatted": "^3.3.3", - "microdiff": "^1.5.0", - "nanoid": "5.1.5", - "type-fest": "4.41.0", - "yaml": "2.8.0", - "zod": "3.24.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/oas-utils/node_modules/@scalar/openapi-types": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.3.7.tgz", - "integrity": "sha512-QHSvHBVDze3+dUwAhIGq6l1iOev4jdoqdBK7QpfeN1Q4h+6qpVEw3EEqBiH0AXUSh/iWwObBv4uMgfIx0aNZ5g==", + "node_modules/astro/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "zod": "3.24.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/oas-utils/node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "node_modules/astro/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" } }, - "node_modules/@scalar/object-utils": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@scalar/object-utils/-/object-utils-1.2.4.tgz", - "integrity": "sha512-lX/+9Sp6euZvbsikGRZiHwmfbLd0oTLTttKbJF9v2EkahSrQUT0WF835Ct2N0R8xSkyQauDhT2xCfuA0QNqDeA==", + "node_modules/astro/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], "license": "MIT", - "dependencies": { - "@scalar/helpers": "0.0.8", - "flatted": "^3.3.3", - "just-clone": "^6.2.0", - "ts-deepmerge": "^7.0.1", - "type-fest": "4.41.0" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/openapi-parser": { - "version": "0.10.17", - "resolved": "https://registry.npmjs.org/@scalar/openapi-parser/-/openapi-parser-0.10.17.tgz", - "integrity": "sha512-SO+vw+kv8xEROJ527KpiT5ccAVQZuE6n8G4qTN6b72QVT0URHoLwr8uHQQnEGlyA0QhAx7En+lKD1Hy39xZ9oQ==", + "node_modules/astro/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", - "ajv-formats": "^3.0.1", - "jsonpointer": "^5.0.1", - "leven": "^4.0.0", - "yaml": "^2.4.5" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { "node": ">=18" } }, - "node_modules/@scalar/openapi-parser/node_modules/leven": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-4.0.0.tgz", - "integrity": "sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw==", + "node_modules/astro/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/@scalar/openapi-types": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.2.3.tgz", - "integrity": "sha512-O1GwqLpcRc3GKXTbeBZ5E12fXR2ltpqGWk4RfhoN4ebKZsPVknV5at5425G97E1SwMy12BporRvn90k1Z+MruQ==", + "node_modules/astro/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], "license": "MIT", - "dependencies": { - "zod": "3.24.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { "node": ">=18" } }, - "node_modules/@scalar/openapi-types/node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "node_modules/astro/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" } }, - "node_modules/@scalar/postman-to-openapi": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@scalar/postman-to-openapi/-/postman-to-openapi-0.3.25.tgz", - "integrity": "sha512-sMf85+uCjmzgyZ8pS7MbVm5FOVj/9SGOT/RX4xDG8LklpE77SQdYXO1G50kj8XEHMwLpsMh5Ufbt5Wft54DqlQ==", + "node_modules/astro/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@scalar/helpers": "0.0.8", - "@scalar/oas-utils": "0.4.22", - "@scalar/openapi-types": "0.3.7" - }, + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/postman-to-openapi/node_modules/@scalar/openapi-types": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.3.7.tgz", - "integrity": "sha512-QHSvHBVDze3+dUwAhIGq6l1iOev4jdoqdBK7QpfeN1Q4h+6qpVEw3EEqBiH0AXUSh/iWwObBv4uMgfIx0aNZ5g==", + "node_modules/astro/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "zod": "3.24.1" - }, + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/postman-to-openapi/node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "node_modules/astro/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" } }, - "node_modules/@scalar/snippetz": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/@scalar/snippetz/-/snippetz-0.4.7.tgz", - "integrity": "sha512-SvjpZ8qVaGAxoypqsJLAlM95XEjccDXXEvd3ljlCoOYzG06tbMX+g8+Vfsv/FjMXQ0LB3/ZfpYjTrKO8h7ZU4Q==", + "node_modules/astro/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@scalar/types": "0.2.13", - "stringify-object": "^5.0.0" - }, + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/snippetz/node_modules/is-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz", - "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==", + "node_modules/astro/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/@scalar/snippetz/node_modules/is-regexp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", - "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==", + "node_modules/astro/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "peer": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/@scalar/snippetz/node_modules/stringify-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz", - "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==", - "license": "BSD-2-Clause", - "dependencies": { - "get-own-enumerable-keys": "^1.0.0", - "is-obj": "^3.0.0", - "is-regexp": "^3.1.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/yeoman/stringify-object?sponsor=1" - } - }, - "node_modules/@scalar/themes": { - "version": "0.13.14", - "resolved": "https://registry.npmjs.org/@scalar/themes/-/themes-0.13.14.tgz", - "integrity": "sha512-uYqWtzQuLaVAEcxRaLzIINRuocds2I+rj8dCHcg3RMdmvSn9oJ8ysEhOZGqzNE7nL5aD7sh2tFa2E4+iScWSyA==", - "license": "MIT", - "dependencies": { - "@scalar/types": "0.2.13", - "nanoid": "5.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@scalar/types": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.2.13.tgz", - "integrity": "sha512-rO6KGMJqOsBnN/2R4fErMFLpRSPVJElni+HABDpf+ZlLJp2lvxuPn0IXLumK5ytfplUH9iqKgSXjndnZfxSYLQ==", + "node_modules/astro/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@scalar/openapi-types": "0.3.7", - "nanoid": "5.1.5", - "zod": "3.24.1" - }, + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/types/node_modules/@scalar/openapi-types": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.3.7.tgz", - "integrity": "sha512-QHSvHBVDze3+dUwAhIGq6l1iOev4jdoqdBK7QpfeN1Q4h+6qpVEw3EEqBiH0AXUSh/iWwObBv4uMgfIx0aNZ5g==", + "node_modules/astro/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "zod": "3.24.1" - }, + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=20" - } - }, - "node_modules/@scalar/types/node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "node": ">=18" } }, - "node_modules/@scalar/use-codemirror": { - "version": "0.12.28", - "resolved": "https://registry.npmjs.org/@scalar/use-codemirror/-/use-codemirror-0.12.28.tgz", - "integrity": "sha512-4hxuSI1lKmOpEMI5Xvv88wWKj6e3KV6RJUsi46Sb5fOsO3aRgYMDopWvo96nk/4wXD+g2QJIITsSL2Ic7NVnxA==", + "node_modules/astro/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.18.3", - "@codemirror/commands": "^6.7.1", - "@codemirror/lang-css": "^6.3.1", - "@codemirror/lang-html": "^6.4.8", - "@codemirror/lang-json": "^6.0.0", - "@codemirror/lang-xml": "^6.0.0", - "@codemirror/lang-yaml": "^6.1.2", - "@codemirror/language": "^6.10.7", - "@codemirror/lint": "^6.8.4", - "@codemirror/state": "^6.5.0", - "@codemirror/view": "^6.35.3", - "@lezer/common": "^1.2.3", - "@lezer/highlight": "^1.2.1", - "@replit/codemirror-css-color-picker": "^6.3.0", - "@scalar/components": "0.14.27", - "codemirror": "^6.0.0", - "vue": "^3.5.17" - }, + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">=18" } }, - "node_modules/@scalar/use-hooks": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@scalar/use-hooks/-/use-hooks-0.2.4.tgz", - "integrity": "sha512-TXviVV9Cfmei6g24QadnfuFj2r1YkZY56ufsSnwHgLNbtDRd9U9jXGIswXAuA+k7whaEVEgcoZ3Zmq2v5ZLF8w==", + "node_modules/astro/node_modules/@shikijs/core": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz", + "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==", "license": "MIT", + "peer": true, "dependencies": { - "@scalar/use-toasts": "0.8.0", - "@vueuse/core": "^10.10.0", - "cva": "1.0.0-beta.2", - "tailwind-merge": "^2.5.5", - "vue": "^3.5.12", - "zod": "3.24.1" - }, - "engines": { - "node": ">=20" + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" } }, - "node_modules/@scalar/use-hooks/node_modules/@vueuse/core": { - "version": "10.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.1.tgz", - "integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==", + "node_modules/astro/node_modules/@shikijs/engine-javascript": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz", + "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==", "license": "MIT", + "peer": true, "dependencies": { - "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "10.11.1", - "@vueuse/shared": "10.11.1", - "vue-demi": ">=0.14.8" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" } }, - "node_modules/@scalar/use-hooks/node_modules/@vueuse/core/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, + "node_modules/astro/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, + "peer": true, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@scalar/use-hooks/node_modules/@vueuse/metadata": { - "version": "10.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.1.tgz", - "integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" + "node_modules/astro/node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">= 0.4" } }, - "node_modules/@scalar/use-hooks/node_modules/@vueuse/shared": { - "version": "10.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.1.tgz", - "integrity": "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==", + "node_modules/astro/node_modules/boxen": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", + "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", "license": "MIT", + "peer": true, "dependencies": { - "vue-demi": ">=0.14.8" + "ansi-align": "^3.0.1", + "camelcase": "^8.0.0", + "chalk": "^5.3.0", + "cli-boxes": "^3.0.0", + "string-width": "^7.2.0", + "type-fest": "^4.21.0", + "widest-line": "^5.0.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@scalar/use-hooks/node_modules/@vueuse/shared/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, + "node_modules/astro/node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, + "peer": true, "engines": { - "node": ">=12" + "node": ">=16" }, "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@scalar/use-hooks/node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "node_modules/astro/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "peer": true, + "engines": { + "node": ">=16" } }, - "node_modules/@scalar/use-toasts": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@scalar/use-toasts/-/use-toasts-0.8.0.tgz", - "integrity": "sha512-u+o77cdTNZ5ePqHPu8ZcFw1BLlISv+cthN0bR1zJHXmqBjvanFTy2kL+Gmv3eW9HxZiHdqycKVETlYd0mWiqJQ==", + "node_modules/astro/node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "license": "MIT", + "peer": true, "dependencies": { - "nanoid": "^5.1.5", - "vue": "^3.5.12", - "vue-sonner": "^1.0.3" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=20" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/@scalar/workspace-store": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/@scalar/workspace-store/-/workspace-store-0.14.2.tgz", - "integrity": "sha512-FLI//S2kxS4NxdKZ+SaMTUoMI7n2hZID/JznAid02+WU35QVA+Y3ioose7VzPRpDmPxeF3lhXgcPpcZ811yIjA==", - "license": "MIT", - "dependencies": { - "@scalar/code-highlight": "0.1.9", - "@scalar/helpers": "0.0.8", - "@scalar/json-magic": "0.3.1", - "@scalar/openapi-parser": "0.20.1", - "@scalar/types": "0.2.13", - "@sinclair/typebox": "https://raw.githubusercontent.com/DemonHa/typebox/refs/heads/amrit/build-2/target/sinclair-typebox-0.34.40.tgz", - "github-slugger": "^2.0.0", - "type-fest": "4.41.0", - "vue": "^3.5.17", - "yaml": "2.8.0" - }, + "node_modules/astro/node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "license": "BSD-3-Clause", + "peer": true, "engines": { - "node": ">=18" + "node": ">=0.3.1" } }, - "node_modules/@scalar/workspace-store/node_modules/@scalar/openapi-parser": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@scalar/openapi-parser/-/openapi-parser-0.20.1.tgz", - "integrity": "sha512-rxtuBQ90YsUEDefWU3GAEmvjYr1CvGO6nkDVzbjmWv2aPB3mtK80bCRBgQGTdIdW5XQEWAAmflSKEhcj2Xo5QA==", + "node_modules/astro/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT", - "dependencies": { - "@scalar/json-magic": "0.3.1", - "@scalar/openapi-types": "0.3.7", - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", - "ajv-formats": "^3.0.1", - "jsonpointer": "^5.0.1", - "leven": "^4.0.0", - "yaml": "2.8.0" - }, - "engines": { - "node": ">=20" - } + "peer": true }, - "node_modules/@scalar/workspace-store/node_modules/@scalar/openapi-types": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.3.7.tgz", - "integrity": "sha512-QHSvHBVDze3+dUwAhIGq6l1iOev4jdoqdBK7QpfeN1Q4h+6qpVEw3EEqBiH0AXUSh/iWwObBv4uMgfIx0aNZ5g==", + "node_modules/astro/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "zod": "3.24.1" + "peer": true, + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=20" - } + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/astro/node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT", + "peer": true }, - "node_modules/@scalar/workspace-store/node_modules/github-slugger": { + "node_modules/astro/node_modules/github-slugger": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", - "license": "ISC" + "license": "ISC", + "peer": true }, - "node_modules/@scalar/workspace-store/node_modules/leven": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-4.0.0.tgz", - "integrity": "sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw==", + "node_modules/astro/node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0", + "peer": true + }, + "node_modules/astro/node_modules/p-queue": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", + "integrity": "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==", "license": "MIT", + "peer": true, + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@scalar/workspace-store/node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "node_modules/astro/node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.16" + }, "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/@shikijs/engine-oniguruma": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.12.1.tgz", - "integrity": "sha512-hbYq+XOc55CU7Irkhsgwh8WgQbx2W5IVzHV4l+wZ874olMLSNg5o3F73vo9m4SAhimFyqq/86xnx9h+T30HhhQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.12.1", - "@shikijs/vscode-textmate": "^10.0.2" - } - }, - "node_modules/@shikijs/langs": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.12.1.tgz", - "integrity": "sha512-Y1MbMfVO5baRz7Boo7EoD36TmzfUx/I5n8e+wZumx6SlUA81Zj1ZwNJL871iIuSHrdsheV4AxJtHQ9mlooklmg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.12.1" - } - }, - "node_modules/@shikijs/themes": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.12.1.tgz", - "integrity": "sha512-9JrAm9cA5hqM/YXymA3oAAZdnCgQf1zyrNDtsnM105nNEoEpux4dyzdoOjc2KawEKj1iUs/WH2ota6Atp7GYkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.12.1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@shikijs/types": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.12.1.tgz", - "integrity": "sha512-Is/p+1vTss22LIsGCJTmGrxu7ZC1iBL9doJFYLaZ4aI8d0VDXb7Mn0kBzhkc7pdsRpmUbQLQ5HXwNpa3H6F8og==", - "dev": true, + "node_modules/astro/node_modules/shiki": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz", + "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==", "license": "MIT", + "peer": true, "dependencies": { + "@shikijs/core": "3.23.0", + "@shikijs/engine-javascript": "3.23.0", + "@shikijs/engine-oniguruma": "3.23.0", + "@shikijs/langs": "3.23.0", + "@shikijs/themes": "3.23.0", + "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, - "node_modules/@shikijs/vscode-textmate": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", - "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sideway/address": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", - "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", - "license": "BSD-3-Clause" - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@sinclair/typebox": { - "version": "0.34.40", - "resolved": "https://raw.githubusercontent.com/DemonHa/typebox/refs/heads/amrit/build-2/target/sinclair-typebox-0.34.40.tgz", - "integrity": "sha512-Kq7MAXpZSj/YOGET0UxWHPBokYxnlyEJNH3PnDqEgQxBlkmM0H0qexwPp7HBvMa7vcETDLQPNDM0X2kHPA4A+A==", - "license": "MIT" - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "node_modules/astro/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@slorber/remark-comment": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", - "integrity": "sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==", + "node_modules/astro/node_modules/svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.2.tgz", + "integrity": "sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==", "license": "MIT", + "peer": true, "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.1.0", - "micromark-util-symbol": "^1.0.1" + "commander": "^11.1.0", + "css-select": "^5.1.0", + "css-tree": "^3.0.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "^1.5.0" + }, + "bin": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" } }, - "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "node_modules/astro/node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "deprecated": "unmaintained", "license": "MIT", + "peer": true, + "bin": { + "tsconfck": "bin/tsconfck.js" + }, "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", - "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", - "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", - "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", - "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", - "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", - "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-preset": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", - "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", - "license": "MIT", - "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", - "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", - "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", - "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", - "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", - "@svgr/babel-plugin-transform-svg-component": "8.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node": "^18 || >=20" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/core": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", - "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^8.1.3", - "snake-case": "^3.0.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", - "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.21.3", - "entities": "^4.4.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/plugin-jsx": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", - "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "@svgr/hast-util-to-babel-ast": "8.0.0", - "svg-parser": "^2.0.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "typescript": "^5.0.0" }, - "peerDependencies": { - "@svgr/core": "*" + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@svgr/plugin-svgo": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", - "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", - "license": "MIT", - "dependencies": { - "cosmiconfig": "^8.1.3", - "deepmerge": "^4.3.1", - "svgo": "^3.0.2" + "node_modules/astro/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@svgr/core": "*" + "node": ">=14.17" } }, - "node_modules/@svgr/webpack": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", - "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "node_modules/astro/node_modules/vite": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", "license": "MIT", + "peer": true, "dependencies": { - "@babel/core": "^7.21.3", - "@babel/plugin-transform-react-constant-elements": "^7.21.3", - "@babel/preset-env": "^7.20.2", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.21.0", - "@svgr/core": "8.1.0", - "@svgr/plugin-jsx": "8.1.0", - "@svgr/plugin-svgo": "8.1.0" - }, - "engines": { - "node": ">=14" + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@swc/core": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.5.tgz", - "integrity": "sha512-WezcBo8a0Dg2rnR82zhwoR6aRNxeTGfK5QCD6TQ+kg3xx/zNT02s/0o+81h/3zhvFSB24NtqEr8FTw88O5W/JQ==", - "devOptional": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.24" + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=10" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" + "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.13.5", - "@swc/core-darwin-x64": "1.13.5", - "@swc/core-linux-arm-gnueabihf": "1.13.5", - "@swc/core-linux-arm64-gnu": "1.13.5", - "@swc/core-linux-arm64-musl": "1.13.5", - "@swc/core-linux-x64-gnu": "1.13.5", - "@swc/core-linux-x64-musl": "1.13.5", - "@swc/core-win32-arm64-msvc": "1.13.5", - "@swc/core-win32-ia32-msvc": "1.13.5", - "@swc/core-win32-x64-msvc": "1.13.5" + "fsevents": "~2.3.3" }, "peerDependencies": { - "@swc/helpers": ">=0.5.17" + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { - "@swc/helpers": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.13.5.tgz", - "integrity": "sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ - "arm64" + "ppc64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "darwin" + "aix" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.13.5.tgz", - "integrity": "sha512-ILd38Fg/w23vHb0yVjlWvQBoE37ZJTdlLHa8LRCFDdX4WKfnVBiblsCU9ar4QTMNdeTBEX9iUF4IrbNWhaF1Ng==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ - "x64" + "arm" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "darwin" + "android" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.13.5.tgz", - "integrity": "sha512-Q6eS3Pt8GLkXxqz9TAw+AUk9HpVJt8Uzm54MvPsqp2yuGmY0/sNaPPNVqctCX9fu/Nu8eaWUen0si6iEiCsazQ==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ - "arm" + "arm64" ], - "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.13.5.tgz", - "integrity": "sha512-aNDfeN+9af+y+M2MYfxCzCy/VDq7Z5YIbMqRI739o8Ganz6ST+27kjQFd8Y/57JN/hcnUEa9xqdS3XY7WaVtSw==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ - "arm64" + "x64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.13.5.tgz", - "integrity": "sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.13.5.tgz", - "integrity": "sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.13.5.tgz", - "integrity": "sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ - "x64" + "arm64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "linux" + "freebsd" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.13.5.tgz", - "integrity": "sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ - "arm64" + "x64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "win32" + "freebsd" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.13.5.tgz", - "integrity": "sha512-C5Yi/xIikrFUzZcyGj9L3RpKljFvKiDMtyDzPKzlsDrKIw2EYY+bF88gB6oGY5RGmv4DAX8dbnpRAqgFD0FMEw==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ - "ia32" + "arm" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.13.5.tgz", - "integrity": "sha512-YrKdMVxbYmlfybCSbRtrilc6UA8GF5aPmGKBdPvjrarvsmf4i7ZHGCEnLtfOMd3Lwbs2WUZq3WdMbozYeLU93Q==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ - "x64" + "arm64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], + "peer": true, "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "devOptional": true, - "license": "Apache-2.0" - }, - "node_modules/@swc/helpers": { - "version": "0.5.17", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", - "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.8.0" + "node": ">=18" } }, - "node_modules/@swc/html": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html/-/html-1.13.5.tgz", - "integrity": "sha512-eVAyb3kk6wltz4FnWNRL06iYnqkQuTfpe5Fin9oLLmcpIYr2DgHcrGgeDJF4vJc9YZwACvEYmV8DC+1NfdzAJQ==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3" - }, - "engines": { - "node": ">=14" - }, - "optionalDependencies": { - "@swc/html-darwin-arm64": "1.13.5", - "@swc/html-darwin-x64": "1.13.5", - "@swc/html-linux-arm-gnueabihf": "1.13.5", - "@swc/html-linux-arm64-gnu": "1.13.5", - "@swc/html-linux-arm64-musl": "1.13.5", - "@swc/html-linux-x64-gnu": "1.13.5", - "@swc/html-linux-x64-musl": "1.13.5", - "@swc/html-win32-arm64-msvc": "1.13.5", - "@swc/html-win32-ia32-msvc": "1.13.5", - "@swc/html-win32-x64-msvc": "1.13.5" - } - }, - "node_modules/@swc/html-darwin-arm64": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html-darwin-arm64/-/html-darwin-arm64-1.13.5.tgz", - "integrity": "sha512-5r4kGFQJm85EKOxSiP9pUT/9T1uq+tx0s5HRqfM/J1hVZmpIq2GudBVYS8CGklVWAVQ0tBHhBuP9SysAb/pcSA==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ - "arm64" + "ia32" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "darwin" + "linux" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/html-darwin-x64": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html-darwin-x64/-/html-darwin-x64-1.13.5.tgz", - "integrity": "sha512-bCY0BSfxrmbKpInB/wZFX0DH4hgEQBwWLeKNwZhafIR5R/tvzuiIvb/VdkeKv8+26r2lkedbp+EreCFnDqQ2BQ==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ - "x64" + "loong64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "darwin" + "linux" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/html-linux-arm-gnueabihf": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html-linux-arm-gnueabihf/-/html-linux-arm-gnueabihf-1.13.5.tgz", - "integrity": "sha512-o6TVZERfx7Z8btauYE7nHgMEPPIVemqAZL3ViUTuBK6asF9wfJ4m2YAbsrlzi8xaLgaizWvdUV7W1qE5yfOxPg==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ - "arm" + "mips64el" ], - "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/html-linux-arm64-gnu": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html-linux-arm64-gnu/-/html-linux-arm64-gnu-1.13.5.tgz", - "integrity": "sha512-I/Ip5FtCfQ0wYg2MurytkEWPZrFB1SOPOeTNu4n+PAWDBjEcX3q+wgmMpzoGgVljvpEAQviJ+jzRyLW2tDDVHA==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ - "arm64" + "ppc64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/html-linux-arm64-musl": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html-linux-arm64-musl/-/html-linux-arm64-musl-1.13.5.tgz", - "integrity": "sha512-q8RTISYZuI5qOR8wEhox2oC+ZBo5IBaT6N43b5W+JRSIMKIsY7hVgC3gSI/tG4/6K14hv2QrqtAUFzVpLwtkyA==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ - "arm64" + "riscv64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/html-linux-x64-gnu": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html-linux-x64-gnu/-/html-linux-x64-gnu-1.13.5.tgz", - "integrity": "sha512-YFU0/xVWzjAtg5V6QREW510O5/SNILrm18Vo2qF1bTktCB2eCjNSjCHOdicvPXTImEUlTp0ey6wO+QvEuvRFAg==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ - "x64" + "s390x" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/html-linux-x64-musl": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html-linux-x64-musl/-/html-linux-x64-musl-1.13.5.tgz", - "integrity": "sha512-/ilgZm7umDQTea97FlE0pIcoHTAlICE+aSoVvLi+ONL3wr4g1ebwlgQ5Cxpgp5cxnKeghDYpqP/mFLh+Ztl8DQ==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/html-win32-arm64-msvc": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html-win32-arm64-msvc/-/html-win32-arm64-msvc-1.13.5.tgz", - "integrity": "sha512-aLZvyEhzM6e7E53jelEp9ob/CrZ4K0atmsq+ctsaki8PNOu8shM03CEK1yQNCdZLR1kKkUgytyUVMEbhqz+IQQ==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "cpu": [ "arm64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "win32" + "netbsd" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/html-win32-ia32-msvc": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html-win32-ia32-msvc/-/html-win32-ia32-msvc-1.13.5.tgz", - "integrity": "sha512-51QXTdKMmgRriRmTzH0gkeyHLY4knJdAKEY1kPTBeguXCjgLIUX2nMQd24oe9ovJfPce0NCOmCSrODri8PiduQ==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ - "ia32" + "x64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "win32" + "netbsd" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/html-win32-x64-msvc": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/html-win32-x64-msvc/-/html-win32-x64-msvc-1.13.5.tgz", - "integrity": "sha512-MnU1fMNZijEKkKTp12SKbNuH7rglgHhXSFZr+zjDhQmtVPEF4goCrBfoY8ZJ4j9FjOGyodFcYH6ulz95l9/QwQ==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ - "x64" + "arm64" ], - "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "win32" + "openbsd" ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/types": { - "version": "0.1.24", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.24.tgz", - "integrity": "sha512-tjTMh3V4vAORHtdTprLlfoMptu1WfTZG9Rsca6yOKyNYsRr+MUXutKmliB17orgSZk5DpnDxs8GUdd/qwYxOng==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3" + "node_modules/astro/node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" } }, - "node_modules/@szmarczak/http-timer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", - "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "defer-to-connect": "^2.0.1" - }, + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, "engines": { - "node": ">=14.16" + "node": ">=18" } }, - "node_modules/@tanstack/virtual-core": { - "version": "3.13.12", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.12.tgz", - "integrity": "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=18" } }, - "node_modules/@tanstack/vue-virtual": { - "version": "3.13.12", - "resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.13.12.tgz", - "integrity": "sha512-vhF7kEU9EXWXh+HdAwKJ2m3xaOnTTmgcdXcF2pim8g4GvI7eRrk2YRuV5nUlZnd/NbCIX4/Ja2OZu5EjJL06Ww==", + "node_modules/astro/node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@tanstack/virtual-core": "3.13.12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "vue": "^2.7.0 || ^3.0.0" + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", - "dev": true, + "node_modules/astro/node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" - }, "engines": { "node": ">=18" } }, - "node_modules/@testing-library/jest-dom": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.8.0.tgz", - "integrity": "sha512-WgXcWzVM6idy5JaftTVC8Vs83NKRmGJz4Hqs4oyOuO2J4r/y79vvKZsb+CaGyCSEbUPI6OsewfPd0G1A0/TUZQ==", - "dev": true, + "node_modules/astro/node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@adobe/css-tools": "^4.4.0", - "aria-query": "^5.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "picocolors": "^1.1.1", - "redent": "^3.0.0" - }, + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" + "node": ">=18" } }, - "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@testing-library/react": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz", - "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==", - "dev": true, + "node_modules/astro/node_modules/vite/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.5" + "peer": true, + "bin": { + "esbuild": "bin/esbuild" }, "engines": { "node": ">=18" }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0 || ^19.0.0", - "@types/react-dom": "^18.0.0 || ^19.0.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/astro/node_modules/widest-line": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", + "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", + "license": "MIT", + "peer": true, + "dependencies": { + "string-width": "^7.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", - "dev": true, + "node_modules/astro/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">=12", - "npm": ">=6" + "node": ">=18" }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "license": "ISC", - "engines": { - "node": ">=10.13.0" + "node_modules/astro/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", - "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "node_modules/astro/node_modules/zod-to-ts": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz", + "integrity": "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==", + "peer": true, + "peerDependencies": { + "typescript": "^4.9.4 || ^5.0.2", + "zod": "^3" } }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "license": "MIT", - "peer": true + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } + "node_modules/async-sema": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz", + "integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==", + "license": "MIT" }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", + "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/types": "^7.26.0" } }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base-64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", + "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" + "peer": true + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.6.tgz", + "integrity": "sha512-69D/imtToCsIcAl8WBS2YaRwA4jO/j0HhU+hELqMEu9f54MoUtI6+XH5mrKU8rEFNEk/Ui1I2MK4/JkWacclGw==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "license": "MIT", "dependencies": { - "@types/node": "*" + "file-uri-to-path": "1.0.0" } }, - "node_modules/@types/bun": { - "version": "1.2.21", - "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.2.21.tgz", - "integrity": "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A==", - "dev": true, - "license": "MIT", - "dependencies": { - "bun-types": "1.2.21" + "node_modules/blume": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/blume/-/blume-1.2.0.tgz", + "integrity": "sha512-VA8TJfSgTp1bRvCPJjufZl+coMRcDSQZvQ5Mx4Qut14TjdO1nB6PY2oOv6zZI11IAQpX/ft9l7i1KzNeXXxNLQ==", + "license": "MIT", + "dependencies": { + "@astrojs/check": "^0.9.0", + "@astrojs/markdown-satteri": "^0.3.2", + "@astrojs/mdx": "^7.0.0", + "@astrojs/node": "^11.0.0", + "@astrojs/react": "^6.0.0", + "@astrojs/vercel": "^11.0.0", + "@clack/prompts": "^1.7.0", + "@iconify-json/lucide": "^1.2.115", + "@iconify/types": "^2.0.0", + "@iconify/utils": "^3.1.3", + "@modelcontextprotocol/sdk": "^1.29.0", + "@orama/orama": "^3.1.18", + "@pierre/diffs": "^1.2.11", + "@scalar/astro": "^0.4.5", + "@scalar/openapi-parser": "^0.28.8", + "@scalar/openapi-types": "^0.9.1", + "@shikijs/transformers": "^4.2.0", + "@shikijs/twoslash": "^4.2.0", + "@tailwindcss/typography": "^0.5.20", + "@tailwindcss/vite": "^4", + "@vercel/analytics": "^2.0.1", + "ai": "^5.0.0", + "astro": "^7.0.2", + "babel-plugin-react-compiler": "^1.0.0", + "citty": "^0.1.6", + "consola": "^3.4.0", + "dompurify": "^3.4.11", + "epub-gen-memory": "^1.1.2", + "github-slugger": "^2.0.0", + "gray-matter": "^4.0.3", + "jiti": "^2.4.0", + "js-yaml": "^4.1.0", + "katex": "^0.17.0", + "marked": "^18.0.5", + "mermaid": "^11.15.0", + "node-html-parser": "^9.0.0", + "pagefind": "^1.3.0", + "pathe": "^2.0.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "satteri": "^0.9.5", + "shiki": "^4.2.0", + "simple-icons": "^13.0.0", + "tailwindcss": "^4", + "takumi-js": "^2.2.1", + "tinyglobby": "^0.2.10", + "twoslash": "^0.3.9", + "typescript": "^6.0.3", + "undici": "^8.6.0", + "zod": "^3.24.0" + }, + "bin": { + "blume": "bin/blume.mjs" + }, + "engines": { + "node": ">=22.12.0" + }, + "peerDependencies": { + "@ai-sdk/openai-compatible": "^1.0.41", + "@astrojs/cloudflare": "^14.0.0", + "@astrojs/netlify": "^8.0.0", + "@astrojs/svelte": "^9.0.0", + "@astrojs/vue": "^7.0.0", + "@mixedbread/sdk": "^0.76.0", + "@notionhq/client": "^2.2.15", + "@openrouter/ai-sdk-provider": "^1.5.4", + "@oramacloud/client": "^2.1.0", + "@sanity/client": "^6.21.0", + "algoliasearch": "^5.55.0", + "flexsearch": "^0.8.0", + "typesense": "^3.0.0" + }, + "peerDependenciesMeta": { + "@ai-sdk/openai-compatible": { + "optional": true + }, + "@astrojs/cloudflare": { + "optional": true + }, + "@astrojs/netlify": { + "optional": true + }, + "@astrojs/svelte": { + "optional": true + }, + "@astrojs/vue": { + "optional": true + }, + "@mixedbread/sdk": { + "optional": true + }, + "@notionhq/client": { + "optional": true + }, + "@openrouter/ai-sdk-provider": { + "optional": true + }, + "@oramacloud/client": { + "optional": true + }, + "@sanity/client": { + "optional": true + }, + "algoliasearch": { + "optional": true + }, + "flexsearch": { + "optional": true + }, + "typesense": { + "optional": true + } } }, - "node_modules/@types/chai": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", - "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", - "dev": true, + "node_modules/blume/node_modules/@astrojs/mdx": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-7.0.5.tgz", + "integrity": "sha512-wEM/HH1RiEntyPVagdiF+yArzfcYLKBB0C1RZspVidKZ97rRMbaqP1Nbl/GR0sJs8zwaceqxRymw8aOKKJRdYw==", "license": "MIT", "dependencies": { - "@types/deep-eql": "*" + "@astrojs/internal-helpers": "0.10.2", + "@astrojs/markdown-remark": "7.2.2", + "@mdx-js/mdx": "^3.1.1", + "acorn": "^8.16.0", + "es-module-lexer": "^2.0.0", + "estree-util-visit": "^2.0.0", + "hast-util-to-html": "^9.0.5", + "piccolore": "^0.1.3", + "rehype-raw": "^7.0.0", + "remark-gfm": "^4.0.1", + "remark-smartypants": "^3.0.2", + "source-map": "^0.7.6", + "unist-util-visit": "^5.1.0", + "vfile": "^6.0.3" + }, + "engines": { + "node": ">=22.12.0" + }, + "peerDependencies": { + "@astrojs/markdown-satteri": "^0.3.1", + "astro": "^7.0.0" + }, + "peerDependenciesMeta": { + "@astrojs/markdown-satteri": { + "optional": true + } } }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "node_modules/blume/node_modules/@astrojs/node": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@astrojs/node/-/node-11.0.3.tgz", + "integrity": "sha512-T5BLn3gh9qpWpPK4vcpsnCmFyU3TL4u7m1n33D+h1uEuUVMjmald5QryZI7B/PwlM9fk09s+DQupy6a61wfi9A==", "license": "MIT", "dependencies": { - "@types/node": "*" + "@astrojs/internal-helpers": "0.10.2", + "send": "^1.2.1", + "server-destroy": "^1.0.1" + }, + "peerDependencies": { + "astro": "^7.0.0" } }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "node_modules/blume/node_modules/@astrojs/telemetry": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.3.tgz", + "integrity": "sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==", "license": "MIT", "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" + "ci-info": "^4.4.0", + "dset": "^3.1.4", + "is-docker": "^4.0.0", + "package-manager-detector": "^1.6.0" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0" } }, - "node_modules/@types/css-font-loading-module": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz", - "integrity": "sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==", - "license": "MIT" - }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "node_modules/blume/node_modules/@astrojs/vercel": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@astrojs/vercel/-/vercel-11.0.4.tgz", + "integrity": "sha512-8HXVXTdpjSCNrIRSY4gOMmLntYUgl+b6FsXSNPWGbvpWR/SAXRbkZR4FJOmjzeI7L4Z8teBsQLdxwdQsSnGtYg==", "license": "MIT", "dependencies": { - "@types/ms": "*" + "@astrojs/internal-helpers": "0.10.2", + "@vercel/analytics": "^1.6.1", + "@vercel/functions": "^3.4.3", + "@vercel/nft": "^1.3.2", + "@vercel/routing-utils": "^5.3.3", + "esbuild": "^0.28.0", + "tinyglobby": "^0.2.15" + }, + "peerDependencies": { + "astro": "^7.0.0" } }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" + "node_modules/blume/node_modules/@astrojs/vercel/node_modules/@vercel/analytics": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.6.1.tgz", + "integrity": "sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==", + "license": "MPL-2.0", + "peerDependencies": { + "@remix-run/react": "^2", + "@sveltejs/kit": "^1 || ^2", + "next": ">= 13", + "react": "^18 || ^19 || ^19.0.0-rc", + "svelte": ">= 4", + "vue": "^3", + "vue-router": "^4" + }, + "peerDependenciesMeta": { + "@remix-run/react": { + "optional": true + }, + "@sveltejs/kit": { + "optional": true + }, + "next": { + "optional": true + }, + "react": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + }, + "vue-router": { + "optional": true + } } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "node_modules/blume/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "license": "MIT" - }, - "node_modules/@types/estree-jsx": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "node_modules/blume/node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@types/estree": "*" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/express": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", - "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", + "node_modules/blume/node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/express-serve-static-core": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz", - "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", + "node_modules/blume/node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/express/node_modules/@types/express-serve-static-core": { - "version": "4.19.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", - "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "node_modules/blume/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/fs-extra": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", - "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", - "dev": true, + "node_modules/blume/node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@types/jsonfile": "*", - "@types/node": "*" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/gtag.js": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz", - "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==", - "license": "MIT" - }, - "node_modules/@types/har-format": { - "version": "1.2.16", - "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.16.tgz", - "integrity": "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==", - "license": "MIT" - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "node_modules/blume/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@types/unist": "*" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/history": { - "version": "4.7.11", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", - "license": "MIT" - }, - "node_modules/@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "license": "MIT" - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "license": "MIT" - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "license": "MIT" - }, - "node_modules/@types/http-proxy": { - "version": "1.17.16", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", - "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", + "node_modules/blume/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@types/node": "*" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "node_modules/blume/node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "node_modules/blume/node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "license": "MIT" - }, - "node_modules/@types/jsonfile": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", - "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", - "dev": true, + "node_modules/blume/node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "@types/node": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "node_modules/blume/node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], "license": "MIT", - "dependencies": { - "@types/unist": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/mdx": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", - "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", - "license": "MIT" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.18.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.0.tgz", - "integrity": "sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ==", + "node_modules/blume/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/node-forge": { - "version": "1.3.14", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", - "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", + "node_modules/blume/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "@types/node": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/prismjs": { - "version": "1.26.5", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", - "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", - "license": "MIT" - }, - "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "19.1.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz", - "integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==", + "node_modules/blume/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], "license": "MIT", - "dependencies": { - "csstype": "^3.0.2" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/react-router": { - "version": "5.1.20", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", - "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "node_modules/blume/node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/react-router-config": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz", - "integrity": "sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw==", + "node_modules/blume/node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "^5.1.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/react-router-dom": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", - "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "node_modules/blume/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "*" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "license": "MIT" - }, - "node_modules/@types/sax": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", - "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "node_modules/blume/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@types/node": "*" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/send": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", - "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "node_modules/blume/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "node_modules/blume/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@types/express": "*" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/serve-static": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", - "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "node_modules/blume/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "node_modules/blume/node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, - "node_modules/@types/web-bluetooth": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", - "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", - "license": "MIT" - }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "node_modules/blume/node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "license": "MIT" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "license": "ISC" - }, - "node_modules/@unhead/dom": { - "version": "1.11.20", - "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.11.20.tgz", - "integrity": "sha512-jgfGYdOH+xHJF/j8gudjsYu3oIjFyXhCWcgKaw3vQnT616gSqyqnGQGOItL+BQtQZACKNISwIfx5PuOtztMKLA==", + "node_modules/blume/node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "@unhead/schema": "1.11.20", - "@unhead/shared": "1.11.20" - }, - "funding": { - "url": "https://github.com/sponsors/harlan-zw" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@unhead/schema": { - "version": "1.11.20", - "resolved": "https://registry.npmjs.org/@unhead/schema/-/schema-1.11.20.tgz", - "integrity": "sha512-0zWykKAaJdm+/Y7yi/Yds20PrUK7XabLe9c3IRcjnwYmSWY6z0Cr19VIs3ozCj8P+GhR+/TI2mwtGlueCEYouA==", + "node_modules/blume/node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "hookable": "^5.5.3", - "zhead": "^2.2.4" - }, - "funding": { - "url": "https://github.com/sponsors/harlan-zw" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@unhead/shared": { - "version": "1.11.20", - "resolved": "https://registry.npmjs.org/@unhead/shared/-/shared-1.11.20.tgz", - "integrity": "sha512-1MOrBkGgkUXS+sOKz/DBh4U20DNoITlJwpmvSInxEUNhghSNb56S0RnaHRq0iHkhrO/cDgz2zvfdlRpoPLGI3w==", + "node_modules/blume/node_modules/@vercel/analytics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-2.0.1.tgz", + "integrity": "sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g==", "license": "MIT", - "dependencies": { - "@unhead/schema": "1.11.20", - "packrup": "^0.1.2" + "peerDependencies": { + "@remix-run/react": "^2", + "@sveltejs/kit": "^1 || ^2", + "next": ">= 13", + "nuxt": ">= 3", + "react": "^18 || ^19 || ^19.0.0-rc", + "svelte": ">= 4", + "vue": "^3", + "vue-router": "^4" }, - "funding": { - "url": "https://github.com/sponsors/harlan-zw" + "peerDependenciesMeta": { + "@remix-run/react": { + "optional": true + }, + "@sveltejs/kit": { + "optional": true + }, + "next": { + "optional": true + }, + "nuxt": { + "optional": true + }, + "react": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + }, + "vue-router": { + "optional": true + } } }, - "node_modules/@unhead/vue": { - "version": "1.11.20", - "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-1.11.20.tgz", - "integrity": "sha512-sqQaLbwqY9TvLEGeq8Fd7+F2TIuV3nZ5ihVISHjWpAM3y7DwNWRU7NmT9+yYT+2/jw1Vjwdkv5/HvDnvCLrgmg==", - "license": "MIT", + "node_modules/blume/node_modules/ai": { + "version": "5.0.222", + "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.222.tgz", + "integrity": "sha512-RdTURjrJXJFMOs7vsojKbeRdoeTSHjQ3VvavR7WHfQZF93enBpl584Un6bh2C86UjcECFPk7JEpCxqNFbh1HmA==", + "license": "Apache-2.0", "dependencies": { - "@unhead/schema": "1.11.20", - "@unhead/shared": "1.11.20", - "hookable": "^5.5.3", - "unhead": "1.11.20" + "@ai-sdk/gateway": "2.0.121", + "@ai-sdk/provider": "2.0.3", + "@ai-sdk/provider-utils": "3.0.30", + "@opentelemetry/api": "1.9.0" }, - "funding": { - "url": "https://github.com/sponsors/harlan-zw" + "engines": { + "node": ">=18" }, "peerDependencies": { - "vue": ">=2.7 || >=3" + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, + "node_modules/blume/node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "node": ">= 0.4" } }, - "node_modules/@vitest/expect": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", - "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "tinyrainbow": "^2.0.0" + "node_modules/blume/node_modules/astro": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/astro/-/astro-7.1.5.tgz", + "integrity": "sha512-3Yi3cPzVkudPcwStEaNzglu3hM2tjZ3NyhG8shUTMpcSX+8clQta23dMz41I44fiaMCp37H9K/5P2AudN6YKwg==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler-rs": "^0.3.1", + "@astrojs/internal-helpers": "0.10.2", + "@astrojs/markdown-satteri": "0.3.5", + "@astrojs/telemetry": "3.3.3", + "@capsizecss/unpack": "^4.0.0", + "@clack/prompts": "^1.1.0", + "@oslojs/encoding": "^1.1.0", + "@rollup/pluginutils": "^5.3.0", + "am-i-vibing": "^0.4.0", + "aria-query": "^5.3.2", + "axobject-query": "^4.1.0", + "ci-info": "^4.4.0", + "clsx": "^2.1.1", + "common-ancestor-path": "^2.0.0", + "cookie": "^2.0.1", + "devalue": "^5.8.1", + "diff": "^8.0.3", + "dset": "^3.1.4", + "es-module-lexer": "^2.0.0", + "esbuild": "^0.28.0", + "flattie": "^1.1.1", + "fontace": "~0.4.1", + "get-tsconfig": "5.0.0-beta.4", + "github-slugger": "^2.0.0", + "html-escaper": "3.0.3", + "http-cache-semantics": "^4.2.0", + "js-yaml": "^4.3.0", + "jsonc-parser": "^3.3.1", + "magic-string": "^1.0.0", + "magicast": "^0.5.2", + "mrmime": "^2.0.1", + "neotraverse": "^1.0.1", + "obug": "^2.1.1", + "p-limit": "^7.3.0", + "p-queue": "^9.1.0", + "package-manager-detector": "^1.6.0", + "piccolore": "^0.1.3", + "picomatch": "^4.0.4", + "semver": "^7.7.4", + "shiki": "^4.0.2", + "smol-toml": "^1.6.0", + "svgo": "^4.0.1", + "tinyclip": "^0.1.12", + "tinyexec": "^1.0.4", + "tinyglobby": "^0.2.15", + "ultrahtml": "^1.6.0", + "unifont": "~0.7.4", + "unstorage": "^1.17.5", + "vite": "^8.0.13", + "vitefu": "^1.1.2", + "xxhash-wasm": "^1.1.0", + "yargs-parser": "^22.0.0", + "zod": "^4.3.6" }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", - "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "3.2.4", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.17" + "bin": { + "astro": "bin/astro.mjs" + }, + "engines": { + "node": ">=22.12.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/astrodotbuild" + }, + "optionalDependencies": { + "sharp": "^0.34.0 || ^0.35.0" }, "peerDependencies": { - "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + "@astrojs/markdown-remark": "7.2.2" }, "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { + "@astrojs/markdown-remark": { "optional": true } } }, - "node_modules/@vitest/pretty-format": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", - "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", - "dev": true, + "node_modules/blume/node_modules/astro/node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", - "dependencies": { - "tinyrainbow": "^2.0.0" - }, "funding": { - "url": "https://opencollective.com/vitest" + "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/@vitest/runner": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", - "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", - "dev": true, + "node_modules/blume/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "license": "MIT", - "dependencies": { - "@vitest/utils": "3.2.4", - "pathe": "^2.0.3", - "strip-literal": "^3.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=16" } }, - "node_modules/@vitest/snapshot": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", - "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "3.2.4", - "magic-string": "^0.30.17", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "node_modules/blume/node_modules/common-ancestor-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz", + "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" } }, - "node_modules/@vitest/spy": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", - "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", - "dev": true, + "node_modules/blume/node_modules/cookie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==", "license": "MIT", - "dependencies": { - "tinyspy": "^4.0.3" + "engines": { + "node": ">=22" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@vitest/utils": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", - "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", - "dev": true, + "node_modules/blume/node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.4", - "loupe": "^3.1.4", - "tinyrainbow": "^2.0.0" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/@vue/compiler-core": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.20.tgz", - "integrity": "sha512-8TWXUyiqFd3GmP4JTX9hbiTFRwYHgVL/vr3cqhr4YQ258+9FADwvj7golk2sWNGHR67QgmCZ8gz80nQcMokhwg==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.3", - "@vue/shared": "3.5.20", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" + "node_modules/blume/node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" } }, - "node_modules/@vue/compiler-core/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "node_modules/blume/node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", "license": "MIT" }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.20.tgz", - "integrity": "sha512-whB44M59XKjqUEYOMPYU0ijUV0G+4fdrHVKDe32abNdX/kJe1NUEMqsi4cwzXa9kyM9w5S8WqFsrfo1ogtBZGQ==", + "node_modules/blume/node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.20", - "@vue/shared": "3.5.20" + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/blume/node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/blume/node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" + }, + "node_modules/blume/node_modules/is-docker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-4.0.0.tgz", + "integrity": "sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.20.tgz", - "integrity": "sha512-SFcxapQc0/feWiSBfkGsa1v4DOrnMAQSYuvDMpEaxbpH5dKbnEM5KobSNSgU+1MbHCl+9ftm7oQWxvwDB6iBfw==", + "node_modules/blume/node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.3", - "@vue/compiler-core": "3.5.20", - "@vue/compiler-dom": "3.5.20", - "@vue/compiler-ssr": "3.5.20", - "@vue/shared": "3.5.20", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.17", - "postcss": "^8.5.6", - "source-map-js": "^1.2.1" + "bin": { + "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "node_modules/blume/node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "license": "MIT" }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.20.tgz", - "integrity": "sha512-RSl5XAMc5YFUXpDQi+UQDdVjH9FnEpLDHIALg5J0ITHxkEzJ8uQLlo7CIbjPYqmZtt6w0TsIPbo1izYXwDG7JA==", + "node_modules/blume/node_modules/magic-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.1.0.tgz", + "integrity": "sha512-kS3VHe0nEPST2saQV4Rbkchcd3UBRkVTQHo1D3h/ZTwFDhai/mfKkmtPAtD129EOI7K3HlHIsFOt0WrI2/oU9g==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.20", - "@vue/shared": "3.5.20" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/@vue/devtools-api": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", - "license": "MIT" - }, - "node_modules/@vue/reactivity": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.20.tgz", - "integrity": "sha512-hS8l8x4cl1fmZpSQX/NXlqWKARqEsNmfkwOIYqtR2F616NGfsLUm0G6FQBK6uDKUCVyi1YOL8Xmt/RkZcd/jYQ==", - "license": "MIT", - "dependencies": { - "@vue/shared": "3.5.20" - } + "node_modules/blume/node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" }, - "node_modules/@vue/runtime-core": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.20.tgz", - "integrity": "sha512-vyQRiH5uSZlOa+4I/t4Qw/SsD/gbth0SW2J7oMeVlMFMAmsG1rwDD6ok0VMmjXY3eI0iHNSSOBilEDW98PLRKw==", + "node_modules/blume/node_modules/neotraverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-1.0.1.tgz", + "integrity": "sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==", "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.20", - "@vue/shared": "3.5.20" + "engines": { + "node": ">= 10" } }, - "node_modules/@vue/runtime-dom": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.20.tgz", - "integrity": "sha512-KBHzPld/Djw3im0CQ7tGCpgRedryIn4CcAl047EhFTCCPT2xFf4e8j6WeKLgEEoqPSl9TYqShc3Q6tpWpz/Xgw==", + "node_modules/blume/node_modules/p-limit": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.1.tgz", + "integrity": "sha512-0trZaiG7Y7kN/Egy9a8j47t9osC0Tch4PaIWd9yGF6bvmlk7muExRvGNYb8sXBwEKMoNKsbNN9P8EefuQekE4Q==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.20", - "@vue/runtime-core": "3.5.20", - "@vue/shared": "3.5.20", - "csstype": "^3.1.3" + "yocto-queue": "^1.2.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@vue/server-renderer": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.20.tgz", - "integrity": "sha512-HthAS0lZJDH21HFJBVNTtx+ULcIbJQRpjSVomVjfyPkFSpCwvsPTA+jIzOaUm3Hrqx36ozBHePztQFg6pj5aKg==", + "node_modules/blume/node_modules/p-queue": { + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.3.tgz", + "integrity": "sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.20", - "@vue/shared": "3.5.20" + "eventemitter3": "^5.0.4", + "p-timeout": "^7.0.0" }, - "peerDependencies": { - "vue": "3.5.20" + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@vue/shared": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.20.tgz", - "integrity": "sha512-SoRGP596KU/ig6TfgkCMbXkr4YJ91n/QSdMuqeP5r3hVIYA3CPHUBCc7Skak0EAKV+5lL4KyIh61VA/pK1CIAA==", - "license": "MIT" - }, - "node_modules/@vueuse/core": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-11.3.0.tgz", - "integrity": "sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==", + "node_modules/blume/node_modules/p-timeout": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", + "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", "license": "MIT", - "dependencies": { - "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "11.3.0", - "@vueuse/shared": "11.3.0", - "vue-demi": ">=0.14.10" + "engines": { + "node": ">=20" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@vueuse/core/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, + "node_modules/blume/node_modules/svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.2.tgz", + "integrity": "sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==", "license": "MIT", + "dependencies": { + "commander": "^11.1.0", + "css-select": "^5.1.0", + "css-tree": "^3.0.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "^1.5.0" + }, "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" + "svgo": "bin/svgo.js" }, "engines": { - "node": ">=12" + "node": ">=16" }, "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "type": "opencollective", + "url": "https://opencollective.com/svgo" } }, - "node_modules/@vueuse/integrations": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-11.3.0.tgz", - "integrity": "sha512-5fzRl0apQWrDezmobchoiGTkGw238VWESxZHazfhP3RM7pDSiyXy18QbfYkILoYNTd23HPAfQTJpkUc5QbkwTw==", + "node_modules/blume/node_modules/vite": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", + "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", "license": "MIT", "dependencies": { - "@vueuse/core": "11.3.0", - "@vueuse/shared": "11.3.0", - "vue-demi": ">=0.14.10" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.17", + "rolldown": "~1.1.5", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "async-validator": "^4", - "axios": "^1", - "change-case": "^5", - "drauu": "^0.4", - "focus-trap": "^7", - "fuse.js": "^7", - "idb-keyval": "^6", - "jwt-decode": "^4", - "nprogress": "^0.2", - "qrcode": "^1.5", - "sortablejs": "^1", - "universal-cookie": "^7" + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { - "async-validator": { + "@types/node": { "optional": true }, - "axios": { + "@vitejs/devtools": { "optional": true }, - "change-case": { + "esbuild": { "optional": true }, - "drauu": { + "jiti": { "optional": true }, - "focus-trap": { + "less": { "optional": true }, - "fuse.js": { + "sass": { "optional": true }, - "idb-keyval": { + "sass-embedded": { "optional": true }, - "jwt-decode": { + "stylus": { "optional": true }, - "nprogress": { + "sugarss": { "optional": true }, - "qrcode": { + "terser": { "optional": true }, - "sortablejs": { + "tsx": { "optional": true }, - "universal-cookie": { + "yaml": { "optional": true } } }, - "node_modules/@vueuse/integrations/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, + "node_modules/blume/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/@vueuse/metadata": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-11.3.0.tgz", - "integrity": "sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==", + "node_modules/blume/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/@vueuse/shared": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-11.3.0.tgz", - "integrity": "sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==", + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", "license": "MIT", "dependencies": { - "vue-demi": ">=0.14.10" + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@vueuse/shared/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "license": "MIT" + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "node_modules/brace-expansion": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", + "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" } }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "node_modules/brace-expansion/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "license": "MIT", "dependencies": { - "@xtuc/ieee754": "^1.2.0" + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "license": "Apache-2.0", + "node_modules/browserslist": { + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "@xtuc/long": "4.2.2" + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" - } + "optional": true, + "peer": true }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "node_modules/bun-types": { + "version": "1.2.21", + "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.2.21.tgz", + "integrity": "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw==", + "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" + "@types/node": "*" + }, + "peerDependencies": { + "@types/react": "^19" } }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" + "engines": { + "node": ">= 0.8" } }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@xstate/fsm": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@xstate/fsm/-/fsm-1.6.5.tgz", - "integrity": "sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw==", - "license": "MIT" - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "license": "BSD-3-Clause" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "license": "Apache-2.0" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, "engines": { - "node": ">= 0.6" + "node": ">=6" } }, - "node_modules/accepts/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "license": "MIT", - "engines": { - "node": ">= 0.6" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, "engines": { - "node": ">=0.4.0" + "node": ">=18" } }, - "node_modules/acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "node_modules/chalk": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz", + "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==", "license": "MIT", + "peer": true, "engines": { - "node": ">=10.13.0" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, - "peerDependencies": { - "acorn": "^8.14.0" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/address": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", - "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", "license": "MIT", - "engines": { - "node": ">= 10.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", "license": "MIT", - "engines": { - "node": ">= 14" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": "*" } }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, - "node_modules/ajv-draft-04": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "license": "MIT", - "peerDependencies": { - "ajv": "^8.5.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" } + ], + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", "license": "MIT", "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "consola": "^3.2.3" } }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" + "peer": true, + "engines": { + "node": ">=10" }, - "peerDependencies": { - "ajv": "^8.8.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/algoliasearch": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.36.0.tgz", - "integrity": "sha512-FpwQ+p4x4RIsWnPj2z9idOC70T90ga7Oeh8BURSFKpqp5lITRsgkIj/bwYj2bY5xbyD7uBuP9AZRnM5EV20WOw==", - "license": "MIT", - "dependencies": { - "@algolia/abtesting": "1.2.0", - "@algolia/client-abtesting": "5.36.0", - "@algolia/client-analytics": "5.36.0", - "@algolia/client-common": "5.36.0", - "@algolia/client-insights": "5.36.0", - "@algolia/client-personalization": "5.36.0", - "@algolia/client-query-suggestions": "5.36.0", - "@algolia/client-search": "5.36.0", - "@algolia/ingestion": "1.36.0", - "@algolia/monitoring": "1.36.0", - "@algolia/recommend": "5.36.0", - "@algolia/requester-browser-xhr": "5.36.0", - "@algolia/requester-fetch": "5.36.0", - "@algolia/requester-node-http": "5.36.0" + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">= 14.0.0" + "node": ">=20" } }, - "node_modules/algoliasearch-helper": { - "version": "3.26.0", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.26.0.tgz", - "integrity": "sha512-Rv2x3GXleQ3ygwhkhJubhhYGsICmShLAiqtUuJTUkr9uOCOXyF2E71LVT4XDnVffbknv8XgScP4U0Oxtgm+hIw==", + "node_modules/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", - "dependencies": { - "@algolia/events": "^4.0.1" + "engines": { + "node": ">=12" }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 6" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "license": "ISC", - "dependencies": { - "string-width": "^4.1.0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansi-align/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/cliui/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, - "node_modules/ansi-align/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-align/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" + "node": ">=18" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "license": "MIT", "dependencies": { - "type-fest": "^0.21.3" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "license": "(MIT OR CC0-1.0)", + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "engines": [ - "node >= 0.8.0" - ], - "license": "Apache-2.0", - "bin": { - "ansi-html": "bin/ansi-html" + "node": ">=6" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", "license": "MIT", - "engines": { - "node": ">=8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/common-ancestor-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, + "peer": true + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", "engines": { - "node": ">= 8" + "node": "^14.18.0 || >=16.10.0" } }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "license": "MIT" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/aria-hidden": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", - "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, "engines": { - "node": ">=10" - } - }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "dequal": "^2.0.3" + "node": ">= 0.6" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "license": "MIT" }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", + "peer": true, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } + "node_modules/cookie-es": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz", + "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==", + "license": "MIT" }, - "node_modules/astring": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", - "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", - "bin": { - "astring": "bin/astring" + "engines": { + "node": ">=6.6.0" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, - "node_modules/autoprefixer": { - "version": "10.4.21", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", - "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "license": "MIT", "dependencies": { - "browserslist": "^4.24.4", - "caniuse-lite": "^1.0.30001702", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" + "object-assign": "^4", + "vary": "^1" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">= 0.10" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/axios": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", - "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "layout-base": "^1.0.0" } }, - "node_modules/babel-loader": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", - "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { - "find-cache-dir": "^4.0.0", - "schema-utils": "^4.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0", - "webpack": ">=5" + "node": ">= 8" } }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", "license": "MIT", "dependencies": { - "object.assign": "^4.1.0" + "uncrypto": "^0.1.3" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", - "license": "MIT", + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", - "semver": "^6.3.1" + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" + "bin": { + "cssesc": "bin/cssesc" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">=4" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" + "css-tree": "~2.2.0" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" } }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" }, - "node_modules/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, "engines": { - "node": ">= 0.6.0" + "node": ">=18" } }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "node_modules/cytoscape": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.0.tgz", + "integrity": "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==", "license": "MIT", "engines": { - "node": "*" + "node": ">=0.10" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "cose-base": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "cytoscape": "^3.2.0" } }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "cose-base": "^2.2.0" }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" + "peerDependencies": { + "cytoscape": "^3.2.0" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", "license": "MIT", "dependencies": { - "ms": "2.0.0" + "layout-base": "^2.0.0" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", "license": "MIT" }, - "node_modules/bonjour-service": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", - "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", - "license": "MIT", + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "license": "ISC" - }, - "node_modules/boxen": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", - "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", - "license": "MIT", + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", "dependencies": { - "ansi-align": "^3.0.1", - "camelcase": "^6.2.0", - "chalk": "^4.1.2", - "cli-boxes": "^3.0.0", - "string-width": "^5.0.1", - "type-fest": "^2.5.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" + "internmap": "1 - 2" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/boxen/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=12" } }, - "node_modules/boxen/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=12" } }, - "node_modules/boxen/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "d3-path": "1 - 3" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/boxen/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "license": "(MIT OR CC0-1.0)", + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "license": "MIT", + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", "dependencies": { - "fill-range": "^7.1.1" + "delaunator": "5" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/browser-tabs-lock": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.3.0.tgz", - "integrity": "sha512-g6nHaobTiT0eMZ7jh16YpD2kcjAp+PInbiVq3M1x6KKaEIVhT4v9oURNIpZLOZ3LQbQ3XYfNhMAb/9hzNLIWrw==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "lodash": ">=4.17.21" + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" } }, - "node_modules/browserslist": { - "version": "4.25.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.4.tgz", - "integrity": "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", "dependencies": { - "caniuse-lite": "^1.0.30001737", - "electron-to-chromium": "^1.5.211", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.3" - }, - "bin": { - "browserslist": "cli.js" + "d3-dispatch": "1 - 3", + "d3-selection": "3" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=12" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/bun-types": { - "version": "1.2.21", - "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.2.21.tgz", - "integrity": "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw==", - "dev": true, - "license": "MIT", + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", "dependencies": { - "@types/node": "*" + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" }, - "peerDependencies": { - "@types/react": "^19" + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" } }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 10" } }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/cacheable-lookup": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", - "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", - "license": "MIT", + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", "engines": { - "node": ">=14.16" + "node": ">=12" } }, - "node_modules/cacheable-request": { - "version": "10.2.14", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", - "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", - "license": "MIT", + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", "dependencies": { - "@types/http-cache-semantics": "^4.0.2", - "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.3", - "mimic-response": "^4.0.0", - "normalize-url": "^8.0.0", - "responselike": "^3.0.0" + "d3-dsv": "1 - 3" }, "engines": { - "node": ">=14.16" + "node": ">=12" } }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "license": "MIT", + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=12" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" + "d3-array": "2.5.0 - 3" }, "engines": { - "node": ">= 0.4" + "node": ">=12" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" + "d3-color": "1 - 3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=12" } }, - "node_modules/callsites": { + "node_modules/d3-path": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "license": "MIT", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", "engines": { - "node": ">=6" + "node": ">=12" } }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "license": "MIT", - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" } }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "license": "MIT", + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "license": "MIT", + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001739", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001739.tgz", - "integrity": "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" } }, - "node_modules/chai": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", - "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", - "dev": true, - "license": "MIT", + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" }, "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/chalk": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz", - "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" } }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" } }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", - "dev": true, - "license": "MIT", + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", "engines": { - "node": ">= 16" + "node": ">=12" } }, - "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "license": "MIT", + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" }, "engines": { - "node": ">= 6" + "node": ">=12" }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + "peerDependencies": { + "d3-selection": "2 - 3" } }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "license": "BSD-2-Clause", + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" }, "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">=18" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "node_modules/dayjs": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, "engines": { "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=8" - } + "optional": true, + "peer": true }, - "node_modules/class-variance-authority": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", - "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", - "license": "Apache-2.0", + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "license": "MIT", "dependencies": { - "clsx": "^2.1.1" + "character-entities": "^2.0.0" }, "funding": { - "url": "https://polar.sh/cva" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", "license": "MIT" }, - "node_modules/clean-css": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", - "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", - "license": "MIT", + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "license": "ISC", "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 10.0" + "robust-predicates": "^3.0.2" } }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", - "license": "MIT", + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, + "node_modules/deterministic-object-hash": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/deterministic-object-hash/-/deterministic-object-hash-2.0.2.tgz", + "integrity": "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==", "license": "MIT", + "peer": true, "dependencies": { - "restore-cursor": "^5.0.0" + "base-64": "^1.0.0" }, "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-table3": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", - "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "node_modules/devalue": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.2.tgz", + "integrity": "sha512-DObPPAfdtFbXjxLqK8s2Xk9ZuWz5+ZoFEhC7J76es4GU/rEiXwHTmbImoCdyoCOcBH1UF3+Cz6Z2sYD4hyl5TA==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "license": "MIT", "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" + "dequal": "^2.0.0" }, - "optionalDependencies": { - "@colors/colors": "1.5.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/cli-table3/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/diacritics": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz", + "integrity": "sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA==", "license": "MIT" }, - "node_modules/cli-table3/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": ">=0.3.1" } }, - "node_modules/cli-table3/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT", + "peer": true + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "license": "MIT", + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" + "domelementtype": "^2.3.0" }, "engines": { - "node": ">=6" + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" + "node_modules/dompurify": { + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", + "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" } }, - "node_modules/codemirror": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz", - "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==", - "license": "MIT", + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/commands": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" - } - }, - "node_modules/collapse-white-space": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", - "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", - "license": "MIT", + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "is-obj": "^2.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "license": "MIT" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "license": "MIT" - }, - "node_modules/combine-promises": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.2.0.tgz", - "integrity": "sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==", + "node_modules/dset": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", "license": "MIT", "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { - "delayed-stream": "~1.0.0" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.4" } }, - "node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, - "node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "license": "MIT", + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "node_modules/electron-to-chromium": { + "version": "1.5.398", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.398.tgz", + "integrity": "sha512-AsvhAxopJGh6museTDMIjn6JpDYOfgu4RLlygomt87MUwBUqTfd/1EiPtx10/LZE8xpTvkP2E9Gafq7lkLtodQ==", "license": "ISC" }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/emmet": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.4.11.tgz", + "integrity": "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==", "license": "MIT", + "workspaces": [ + "./packages/scanner", + "./packages/abbreviation", + "./packages/css-abbreviation", + "./" + ], "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, + "@emmetio/abbreviation": "^2.3.3", + "@emmetio/css-abbreviation": "^2.1.8" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "node_modules/enhanced-resolve": { + "version": "5.24.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.4.tgz", + "integrity": "sha512-GVoi+ICHocoOIU7qVVM48wOJziRsqrsyqlI0Ce0LdowRn6v3bcH2zUa9kp85ncx0nwIb9/HOCOLS3fdThDG/XQ==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" }, "engines": { - "node": ">= 0.8.0" + "node": ">=10.13.0" } }, - "node_modules/compression/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.8" + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/epub-gen-memory": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/epub-gen-memory/-/epub-gen-memory-1.1.2.tgz", + "integrity": "sha512-vwGM6MVNqKIskFzPZqhi4ZOs0ZTUXco9oDuHFX1vB2Il9pTAkaHWFBFgHrrl832dYmBPb/raGVUZXFvZYueRyw==", "license": "MIT", "dependencies": { - "ms": "2.0.0" + "abort-controller": "^3.0.0", + "css-select": "^4.1.3", + "diacritics": "^1.3.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "ejs": "^3.1.6", + "htmlparser2": "^7.1.2", + "jszip": "^3.7.1", + "mime": "^2.5.2", + "node-fetch": "^2.0.0", + "ow": "^0.28.1", + "slugify": "^1.6.5" + }, + "engines": { + "node": ">=10.0.0" } }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" + "node_modules/epub-gen-memory/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "node_modules/epub-gen-memory/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "license": "MIT", "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/config-chain/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, - "node_modules/configstore": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", - "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "node_modules/epub-gen-memory/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "license": "BSD-2-Clause", "dependencies": { - "dot-prop": "^6.0.1", - "graceful-fs": "^4.2.6", - "unique-string": "^3.0.0", - "write-file-atomic": "^3.0.3", - "xdg-basedir": "^5.0.1" + "domelementtype": "^2.2.0" }, "engines": { - "node": ">=12" + "node": ">= 4" }, "funding": { - "url": "https://github.com/yeoman/configstore?sponsor=1" - } - }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "license": "MIT", - "engines": { - "node": ">=0.8" + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/consola": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", - "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.10.0" + "node_modules/epub-gen-memory/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "node_modules/epub-gen-memory/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/epub-gen-memory/node_modules/htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" + } + }, + "node_modules/epub-gen-memory/node_modules/htmlparser2/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.6" + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.4" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.4" } }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "license": "MIT", + "peer": true }, - "node_modules/copy-text-to-clipboard": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", - "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==", + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "es-errors": "^1.3.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.4" } }, - "node_modules/copy-webpack-plugin": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "node_modules/es-toolkit": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.50.0.tgz", + "integrity": "sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks", + "tests/types" + ] + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", "license": "MIT", "dependencies": { - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.1", - "globby": "^13.1.1", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" - }, - "engines": { - "node": ">= 14.15.0" + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" + "url": "https://opencollective.com/unified" } }, - "node_modules/copy-webpack-plugin/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "license": "ISC", + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">=10.13.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/copy-webpack-plugin/node_modules/globby": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "node_modules/esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.3.0", - "ignore": "^5.2.4", - "merge2": "^1.4.1", - "slash": "^4.0.0" + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" } }, - "node_modules/copy-webpack-plugin/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { - "node": ">=12" + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=4" } }, - "node_modules/core-js": { - "version": "3.45.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz", - "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==", - "hasInstallScript": true, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/core-js" + "url": "https://opencollective.com/unified" } }, - "node_modules/core-js-compat": { - "version": "3.45.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz", - "integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==", + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", "license": "MIT", "dependencies": { - "browserslist": "^4.25.3" + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/core-js" + "url": "https://opencollective.com/unified" } }, - "node_modules/core-js-pure": { - "version": "3.45.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.45.1.tgz", - "integrity": "sha512-OHnWFKgTUshEU8MK+lOs1H8kC8GkTi9Z1tvNkxrCcw9wl3MJIO7q2ld77wjWn4/xuGrVu2X+nME1iIIPBSdyEQ==", - "hasInstallScript": true, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", "license": "MIT", "funding": { "type": "opencollective", - "url": "https://opencollective.com/core-js" + "url": "https://opencollective.com/unified" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", "license": "MIT", "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/crelt": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", - "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" }, - "engines": { - "node": ">= 8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", "license": "MIT", "dependencies": { - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/crypto-random-string/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/css-blank-pseudo": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz", - "integrity": "sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "@types/estree": "^1.0.0" } }, - "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=4" + "node": ">= 0.6" } }, - "node_modules/css-declaration-sorter": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", - "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", - "license": "ISC", + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.0.9" + "node": ">=6" } }, - "node_modules/css-has-pseudo": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.3.tgz", - "integrity": "sha512-oG+vKuGyqe/xvEMoxAQrhi7uY16deJR3i7wwhBerVrGQKSqUC5GiOVxTpM9F9B9hw0J+eKeOWLH7E9gZ1Dr5rA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", "dependencies": { - "@csstools/selector-specificity": "^5.0.0", - "postcss-selector-parser": "^7.0.0", - "postcss-value-parser": "^4.2.0" + "eventsource-parser": "^3.0.1" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=18.0.0" } }, - "node_modules/css-has-pseudo/node_modules/@csstools/selector-specificity": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", - "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/eventsource-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", + "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", + "license": "MIT", "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss-selector-parser": "^7.0.0" + "node": ">=18.0.0" } }, - "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" } }, - "node_modules/css-loader": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", - "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.1.0", - "postcss-modules-local-by-default": "^4.0.5", - "postcss-modules-scope": "^3.2.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.5.4" + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } + "url": "https://opencollective.com/express" } }, - "node_modules/css-minimizer-webpack-plugin": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz", - "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==", + "node_modules/express-rate-limit": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.6.1.tgz", + "integrity": "sha512-0D493aP61w0TJ2A0wy27riRsO7FMQ7FK+KUHOKCSfPvYo0R55aiC6emCVgFUeShH0fq0ICPVzNcgoS+BsbXQCA==", "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "cssnano": "^6.0.1", - "jest-worker": "^29.4.3", - "postcss": "^8.4.24", - "schema-utils": "^4.0.1", - "serialize-javascript": "^6.0.1" + "debug": "^4.4.3", + "ip-address": "^10.2.0" }, "engines": { - "node": ">= 14.15.0" + "node": ">= 16" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/express-rate-limit" }, "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@parcel/css": { - "optional": true - }, - "@swc/css": { - "optional": true - }, - "clean-css": { - "optional": true - }, - "csso": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "lightningcss": { - "optional": true - } + "express": ">= 4.11" } }, - "node_modules/css-prefers-color-scheme": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-10.0.0.tgz", - "integrity": "sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/express/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">= 0.6" } }, - "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "node_modules/express/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" + "mime-db": "^1.54.0" }, "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/fb55" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, - "node_modules/cssdb": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.4.0.tgz", - "integrity": "sha512-lyATYGyvXwQ8h55WeQeEHXhI+47rl52pXSYkFK/ZrCbAJSgVIaPFjYc3RM8TpRHKk7W3wsAZImmLps+P5VyN9g==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - } - ], - "license": "MIT-0" - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" + "dependencies": { + "is-extendable": "^0.1.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/cssnano": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", - "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", "dependencies": { - "cssnano-preset-default": "^6.1.2", - "lilconfig": "^3.1.1" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" }, "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "node": ">=8.6.0" } }, - "node_modules/cssnano-preset-advanced": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-6.1.2.tgz", - "integrity": "sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "license": "MIT", - "dependencies": { - "autoprefixer": "^10.4.19", - "browserslist": "^4.23.0", - "cssnano-preset-default": "^6.1.2", - "postcss-discard-unused": "^6.0.5", - "postcss-merge-idents": "^6.0.3", - "postcss-reduce-idents": "^6.0.3", - "postcss-zindex": "^6.0.2" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/cssnano-preset-default": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", - "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", - "license": "MIT", - "dependencies": { - "browserslist": "^4.23.0", - "css-declaration-sorter": "^7.2.0", - "cssnano-utils": "^4.0.2", - "postcss-calc": "^9.0.1", - "postcss-colormin": "^6.1.0", - "postcss-convert-values": "^6.1.0", - "postcss-discard-comments": "^6.0.2", - "postcss-discard-duplicates": "^6.0.3", - "postcss-discard-empty": "^6.0.3", - "postcss-discard-overridden": "^6.0.2", - "postcss-merge-longhand": "^6.0.5", - "postcss-merge-rules": "^6.1.1", - "postcss-minify-font-values": "^6.1.0", - "postcss-minify-gradients": "^6.0.3", - "postcss-minify-params": "^6.1.0", - "postcss-minify-selectors": "^6.0.4", - "postcss-normalize-charset": "^6.0.2", - "postcss-normalize-display-values": "^6.0.2", - "postcss-normalize-positions": "^6.0.2", - "postcss-normalize-repeat-style": "^6.0.2", - "postcss-normalize-string": "^6.0.2", - "postcss-normalize-timing-functions": "^6.0.2", - "postcss-normalize-unicode": "^6.1.0", - "postcss-normalize-url": "^6.0.2", - "postcss-normalize-whitespace": "^6.0.2", - "postcss-ordered-values": "^6.0.2", - "postcss-reduce-initial": "^6.1.0", - "postcss-reduce-transforms": "^6.0.2", - "postcss-svgo": "^6.0.3", - "postcss-unique-selectors": "^6.0.4" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } + "optional": true }, - "node_modules/cssnano-utils": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", - "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", - "license": "MIT", - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "license": "MIT" }, - "node_modules/csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", "license": "MIT", "dependencies": { - "css-tree": "~2.2.0" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" + "fast-string-truncated-width": "^3.0.2" } }, - "node_modules/csso/node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", "license": "MIT", "dependencies": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" + "fast-string-width": "^3.0.2" } }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "license": "CC0-1.0" - }, - "node_modules/cssstyle": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", - "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", - "dev": true, - "license": "MIT", + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", "dependencies": { - "@asamuzakjp/css-color": "^3.2.0", - "rrweb-cssom": "^0.8.0" - }, - "engines": { - "node": ">=18" + "reusify": "^1.0.4" } }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" - }, - "node_modules/cva": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/cva/-/cva-1.0.0-beta.2.tgz", - "integrity": "sha512-dqcOFe247I5pKxfuzqfq3seLL5iMYsTgo40Uw7+pKZAntPgFtR7Tmy59P5IVIq/XgB0NQWoIvYDt9TwHkuK8Cg==", - "license": "Apache-2.0", - "dependencies": { - "clsx": "^2.1.1" - }, - "funding": { - "url": "https://polar.sh/cva" + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" }, "peerDependencies": { - "typescript": ">= 4.5.5 < 6" + "picomatch": "^3 || ^4" }, "peerDependenciesMeta": { - "typescript": { + "picomatch": { "optional": true } } }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dev": true, - "license": "MIT", + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "license": "Apache-2.0", "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" - }, - "engines": { - "node": ">=18" + "minimatch": "^5.0.1" } }, - "node_modules/debounce": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.3.tgz", + "integrity": "sha512-DRdx5neNsG/QXbniLFWi2YmC/68oeOOmKz6zOjVk6ZS1ZLXgLIKqVEc6hWsmkjBbgii0SwaBTcJ5XKj5gzY/4A==", "license": "MIT", "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "balanced-match": "^1.0.0" } }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true, - "license": "MIT" - }, - "node_modules/decode-named-character-reference": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", - "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", - "license": "MIT", + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", "dependencies": { - "character-entities": "^2.0.0" + "brace-expansion": "^2.0.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "engines": { + "node": ">=10" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "license": "MIT", "dependencies": { - "mimic-response": "^3.1.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">= 18.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "dev": true, + "node_modules/flattie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", + "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], "license": "MIT", "engines": { - "node": ">=4.0.0" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "node_modules/fontace": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz", + "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==", "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "license": "BSD-2-Clause", "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" + "fontkitten": "^1.0.2" } }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "node_modules/fontkitten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.3.tgz", + "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==", "license": "MIT", + "dependencies": { + "tiny-inflate": "^1.0.3" + }, "engines": { - "node": ">=10" + "node": ">=20" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "license": "MIT", + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "license": "MIT", - "engines": { - "node": ">=8" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", "engines": { - "node": ">= 0.4" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "license": "MIT" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">= 0.6" } }, - "node_modules/depd": { + "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "node_modules/fs-extra": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", + "dev": true, "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": ">=6" + "node": ">=14.14" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/detect-libc": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", - "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", - "devOptional": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "license": "MIT" - }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", - "license": "MIT" - }, - "node_modules/detect-port": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", - "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "license": "MIT", - "dependencies": { - "address": "^1.0.1", - "debug": "4" - }, - "bin": { - "detect": "bin/detect-port.js", - "detect-port": "bin/detect-port.js" - }, "engines": { - "node": ">= 4.0.0" + "node": ">=6.9.0" } }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", "license": "MIT", - "dependencies": { - "dequal": "^2.0.0" + "engines": { + "node": ">=18" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { - "path-type": "^4.0.0" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "node_modules/docusaurus-plugin-sass": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/docusaurus-plugin-sass/-/docusaurus-plugin-sass-0.2.6.tgz", - "integrity": "sha512-2hKQQDkrufMong9upKoG/kSHJhuwd+FA3iAe/qzS/BmWpbIpe7XKmq5wlz4J5CJaOPu4x+iDJbgAxZqcoQf0kg==", + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "license": "MIT", - "dependencies": { - "sass-loader": "^16.0.2" + "engines": { + "node": ">=10" }, - "peerDependencies": { - "@docusaurus/core": "^2.0.0-beta || ^3.0.0-alpha", - "sass": "^1.30.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "node_modules/get-tsconfig": { + "version": "5.0.0-beta.4", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.4.tgz", + "integrity": "sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==", "license": "MIT", "dependencies": { - "utila": "~0.4" + "resolve-pkg-maps": "^1.0.0" + }, + "engines": { + "node": ">=20.20.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "license": "MIT", + "node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "license": "BSD-2-Clause", + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", "dependencies": { - "domelementtype": "^2.3.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">= 4" + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "license": "BSD-2-Clause", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "engines": { + "node": ">=6.0" } }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "license": "MIT", "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" + "sprintf-js": "~1.0.2" } }, - "node_modules/dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "license": "MIT", "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=10" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/dot-prop/node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "node_modules/h3": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", + "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "cookie-es": "^1.2.3", + "crossws": "^0.3.5", + "defu": "^6.1.6", + "destr": "^2.0.5", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.4", + "radix3": "^1.1.2", + "ufo": "^1.6.3", + "uncrypto": "^0.1.3" } }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "license": "BSD-2-Clause", + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://dotenvx.com" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "license": "MIT" - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.211", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.211.tgz", - "integrity": "sha512-IGBvimJkotaLzFnwIVgW9/UD/AOJ2tByUmeOrtqBfACSbAw5b1G0XpvdaieKyc7ULmbwXVx+4e4Be8pOPBrYkw==", - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/emojilib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", - "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", - "license": "MIT" - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/emoticon": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.1.0.tgz", - "integrity": "sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==", + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" }, - "engines": { - "node": ">=10.13.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" }, "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", "license": "MIT", "dependencies": { - "is-arrayish": "^0.2.1" + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", "license": "MIT", "dependencies": { - "es-errors": "^1.3.0" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" }, - "engines": { - "node": ">= 0.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">= 0.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/esast-util-from-estree": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", - "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", - "estree-util-visit": "^2.0.0", - "unist-util-position-from-estree": "^2.0.0" + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/esast-util-from-js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", - "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "node_modules/hast-util-to-parse5/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.0", - "acorn": "^8.0.0", - "esast-util-from-estree": "^2.0.0", - "vfile-message": "^4.0.0" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/esbuild": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", - "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", - "dev": true, - "hasInstallScript": true, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "@types/hast": "^3.0.0" }, - "engines": { - "node": ">=18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.9", - "@esbuild/android-arm": "0.25.9", - "@esbuild/android-arm64": "0.25.9", - "@esbuild/android-x64": "0.25.9", - "@esbuild/darwin-arm64": "0.25.9", - "@esbuild/darwin-x64": "0.25.9", - "@esbuild/freebsd-arm64": "0.25.9", - "@esbuild/freebsd-x64": "0.25.9", - "@esbuild/linux-arm": "0.25.9", - "@esbuild/linux-arm64": "0.25.9", - "@esbuild/linux-ia32": "0.25.9", - "@esbuild/linux-loong64": "0.25.9", - "@esbuild/linux-mips64el": "0.25.9", - "@esbuild/linux-ppc64": "0.25.9", - "@esbuild/linux-riscv64": "0.25.9", - "@esbuild/linux-s390x": "0.25.9", - "@esbuild/linux-x64": "0.25.9", - "@esbuild/netbsd-arm64": "0.25.9", - "@esbuild/netbsd-x64": "0.25.9", - "@esbuild/openbsd-arm64": "0.25.9", - "@esbuild/openbsd-x64": "0.25.9", - "@esbuild/openharmony-arm64": "0.25.9", - "@esbuild/sunos-x64": "0.25.9", - "@esbuild/win32-arm64": "0.25.9", - "@esbuild/win32-ia32": "0.25.9", - "@esbuild/win32-x64": "0.25.9" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/hono": { + "version": "4.12.32", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.32.tgz", + "integrity": "sha512-XcuyW9qE2kJn07PkecMOBd5Vq/hMy7mmGw+idz1yblbg9N17ijJODrvPkn7/dwL3Kulj8LcRJ69DLOWf91dRUg==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=16.9.0" } }, - "node_modules/escape-goat": { + "node_modules/html-encoding-sniffer": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", - "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "optional": true, + "peer": true, + "dependencies": { + "whatwg-encoding": "^3.1.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=18" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", "license": "MIT" }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", "license": "MIT", - "engines": { - "node": ">=10" - }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "license": "BSD-2-Clause", + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node": ">= 0.8" }, - "engines": { - "node": ">=4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "license": "BSD-2-Clause", + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" }, "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" + "node": ">=8.0.0" } }, - "node_modules/estree-util-attach-comments": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", - "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@types/estree": "^1.0.0" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 14" } }, - "node_modules/estree-util-build-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", - "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "estree-walker": "^3.0.0" + "agent-base": "^7.1.2", + "debug": "4" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 14" } }, - "node_modules/estree-util-is-identifier-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" } }, - "node_modules/estree-util-scope": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", - "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://opencollective.com/express" } }, - "node_modules/estree-util-to-js": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", - "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "node_modules/idb-keyval": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", + "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", + "license": "Apache-2.0", + "optional": true, + "peer": true + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/immutable": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", + "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "astring": "^1.8.0", - "source-map": "^0.7.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "optional": true, + "peer": true }, - "node_modules/estree-util-value-to-estree": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.4.0.tgz", - "integrity": "sha512-Zlp+gxis+gCfK12d3Srl2PdX2ybsEA8ZYy6vQGVQTNNYLEGRQQ56XB64bjemN8kxIKXP1nC9ip4Z+ILy9LGzvQ==", + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - }, "funding": { - "url": "https://github.com/sponsors/remcohaszing" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/estree-util-visit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", - "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" }, - "node_modules/esutils": { + "node_modules/internmap": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/eta": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", - "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", + "node_modules/ip-address": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.3.1.tgz", + "integrity": "sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==", "license": "MIT", "engines": { - "node": ">=6.0.0" - }, - "funding": { - "url": "https://github.com/eta-dev/eta?sponsor=1" + "node": ">= 12" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.10" } }, - "node_modules/eval": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", - "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", - "dependencies": { - "@types/node": "*", - "require-like": ">= 0.1.1" - }, - "engines": { - "node": ">= 0.8" + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "license": "MIT" - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", "license": "MIT", - "engines": { - "node": ">=0.8.x" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/expect-type": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", - "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" }, - "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/express/node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" + "peer": true, + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">= 0.6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" - }, - "node_modules/express/node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT" - }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", - "dependencies": { - "is-extendable": "^0.1.0" - }, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" + "node": ">=0.10.0" } }, - "node_modules/fault": { + "node_modules/is-hexadecimal": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", - "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", "license": "MIT", - "dependencies": { - "format": "^0.2.0" - }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "license": "Apache-2.0", + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "peer": true, "dependencies": { - "websocket-driver": ">=0.5.1" + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" }, "engines": { - "node": ">=0.8.0" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "license": "MIT", "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "node": ">=0.12.0" } }, - "node_modules/feed": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", - "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "license": "MIT", - "dependencies": { - "xml-js": "^1.6.11" - }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/fflate": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", - "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==", - "license": "MIT" - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=0.8.0" - } + "optional": true, + "peer": true }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "license": "MIT", - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, "engines": { - "node": ">= 10.13.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/file-loader/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", "license": "MIT", + "peer": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/file-loader/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/file-loader/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, - "node_modules/file-loader/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "license": "MIT", + "node_modules/jackspeak": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", + "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@isaacs/cliui": "^9.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": "20 || >=22" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "license": "MIT", + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "license": "Apache-2.0", "dependencies": { - "to-regex-range": "^5.0.1" + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" + "optional": true, + "peer": true, + "bin": { + "jiti": "bin/jiti.js" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/jose": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.4.tgz", + "integrity": "sha512-N8acGzVsQy6M/fjFcxtysNc4Q379TcM5dM/qKkNtsHFji88yANnXTr7BLeP75iPnFwBfQzM/jg2BZ9+HZrHCZA==", "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "funding": { + "url": "https://github.com/sponsors/panva" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, - "node_modules/find-cache-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", - "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { - "common-path-prefix": "^3.0.0", - "pkg-dir": "^7.0.0" - }, - "engines": { - "node": ">=14.16" + "argparse": "^2.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "node_modules/jsdom": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.5.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.1.1", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.1", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "license": "BSD-3-Clause", + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", "bin": { - "flat": "cli.js" + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" } }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "license": "ISC" + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" }, - "node_modules/focus-trap": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.5.tgz", - "integrity": "sha512-7Ke1jyybbbPZyZXFxEftUtxFGLMpE2n6A+z//m4CRDlj0hW+o3iYSmh8nFlYMurOiJVDmJRilUQtJr08KfIxlg==", - "license": "MIT", - "dependencies": { - "tabbable": "^6.2.0" - } + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "license": "MIT", - "engines": { - "node": ">=4.0" + "bin": { + "json5": "lib/cli.js" }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "engines": { + "node": ">=6" } }, - "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "node_modules/jsonc-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", + "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==", + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "universalify": "^2.0.0" }, - "engines": { - "node": ">= 6" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/form-data-encoder": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", - "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", "license": "MIT", "engines": { - "node": ">= 14.17" + "node": ">=0.10.0" } }, - "node_modules/format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", - "engines": { - "node": ">=0.4.x" + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/katex": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.17.0.tgz", + "integrity": "sha512-Vdw0ATsQ9V+LuegM/BTwQqV/6cTl5lbGcIrU+BCgLxyf6bo38ybOr372tuSIxir3CN720flu1meYR6XzNMwQnw==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" } }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "license": "MIT", "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" + "node": ">= 12" } }, - "node_modules/framer-motion": { - "version": "11.18.2", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", - "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "license": "MIT", - "dependencies": { - "motion-dom": "^11.18.1", - "motion-utils": "^11.18.1", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": ">=0.10.0" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "license": "MIT", + "peer": true, "engines": { - "node": ">= 0.6" + "node": ">=6" } }, - "node_modules/fs-extra": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", - "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" + "immediate": "~3.0.5" } }, - "node_modules/fs-monkey": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", - "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", - "license": "Unlicense" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", "optional": true, "os": [ - "darwin" + "android" ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", + "node": ">= 12.0.0" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/fuse.js": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", - "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=10" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "license": "MIT", + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-east-asian-width": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.1.tgz", - "integrity": "sha512-R1QfovbPsKmosqTnPoRFiJ7CF9MLRgb53ChvMZm+r4p76/+8yKDy17qLL2PKInORy2RkZZekuK0efYgmzTkXyQ==", - "dev": true, - "license": "MIT", + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "license": "MIT", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-own-enumerable-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz", - "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==", - "license": "MIT", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=14.16" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "license": "ISC" - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "license": "MIT", + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/github-slugger": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", - "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==", - "license": "ISC" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "*" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "license": "BSD-2-Clause" - }, - "node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", - "license": "MIT", - "dependencies": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "12.6.1", - "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", - "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^7.0.0", - "cacheable-request": "^10.2.8", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/got/node_modules/@sindresorhus/is": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", - "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "license": "MIT", - "dependencies": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/gray-matter/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/gray-matter/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", - "license": "MIT", - "dependencies": { - "duplexer": "^0.1.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "license": "MIT" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-yarn": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", - "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hast-util-embedded": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-3.0.0.tgz", - "integrity": "sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-is-element": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-format": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hast-util-format/-/hast-util-format-1.1.0.tgz", - "integrity": "sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-embedded": "^3.0.0", - "hast-util-minify-whitespace": "^1.0.0", - "hast-util-phrasing": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "html-whitespace-sensitive-tag-names": "^3.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-html": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", - "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "devlop": "^1.1.0", - "hast-util-from-parse5": "^8.0.0", - "parse5": "^7.0.0", - "vfile": "^6.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-parse5": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", - "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "devlop": "^1.0.0", - "hastscript": "^9.0.0", - "property-information": "^7.0.0", - "vfile": "^6.0.0", - "vfile-location": "^5.0.0", - "web-namespaces": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-has-property": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", - "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-is-body-ok-link": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-3.0.1.tgz", - "integrity": "sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-is-element": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", - "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-minify-whitespace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hast-util-minify-whitespace/-/hast-util-minify-whitespace-1.0.1.tgz", - "integrity": "sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-embedded": "^3.0.0", - "hast-util-is-element": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-parse-selector": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", - "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-phrasing": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/hast-util-phrasing/-/hast-util-phrasing-3.0.1.tgz", - "integrity": "sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-embedded": "^3.0.0", - "hast-util-has-property": "^3.0.0", - "hast-util-is-body-ok-link": "^3.0.0", - "hast-util-is-element": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-raw": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", - "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "@ungap/structured-clone": "^1.0.0", - "hast-util-from-parse5": "^8.0.0", - "hast-util-to-parse5": "^8.0.0", - "html-void-elements": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "parse5": "^7.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0", - "web-namespaces": "^2.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-sanitize": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/hast-util-sanitize/-/hast-util-sanitize-5.0.2.tgz", - "integrity": "sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@ungap/structured-clone": "^1.0.0", - "unist-util-position": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-estree": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", - "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-attach-comments": "^3.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-js": "^1.0.0", - "unist-util-position": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-html": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", - "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-whitespace": "^3.0.0", - "html-void-elements": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "stringify-entities": "^4.0.0", - "zwitch": "^2.0.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", - "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-js": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", - "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "web-namespaces": "^2.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-parse5/node_modules/property-information": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", - "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/hast-util-to-text": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", - "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "hast-util-is-element": "^3.0.0", - "unist-util-find-after": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hastscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", - "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^4.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, - "node_modules/highlight.js": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", - "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/highlightjs-curl": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/highlightjs-curl/-/highlightjs-curl-1.3.0.tgz", - "integrity": "sha512-50UEfZq1KR0Lfk2Tr6xb/MUIZH3h10oNC0OTy9g7WELcs5Fgy/mKN1vEhuKTkKbdo8vr5F9GXstu2eLhApfQ3A==", - "license": "Apache-2.0" - }, - "node_modules/highlightjs-vue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", - "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", - "license": "CC0-1.0" - }, - "node_modules/history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "license": "BSD-3-Clause", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/hookable": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", - "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", - "license": "MIT" - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/html-entities": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ], - "license": "MIT" - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "license": "MIT" - }, - "node_modules/html-minifier-terser": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", - "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", - "license": "MIT", - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "~5.3.2", - "commander": "^10.0.0", - "entities": "^4.4.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.15.1" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": "^14.13.1 || >=16.0.0" - } - }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/html-url-attributes": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", - "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/html-void-elements": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", - "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/html-webpack-plugin": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.4.tgz", - "integrity": "sha512-V/PZeWsqhfpE27nKeX9EO2sbR+D17A+tLf6qU+ht66jdUsN0QLKJN27Z+1+gHrVMKgndBahes0PU6rRihDgHTw==", - "license": "MIT", - "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.20.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/html-webpack-plugin/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "license": "MIT", - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-whitespace-sensitive-tag-names": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-whitespace-sensitive-tag-names/-/html-whitespace-sensitive-tag-names-3.0.1.tgz", - "integrity": "sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "license": "BSD-2-Clause" - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "license": "MIT" - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "license": "MIT" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "license": "MIT", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", - "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", - "license": "MIT", - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/http2-wrapper": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", - "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", - "license": "MIT", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.2.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "license": "ISC", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/idb": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/idb/-/idb-8.0.0.tgz", - "integrity": "sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw==", - "license": "ISC" - }, - "node_modules/idb-keyval": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", - "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", - "license": "Apache-2.0" - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/image-size": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz", - "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==", - "license": "MIT", - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=16.x" - } - }, - "node_modules/immutable": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", - "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", - "license": "MIT" - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/infima": { - "version": "0.2.0-alpha.45", - "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.45.tgz", - "integrity": "sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/inline-style-parser": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", - "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", - "license": "MIT" - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-absolute-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", - "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "license": "MIT", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "license": "MIT" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "license": "MIT", - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "license": "MIT", - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-npm": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", - "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "license": "MIT" - }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-yarn-global": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", - "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/jest-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/joi": { - "version": "17.13.3", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", - "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^9.3.0", - "@hapi/topo": "^5.1.0", - "@sideway/address": "^4.1.5", - "@sideway/formula": "^3.0.1", - "@sideway/pinpoint": "^2.0.0" - } - }, - "node_modules/js-base64": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", - "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", - "license": "BSD-3-Clause" - }, - "node_modules/js-cookie": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "26.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", - "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssstyle": "^4.2.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.5.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.16", - "parse5": "^7.2.1", - "rrweb-cssom": "^0.8.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^5.1.1", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.1.1", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "canvas": "^3.0.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-stringify-deterministic": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/json-stringify-deterministic/-/json-stringify-deterministic-1.0.12.tgz", - "integrity": "sha512-q3PN0lbUdv0pmurkBNdJH3pfFvOTL/Zp0lquqpvcjfKzt6Y0j49EPHAmVHCAS4Ceq/Y+PejWTzyiVpoY71+D6g==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/just-clone": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-6.2.0.tgz", - "integrity": "sha512-1IynUYEc/HAwxhi3WDpIpxJbZpMCvvrrmZVqvj9EhpvbH8lls7HhdhiByjL7DkAaWlLIzpC0Xc/VPvy/UxLNjA==", - "license": "MIT" - }, - "node_modules/just-curry-it": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/just-curry-it/-/just-curry-it-5.3.0.tgz", - "integrity": "sha512-silMIRiFjUWlfaDhkgSzpuAyQ6EX/o09Eu8ZBfmFwQMbax7+LQzeIU2CBrICT6Ne4l86ITCGvUCBpCubWYy0Yw==", - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/latest-version": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", - "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", - "license": "MIT", - "dependencies": { - "package-json": "^8.1.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/launch-editor": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz", - "integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==", - "license": "MIT", - "dependencies": { - "picocolors": "^1.1.1", - "shell-quote": "^1.8.3" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/lightningcss": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", - "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", - "devOptional": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.30.1", - "lightningcss-darwin-x64": "1.30.1", - "lightningcss-freebsd-x64": "1.30.1", - "lightningcss-linux-arm-gnueabihf": "1.30.1", - "lightningcss-linux-arm64-gnu": "1.30.1", - "lightningcss-linux-arm64-musl": "1.30.1", - "lightningcss-linux-x64-gnu": "1.30.1", - "lightningcss-linux-x64-musl": "1.30.1", - "lightningcss-win32-arm64-msvc": "1.30.1", - "lightningcss-win32-x64-msvc": "1.30.1" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", - "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", - "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", - "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", - "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", - "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", - "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", - "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", - "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", - "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", - "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" - }, - "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "license": "MIT", - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "license": "MIT", - "dependencies": { - "p-locate": "^6.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "license": "MIT" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "license": "MIT" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "license": "MIT" - }, - "node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/loupe": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", - "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lowercase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", - "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lowlight": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.3.0.tgz", - "integrity": "sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "devlop": "^1.0.0", - "highlight.js": "~11.11.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lucide-react": { - "version": "0.534.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.534.0.tgz", - "integrity": "sha512-4Bz7rujQ/mXHqCwjx09ih/Q9SCizz9CjBV5repw9YSHZZZaop9/Oj0RgCDt6WdEaeAPfbcZ8l2b4jzApStqgNw==", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/magic-string": { - "version": "0.30.18", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", - "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/markdown-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", - "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "node_modules/markdown-table": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mdast-util-directive": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz", - "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-find-and-replace": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", - "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/mdast-util-frontmatter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", - "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "escape-string-regexp": "^5.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-extension-frontmatter": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdast-util-gfm": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", - "license": "MIT", - "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-gfm-autolink-literal": "^2.0.0", - "mdast-util-gfm-footnote": "^2.0.0", - "mdast-util-gfm-strikethrough": "^2.0.0", - "mdast-util-gfm-table": "^2.0.0", - "mdast-util-gfm-task-list-item": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-autolink-literal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", - "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "ccount": "^2.0.0", - "devlop": "^1.0.0", - "mdast-util-find-and-replace": "^3.0.0", - "micromark-util-character": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/mdast-util-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", - "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", - "license": "MIT", - "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-expression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", - "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", - "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-phrasing": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", - "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "license": "CC0-1.0" - }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "license": "Unlicense", - "dependencies": { - "fs-monkey": "^1.0.4" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/microdiff": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/microdiff/-/microdiff-1.5.0.tgz", - "integrity": "sha512-Drq+/THMvDdzRYrK0oxJmOKiC24ayUV8ahrt8l3oRK51PWt6gdtrIGrlIH3pT/lFh1z93FbAcidtsHcWbnRz8Q==", - "license": "MIT" - }, - "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-extension-directive": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", - "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "parse-entities": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-directive/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-directive/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-directive/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-extension-frontmatter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", - "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", - "license": "MIT", - "dependencies": { - "fault": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-extension-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "license": "MIT", - "dependencies": { - "micromark-extension-gfm-autolink-literal": "^2.0.0", - "micromark-extension-gfm-footnote": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-table": "^2.0.0", - "micromark-extension-gfm-tagfilter": "^2.0.0", - "micromark-extension-gfm-task-list-item": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-extension-gfm-table": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-extension-mdx-expression": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", - "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-mdx-expression": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-extension-mdx-jsx": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", - "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "micromark-factory-mdx-expression": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-extension-mdx-md": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", - "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdxjs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", - "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", - "license": "MIT", - "dependencies": { - "acorn": "^8.0.0", - "acorn-jsx": "^5.0.0", - "micromark-extension-mdx-expression": "^3.0.0", - "micromark-extension-mdx-jsx": "^3.0.0", - "micromark-extension-mdx-md": "^2.0.0", - "micromark-extension-mdxjs-esm": "^3.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdxjs-esm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", - "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-position-from-estree": "^2.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-factory-mdx-expression": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", - "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-position-from-estree": "^2.0.0", - "vfile-message": "^4.0.0" - } - }, - "node_modules/micromark-factory-mdx-expression/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-factory-space": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", - "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-factory-space/node_modules/micromark-util-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", - "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-character": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", - "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-character/node_modules/micromark-util-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", - "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-events-to-acorn": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", - "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/unist": "^3.0.0", - "devlop": "^1.0.0", - "estree-util-visit": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "vfile-message": "^4.0.0" - } - }, - "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" ], - "license": "MIT" - }, - "node_modules/micromark-util-symbol": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", - "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" ], - "license": "MIT" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" ], - "license": "MIT" - }, - "node_modules/micromark/node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/micromark/node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "node_modules/linkify-it": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", + "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", + "dev": true, "funding": [ { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" + "type": "github", + "url": "https://github.com/sponsors/puzrin" }, { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/markdown-it" } ], "license": "MIT", "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "uc.micro": "^2.0.0" } }, - "node_modules/micromark/node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "license": "MIT" }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", "license": "MIT", - "engines": { - "node": ">=8.6" - }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } + "node_modules/lru_map": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.4.1.tgz", + "integrity": "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg==", + "license": "MIT" }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "license": "MIT", "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" } }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "node_modules/markdown-it": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz", + "integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.5.0", + "linkify-it": "^5.0.2", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "markdown-it": "bin/markdown-it.mjs" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", "license": "MIT", - "engines": { - "node": ">=4" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/mini-css-extract-plugin": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.4.tgz", - "integrity": "sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ==", + "node_modules/marked": { + "version": "18.0.7", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.7.tgz", + "integrity": "sha512-iDVQ5ldaiKXn6b2JroX5kgRfmwgqolW7NpaEzTl1k/2Zh1njIEN9yniyLV/mOvWwtsE8OGgkjsCYvijuPk1dtA==", "license": "MIT", - "dependencies": { - "schema-utils": "^4.0.0", - "tapable": "^2.2.1" + "bin": { + "marked": "bin/marked.js" }, "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" + "node": ">= 20" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "license": "ISC" + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "license": "BSD-3-Clause", "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "node_modules/mdast-util-definitions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", + "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "license": "MIT" - }, - "node_modules/motion": { - "version": "11.18.2", - "resolved": "https://registry.npmjs.org/motion/-/motion-11.18.2.tgz", - "integrity": "sha512-JLjvFDuFr42NFtcVoMAyC2sEjnpA8xpy6qWPyzQvCloznAyQ8FIXioxWfHiLtgYhoVpfUqSWpn1h9++skj9+Wg==", + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", "license": "MIT", "dependencies": { - "framer-motion": "^11.18.2", - "tslib": "^2.4.0" + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/motion-dom": { - "version": "11.18.1", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", - "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", "license": "MIT", "dependencies": { - "motion-utils": "^11.18.1" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/motion-utils": { - "version": "11.18.1", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", - "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", "license": "MIT", - "engines": { - "node": ">=10" + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", "license": "MIT", "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" }, - "bin": { - "multicast-dns": "cli.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/nanoid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz", - "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==", + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.js" - }, - "engines": { - "node": "^18 || >=20" - } - }, - "node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", "license": "MIT", "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/node-emoji": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", - "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", "license": "MIT", "dependencies": { - "@sindresorhus/is": "^4.6.0", - "char-regex": "^1.0.2", - "emojilib": "^2.4.0", - "skin-tone": "^2.0.0" + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "license": "(BSD-3-Clause OR GPL-2.0)", - "engines": { - "node": ">= 6.13.0" + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "dev": true, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "license": "MIT" - }, - "node_modules/normalize-path": { + "node_modules/mdast-util-mdx": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/normalize-url": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.2.tgz", - "integrity": "sha512-Ee/R3SyN4BuynXcnTaekmaVdbDAEiNrHqjQIA37mHU8G9pf7aaAD4ZX3XjBLo6rsdcxA/gtkcNYZLt30ACgynw==", + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", "license": "MIT", - "engines": { - "node": ">=14.16" + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", "license": "MIT", "dependencies": { - "path-key": "^3.0.0" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", - "license": "MIT" - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "license": "BSD-2-Clause", + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", "dependencies": { - "boolbase": "^1.0.0" + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" }, "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/null-loader": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", - "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", "license": "MIT", "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "url": "https://opencollective.com/unified" } }, - "node_modules/null-loader/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/null-loader/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/null-loader/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" - }, - "node_modules/null-loader/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" + "@types/mdast": "^4.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://opencollective.com/unified" } }, - "node_modules/nwsapi": { - "version": "2.2.21", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", - "integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==", + "node_modules/mdurl": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.1.0.tgz", + "integrity": "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==", "dev": true, "license": "MIT" }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">= 8" } }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "node_modules/mermaid": { + "version": "11.16.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.16.0.tgz", + "integrity": "sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.1.2", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.2.0", + "@types/d3": "^7.4.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.3", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.20", + "dompurify": "^3.3.3", + "es-toolkit": "^1.45.1", + "katex": "^0.16.45", + "khroma": "^2.1.0", + "marked": "^16.3.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" + } + }, + "node_modules/mermaid/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/mermaid/node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" + "commander": "^8.3.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "katex": "cli.js" + } + }, + "node_modules/mermaid/node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 20" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "license": "MIT" + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 0.8" + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", + "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "wrappy": "1" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", "license": "MIT", "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "license": "(WTFPL OR MIT)", - "bin": { - "opener": "bin/opener-bin.js" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/ora": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", - "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", - "dev": true, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^5.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.2", - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/ora/node_modules/emoji-regex": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", - "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", - "dev": true, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/ora/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", "license": "MIT", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-cancelable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", - "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", - "license": "MIT", - "engines": { - "node": ">=12.20" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "license": "MIT", - "engines": { - "node": ">=4" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "p-limit": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", "license": "MIT", "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/p-queue": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", - "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", "license": "MIT", "dependencies": { - "eventemitter3": "^4.0.4", - "p-timeout": "^3.2.0" - }, - "engines": { - "node": ">=8" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=8" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/package-json": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", - "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", "license": "MIT", "dependencies": { - "got": "^12.1.0", - "registry-auth-token": "^5.0.1", - "registry-url": "^6.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": ">=14.16" + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/packrup": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/packrup/-/packrup-0.1.2.tgz", - "integrity": "sha512-ZcKU7zrr5GlonoS9cxxrb5HVswGnyj6jQvwFBa6p5VFw7G71VAHcUKL5wyZSU/ECtPM/9gacWxy2KFQKt1gMNA==", + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, "funding": { - "url": "https://github.com/sponsors/harlan-zw" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/parse-entities": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", - "license": "MIT" - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/parse-ms": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-3.0.0.tgz", - "integrity": "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==", + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/parse-numeric-range": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", - "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==", - "license": "ISC" + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", "license": "MIT", "dependencies": { - "entities": "^6.0.0" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", - "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "domhandler": "^5.0.3", - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "license": "(WTFPL OR MIT)" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", - "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", "license": "MIT", "dependencies": { - "isarray": "0.0.1" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/pathval": { + "node_modules/micromark-factory-destination": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", - "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.16" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/pkg-dir": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", - "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "dependencies": { - "find-up": "^6.3.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-attribute-case-insensitive": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz", - "integrity": "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==", + "node_modules/micromark-factory-label/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], "license": "MIT", "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" } }, - "node_modules/postcss-calc": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", - "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.2" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-clamp": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", - "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=7.6.0" - }, - "peerDependencies": { - "postcss": "^8.4.6" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-color-functional-notation": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.11.tgz", - "integrity": "sha512-zfqoUSaHMko/k2PA9xnaydVTHqYv5vphq5Q2AHcG/dCdv/OkHYWcVWfVTBKZ526uzT8L7NghuvSw3C9PxlKnLg==", + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "license": "MIT" }, - "node_modules/postcss-color-hex-alpha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-10.0.0.tgz", - "integrity": "sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w==", + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], "license": "MIT", "dependencies": { - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-color-rebeccapurple": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-10.0.0.tgz", - "integrity": "sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ==", + "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "dependencies": { - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-colormin": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", - "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "caniuse-api": "^3.0.0", - "colord": "^2.9.3", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-convert-values": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", - "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "node_modules/micromark-factory-title/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-custom-media": { - "version": "11.0.6", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.6.tgz", - "integrity": "sha512-C4lD4b7mUIw+RZhtY7qUbf4eADmb7Ey8BFA2px9jUbwg7pjTZDl4KY4bvlUV+/vXQvzQRfiGEVJyAbtOsCMInw==", + "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], "license": "MIT", "dependencies": { - "@csstools/cascade-layer-name-parser": "^2.0.5", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/media-query-list-parser": "^4.0.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-custom-properties": { - "version": "14.0.6", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.6.tgz", - "integrity": "sha512-fTYSp3xuk4BUeVhxCSJdIPhDLpJfNakZKoiTDx7yRGCdlZrSJR7mWKVOBS4sBF+5poPQFMj2YdXx1VHItBGihQ==", + "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], "license": "MIT", "dependencies": { - "@csstools/cascade-layer-name-parser": "^2.0.5", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-custom-selectors": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.5.tgz", - "integrity": "sha512-9PGmckHQswiB2usSO6XMSswO2yFWVoCAuih1yl9FVcwkscLjRKjwsjM3t+NIWpSU2Jx3eOiK2+t4vVTQaoCHHg==", + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], "license": "MIT", "dependencies": { - "@csstools/cascade-layer-name-parser": "^2.0.5", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-dir-pseudo-class": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz", - "integrity": "sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==", + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-discard-comments": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", - "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", - "license": "MIT", - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", - "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", - "license": "MIT", - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-discard-empty": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", - "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", - "license": "MIT", - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", - "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", - "license": "MIT", - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } + "license": "MIT" }, - "node_modules/postcss-discard-unused": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz", - "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==", + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.16" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/postcss-double-position-gradients": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.3.tgz", - "integrity": "sha512-Dl0Z9sdbMwrPslgOaGBZRGo3TASmmgTcqcUODr82MTYyJk6devXZM6MlQjpQKMJqlLJ6oL1w78U7IXFdPA5+ug==", + "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "license": "MIT" }, - "node_modules/postcss-focus-visible": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz", - "integrity": "sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==", + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-focus-within": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz", - "integrity": "sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==", + "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-font-variant": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "license": "MIT", - "peerDependencies": { - "postcss": "^8.1.0" - } + "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/postcss-gap-properties": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-6.0.0.tgz", - "integrity": "sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw==", + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-image-set-function": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-7.0.0.tgz", - "integrity": "sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA==", + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", + "license": "MIT", "dependencies": { - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/postcss-lab-function": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.11.tgz", - "integrity": "sha512-BEA4jId8uQe1gyjZZ6Bunb6ZsH2izks+v25AxQJDBtigXCjTLmCPWECwQpLTtcxH589MVxhs/9TAmRC6lUEmXQ==", + "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-loader": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz", - "integrity": "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==", - "license": "MIT", - "dependencies": { - "cosmiconfig": "^8.3.5", - "jiti": "^1.20.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" - } + "license": "MIT" }, - "node_modules/postcss-logical": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.1.0.tgz", - "integrity": "sha512-pL1hXFQ2fEXNKiNiAgtfA005T9FBxky5zkX6s4GZM2D8RkVgRqz3f4g1JUoq925zXv495qk8UNldDwh8uGEDoA==", + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-merge-idents": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz", - "integrity": "sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g==", - "license": "MIT", - "dependencies": { - "cssnano-utils": "^4.0.2", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-merge-longhand": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", - "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.1.1" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-merge-rules": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", - "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", - "license": "MIT", - "dependencies": { - "browserslist": "^4.23.0", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.2", - "postcss-selector-parser": "^6.0.16" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", - "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-minify-gradients": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", - "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", - "license": "MIT", - "dependencies": { - "colord": "^2.9.3", - "cssnano-utils": "^4.0.2", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-minify-params": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", - "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", - "license": "MIT", - "dependencies": { - "browserslist": "^4.23.0", - "cssnano-utils": "^4.0.2", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-minify-selectors": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", - "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.0.16" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", - "license": "ISC", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", - "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", "license": "MIT", "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^7.0.0", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", - "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", - "license": "ISC", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } + "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "license": "ISC", - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/postcss-nesting": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.2.tgz", - "integrity": "sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ==", + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", + "license": "MIT", "dependencies": { - "@csstools/selector-resolve-nested": "^3.1.0", - "@csstools/selector-specificity": "^5.0.0", - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" } }, - "node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.1.0.tgz", - "integrity": "sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g==", + "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss-selector-parser": "^7.0.0" - } + "license": "MIT" }, - "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", - "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss-selector-parser": "^7.0.0" - } - }, - "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-normalize-charset": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", - "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", - "license": "MIT", - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", - "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-normalize-positions": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", - "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", - "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } + "license": "MIT" }, - "node_modules/postcss-normalize-string": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", - "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/postcss-normalize-timing-functions": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", - "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } + "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/postcss-normalize-unicode": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", - "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-normalize-url": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", - "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/postcss-normalize-whitespace": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", - "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-opacity-percentage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-3.0.0.tgz", - "integrity": "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==", + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { - "type": "kofi", - "url": "https://ko-fi.com/mrcgrtz" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "liberapay", - "url": "https://liberapay.com/mrcgrtz" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "license": "MIT" }, - "node_modules/postcss-ordered-values": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", - "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "cssnano-utils": "^4.0.2", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-overflow-shorthand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-6.0.0.tgz", - "integrity": "sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==", + "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "license": "MIT" }, - "node_modules/postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "license": "MIT", - "peerDependencies": { - "postcss": "^8" - } + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/postcss-place": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-10.0.0.tgz", - "integrity": "sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw==", + "node_modules/micromark/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-preset-env": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.3.1.tgz", - "integrity": "sha512-8ZOOWVwQ0iMpfEYkYo+U6W7fE2dJ/tP6dtEFwPJ66eB5JjnFupfYh+y6zo+vWDO72nGhKOVdxwhTjfzcSNRg4Q==", + "node_modules/micromark/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", + "license": "MIT", "dependencies": { - "@csstools/postcss-alpha-function": "^1.0.0", - "@csstools/postcss-cascade-layers": "^5.0.2", - "@csstools/postcss-color-function": "^4.0.11", - "@csstools/postcss-color-function-display-p3-linear": "^1.0.0", - "@csstools/postcss-color-mix-function": "^3.0.11", - "@csstools/postcss-color-mix-variadic-function-arguments": "^1.0.1", - "@csstools/postcss-content-alt-text": "^2.0.7", - "@csstools/postcss-exponential-functions": "^2.0.9", - "@csstools/postcss-font-format-keywords": "^4.0.0", - "@csstools/postcss-gamut-mapping": "^2.0.11", - "@csstools/postcss-gradients-interpolation-method": "^5.0.11", - "@csstools/postcss-hwb-function": "^4.0.11", - "@csstools/postcss-ic-unit": "^4.0.3", - "@csstools/postcss-initial": "^2.0.1", - "@csstools/postcss-is-pseudo-class": "^5.0.3", - "@csstools/postcss-light-dark-function": "^2.0.10", - "@csstools/postcss-logical-float-and-clear": "^3.0.0", - "@csstools/postcss-logical-overflow": "^2.0.0", - "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", - "@csstools/postcss-logical-resize": "^3.0.0", - "@csstools/postcss-logical-viewport-units": "^3.0.4", - "@csstools/postcss-media-minmax": "^2.0.9", - "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.5", - "@csstools/postcss-nested-calc": "^4.0.0", - "@csstools/postcss-normalize-display-values": "^4.0.0", - "@csstools/postcss-oklab-function": "^4.0.11", - "@csstools/postcss-progressive-custom-properties": "^4.2.0", - "@csstools/postcss-random-function": "^2.0.1", - "@csstools/postcss-relative-color-syntax": "^3.0.11", - "@csstools/postcss-scope-pseudo-class": "^4.0.1", - "@csstools/postcss-sign-functions": "^1.1.4", - "@csstools/postcss-stepped-value-functions": "^4.0.9", - "@csstools/postcss-text-decoration-shorthand": "^4.0.3", - "@csstools/postcss-trigonometric-functions": "^4.0.9", - "@csstools/postcss-unset-value": "^4.0.0", - "autoprefixer": "^10.4.21", - "browserslist": "^4.25.1", - "css-blank-pseudo": "^7.0.1", - "css-has-pseudo": "^7.0.3", - "css-prefers-color-scheme": "^10.0.0", - "cssdb": "^8.4.0", - "postcss-attribute-case-insensitive": "^7.0.1", - "postcss-clamp": "^4.1.0", - "postcss-color-functional-notation": "^7.0.11", - "postcss-color-hex-alpha": "^10.0.0", - "postcss-color-rebeccapurple": "^10.0.0", - "postcss-custom-media": "^11.0.6", - "postcss-custom-properties": "^14.0.6", - "postcss-custom-selectors": "^8.0.5", - "postcss-dir-pseudo-class": "^9.0.1", - "postcss-double-position-gradients": "^6.0.3", - "postcss-focus-visible": "^10.0.1", - "postcss-focus-within": "^9.0.1", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^6.0.0", - "postcss-image-set-function": "^7.0.0", - "postcss-lab-function": "^7.0.11", - "postcss-logical": "^8.1.0", - "postcss-nesting": "^13.0.2", - "postcss-opacity-percentage": "^3.0.0", - "postcss-overflow-shorthand": "^6.0.0", - "postcss-page-break": "^3.0.4", - "postcss-place": "^10.0.0", - "postcss-pseudo-class-any-link": "^10.0.1", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^8.0.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-pseudo-class-any-link": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz", - "integrity": "sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==", + "node_modules/micromark/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "MIT-0", + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^7.0.0" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=8.6" } }, - "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=4" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/postcss-reduce-idents": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz", - "integrity": "sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA==", + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" + "bin": { + "mime": "cli.js" }, "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "node": ">=4.0.0" } }, - "node_modules/postcss-reduce-initial": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", - "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", "dependencies": { - "browserslist": "^4.23.0", - "caniuse-api": "^3.0.0" + "brace-expansion": "^5.0.8" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "18 || 20 || >=22" }, - "peerDependencies": { - "postcss": "^8.4.31" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/postcss-reduce-transforms": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", - "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "minipass": "^7.1.2" }, "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "node": ">= 18" } }, - "node_modules/postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "license": "MIT", - "peerDependencies": { - "postcss": "^8.0.3" + "engines": { + "node": ">=10" } }, - "node_modules/postcss-selector-not": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz", - "integrity": "sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "funding": [ { "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "url": "https://github.com/sponsors/ai" } ], "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^7.0.0" + "bin": { + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=4" + "node": ">= 0.6" } }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "node_modules/neotraverse": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", + "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, + "peer": true, "engines": { - "node": ">=4" + "node": ">= 10" } }, - "node_modules/postcss-sort-media-queries": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz", - "integrity": "sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==", + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", "license": "MIT", "dependencies": { - "sort-css-media-queries": "2.2.0" - }, - "engines": { - "node": ">=14.0.0" + "@types/nlcst": "^2.0.0" }, - "peerDependencies": { - "postcss": "^8.4.23" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-svgo": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", - "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.2.0" + "whatwg-url": "^5.0.0" }, "engines": { - "node": "^14 || ^16 || >= 18" + "node": "4.x || >=6.0.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node_modules/postcss-unique-selectors": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", - "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.16" - }, + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-html-parser": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-9.0.1.tgz", + "integrity": "sha512-QrdiYYm1NnLRXsMXThUgVcF/syWfWIgHFmy8hylWMGFbHFtnRuXLBxxGQvIm3xaIJMUDJ0ayOmT/FGJYT3pZIw==", + "license": "MIT", + "dependencies": { + "css-select": "^5.1.0", + "entities": "^8.0.0" + } + }, + "node_modules/node-html-parser/node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "license": "BSD-2-Clause", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": ">=20.19.0" }, - "peerDependencies": { - "postcss": "^8.4.31" + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "node_modules/node-mock-http": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.5.tgz", + "integrity": "sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==", "license": "MIT" }, - "node_modules/postcss-zindex": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-6.0.2.tgz", - "integrity": "sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==", + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "node": ">=18" } }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", + "node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "license": "ISC", + "dependencies": { + "abbrev": "^3.0.0" + }, "bin": { - "nanoid": "bin/nanoid.cjs" + "nopt": "bin/nopt.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/pretty-bytes": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", - "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "license": "MIT", - "engines": { - "node": "^14.13.1 || >=16.0.0" + "dependencies": { + "path-key": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8" } }, - "node_modules/pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "license": "MIT", + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "node_modules/nwsapi": { + "version": "2.2.21", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", + "integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, + "optional": true, + "peer": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "node_modules/pretty-ms": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-8.0.0.tgz", - "integrity": "sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==", + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", - "dependencies": { - "parse-ms": "^3.0.0" - }, "engines": { - "node": ">=14.16" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/pretty-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", - "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], "license": "MIT", "engines": { - "node": ">=4" + "node": ">=12.20.0" } }, - "node_modules/prism-react-renderer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz", - "integrity": "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==", + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", "license": "MIT", "dependencies": { - "@types/prismjs": "^1.26.0", - "clsx": "^2.0.0" - }, - "peerDependencies": { - "react": ">=16.0.0" - } - }, - "node_modules/prismjs": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", - "license": "MIT", - "engines": { - "node": ">=6" + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", "license": "MIT" }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" + "ee-first": "1.1.1" }, "engines": { - "node": ">= 6" + "node": ">= 0.8" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/property-information": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "wrappy": "1" } }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "license": "ISC" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "license": "MIT", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", "license": "MIT" }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" } }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "dev": true, + "node_modules/os-paths": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/os-paths/-/os-paths-4.4.0.tgz", + "integrity": "sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 6.0" } }, - "node_modules/pupa": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", - "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "node_modules/ow": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/ow/-/ow-0.28.2.tgz", + "integrity": "sha512-dD4UpyBh/9m4X2NVjA+73/ZPBRF+uF4zIMFvvQsabMiEK8x41L3rQ8EENOi35kyyoaJwNxEeJcP6Fj1H4U409Q==", "license": "MIT", "dependencies": { - "escape-goat": "^4.0.0" + "@sindresorhus/is": "^4.2.0", + "callsites": "^3.1.0", + "dot-prop": "^6.0.1", + "lodash.isequal": "^4.5.0", + "vali-date": "^1.0.0" }, "engines": { - "node": ">=12.20" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", + "node_modules/p-limit": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", + "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", + "license": "MIT", + "peer": true, "dependencies": { - "side-channel": "^1.0.6" + "yocto-queue": "^1.1.1" }, "engines": { - "node": ">=0.6" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/package-manager-detector": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.8.0.tgz", + "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==", "license": "MIT" }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "node_modules/pagefind": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.5.2.tgz", + "integrity": "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==", "license": "MIT", - "engines": { - "node": ">=10" + "bin": { + "pagefind": "lib/runner/bin.cjs" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "@pagefind/darwin-arm64": "1.5.2", + "@pagefind/darwin-x64": "1.5.2", + "@pagefind/freebsd-x64": "1.5.2", + "@pagefind/linux-arm64": "1.5.2", + "@pagefind/linux-x64": "1.5.2", + "@pagefind/windows-arm64": "1.5.2", + "@pagefind/windows-x64": "1.5.2" } }, - "node_modules/radix-ui": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz", - "integrity": "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-accessible-icon": "1.1.7", - "@radix-ui/react-accordion": "1.2.12", - "@radix-ui/react-alert-dialog": "1.1.15", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-aspect-ratio": "1.1.7", - "@radix-ui/react-avatar": "1.1.10", - "@radix-ui/react-checkbox": "1.3.3", - "@radix-ui/react-collapsible": "1.1.12", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-context-menu": "2.2.16", - "@radix-ui/react-dialog": "1.1.15", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-dropdown-menu": "2.1.16", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-form": "0.1.8", - "@radix-ui/react-hover-card": "1.1.15", - "@radix-ui/react-label": "2.1.7", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-menubar": "1.1.16", - "@radix-ui/react-navigation-menu": "1.2.14", - "@radix-ui/react-one-time-password-field": "0.1.8", - "@radix-ui/react-password-toggle-field": "0.1.3", - "@radix-ui/react-popover": "1.1.15", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-progress": "1.1.7", - "@radix-ui/react-radio-group": "1.3.8", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-scroll-area": "1.2.10", - "@radix-ui/react-select": "2.2.6", - "@radix-ui/react-separator": "1.1.7", - "@radix-ui/react-slider": "1.3.6", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-switch": "1.2.6", - "@radix-ui/react-tabs": "1.1.13", - "@radix-ui/react-toast": "1.2.15", - "@radix-ui/react-toggle": "1.1.10", - "@radix-ui/react-toggle-group": "1.1.11", - "@radix-ui/react-toolbar": "1.1.11", - "@radix-ui/react-tooltip": "1.2.8", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-escape-keydown": "1.1.1", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/radix-vue": { - "version": "1.9.17", - "resolved": "https://registry.npmjs.org/radix-vue/-/radix-vue-1.9.17.tgz", - "integrity": "sha512-mVCu7I2vXt1L2IUYHTt0sZMz7s1K2ZtqKeTIxG3yC5mMFfLBG4FtE1FDeRMpDd+Hhg/ybi9+iXmAP1ISREndoQ==", + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-latin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.6.7", - "@floating-ui/vue": "^1.1.0", - "@internationalized/date": "^3.5.4", - "@internationalized/number": "^3.5.3", - "@tanstack/vue-virtual": "^3.8.1", - "@vueuse/core": "^10.11.0", - "@vueuse/shared": "^10.11.0", - "aria-hidden": "^1.2.4", - "defu": "^6.1.4", - "fast-deep-equal": "^3.1.3", - "nanoid": "^5.0.7" + "@types/nlcst": "^2.0.0", + "@types/unist": "^3.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-modify-children": "^4.0.0", + "unist-util-visit-children": "^3.0.0", + "vfile": "^6.0.0" }, - "peerDependencies": { - "vue": ">= 3.2.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/radix-vue/node_modules/@vueuse/core": { - "version": "10.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.1.tgz", - "integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==", + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "license": "MIT", "dependencies": { - "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "10.11.1", - "@vueuse/shared": "10.11.1", - "vue-demi": ">=0.14.8" + "entities": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/radix-vue/node_modules/@vueuse/core/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", "engines": { - "node": ">=12" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/radix-vue/node_modules/@vueuse/metadata": { - "version": "10.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.1.tgz", - "integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==", + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" + "engines": { + "node": ">= 0.8" } }, - "node_modules/radix-vue/node_modules/@vueuse/shared": { - "version": "10.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.1.tgz", - "integrity": "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==", + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", "dependencies": { - "vue-demi": ">=0.14.8" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/radix-vue/node_modules/@vueuse/shared/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT" + }, + "node_modules/path-to-regexp-updated": { + "name": "path-to-regexp", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/piccolore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", + "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==", + "license": "ISC" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" + "engines": { + "node": ">=16.20.0" } }, - "node_modules/range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" } }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "node_modules/postcss": { + "version": "8.5.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.24.tgz", + "integrity": "sha512-8RyVklq0owXUTa4xlpzu4l9AaVKIdQvAcOHZWaMh98HgySsUtxRVf/chRe3dsSLqb6i40BzGRzEUddRaI+9TSw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">= 0.8" + "node": "^10 || ^12 || >=14" } }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, - "bin": { - "rc": "cli.js" + "engines": { + "node": ">=4" } }, - "node_modules/rc/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "devOptional": true, "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, "engines": { - "node": ">=0.10.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "node_modules/process-ancestry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/process-ancestry/-/process-ancestry-0.1.0.tgz", + "integrity": "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/react-fast-compare": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", - "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, - "node_modules/react-helmet-async": { - "name": "@slorber/react-helmet-async", - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@slorber/react-helmet-async/-/react-helmet-async-1.3.0.tgz", - "integrity": "sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A==", - "license": "Apache-2.0", - "dependencies": { - "@babel/runtime": "^7.12.5", - "invariant": "^2.2.4", - "prop-types": "^15.7.2", - "react-fast-compare": "^3.2.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/react-json-view-lite": { + "node_modules/prompts": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-2.4.2.tgz", - "integrity": "sha512-m7uTsXDgPQp8R9bJO4HD/66+i218eyQPAb+7/dGQpwg8i4z2afTFqtHJPQFHvJfgDCjGQ1HSGlL3HtrZDa3Tdg==", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "license": "MIT", - "engines": { - "node": ">=18" + "peer": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0" + "engines": { + "node": ">= 6" } }, - "node_modules/react-loadable": { - "name": "@docusaurus/react-loadable", - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", - "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", "license": "MIT", - "dependencies": { - "@types/react": "*" - }, - "peerDependencies": { - "react": "*" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/react-loadable-ssr-addon-v5-slorber": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", - "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.10.3" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "react-loadable": "*", - "webpack": ">=4.41.1 || 5.x" + "node": ">= 0.10" } }, - "node_modules/react-markdown": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", - "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "hast-util-to-jsx-runtime": "^2.0.0", - "html-url-attributes": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "unified": "^11.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=18", - "react": ">=18" + "optional": true, + "engines": { + "node": ">=6" } }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/react-remove-scroll": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", - "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", - "license": "MIT", + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", "dependencies": { - "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.3", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.3" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + "node": ">=0.6" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-remove-scroll-bar": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", - "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", "license": "MIT", - "dependencies": { - "react-style-singleton": "^2.2.2", - "tslib": "^2.0.0" - }, "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "node": ">= 0.6" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/react-router": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", - "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, - "peerDependencies": { - "react": ">=15" + "engines": { + "node": ">= 0.10" } }, - "node_modules/react-router-config": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", - "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.1.2" - }, - "peerDependencies": { - "react": ">=15", - "react-router": ">=5" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/react-router-dom": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", - "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.3.4", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": ">=15" + "react": "^19.2.8" } }, - "node_modules/react-router/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/react-style-singleton": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", - "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", "license": "MIT", - "dependencies": { - "get-nonce": "^1.0.0", - "tslib": "^2.0.0" - }, "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "node": ">=0.10.0" } }, "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" }, "node_modules/recma-build-jsx": { "version": "1.0.0", @@ -23011,138 +16331,41 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "license": "MIT" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", - "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regexpu-core": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", - "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.0", - "regjsgen": "^0.8.0", - "regjsparser": "^0.12.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/registry-auth-token": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz", - "integrity": "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==", + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", "license": "MIT", "dependencies": { - "@pnpm/npm-conf": "^2.1.0" - }, - "engines": { - "node": ">=14" + "regex-utilities": "^2.3.0" } }, - "node_modules/registry-url": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", - "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", "license": "MIT", "dependencies": { - "rc": "1.2.8" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "regex-utilities": "^2.3.0" } }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", "license": "MIT" }, - "node_modules/regjsparser": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", - "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.0.2" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/rehype-external-links": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", - "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@ungap/structured-clone": "^1.0.0", - "hast-util-is-element": "^3.0.0", - "is-absolute-url": "^4.0.0", - "space-separated-tokens": "^2.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rehype-format": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/rehype-format/-/rehype-format-5.0.1.tgz", - "integrity": "sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==", + "node_modules/rehype": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", + "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==", "license": "MIT", + "peer": true, "dependencies": { "@types/hast": "^3.0.0", - "hast-util-format": "^1.0.0" + "rehype-parse": "^9.0.0", + "rehype-stringify": "^10.0.0", + "unified": "^11.0.0" }, "funding": { "type": "opencollective", @@ -23154,6 +16377,7 @@ "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", "license": "MIT", + "peer": true, "dependencies": { "@types/hast": "^3.0.0", "hast-util-from-html": "^2.0.0", @@ -23164,115 +16388,44 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-raw": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", - "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-raw": "^9.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rehype-recma": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", - "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "hast-util-to-estree": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rehype-sanitize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/rehype-sanitize/-/rehype-sanitize-6.0.0.tgz", - "integrity": "sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-sanitize": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rehype-stringify": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", - "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-to-html": "^9.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remark-directive": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.1.tgz", - "integrity": "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==", + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", "license": "MIT", "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-directive": "^3.0.0", - "micromark-extension-directive": "^3.0.0", - "unified": "^11.0.0" + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/remark-emoji": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz", - "integrity": "sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg==", + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", "license": "MIT", "dependencies": { - "@types/mdast": "^4.0.2", - "emoticon": "^4.0.1", - "mdast-util-find-and-replace": "^3.0.1", - "node-emoji": "^2.1.0", - "unified": "^11.0.4" + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/remark-frontmatter": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", - "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "node_modules/rehype-stringify": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", "license": "MIT", "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-frontmatter": "^2.0.0", - "micromark-extension-frontmatter": "^2.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", "unified": "^11.0.0" }, "funding": { @@ -23345,6 +16498,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-smartypants": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.3.tgz", + "integrity": "sha512-gCaK+ndZ0hYezlqFegHFCVh2CQemsi0Npdh1qVM9bxlUFknjkbP6VmojWhddOCrbK0PbbacmYLWfTULRiT1eWA==", + "license": "MIT", + "dependencies": { + "retext": "^9.0.0", + "retext-smartypants": "^6.0.0", + "unified": "^11.0.4", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/remark-stringify": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", @@ -23360,126 +16528,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "license": "MIT", - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/renderkid/node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/renderkid/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "license": "BSD-2-Clause", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/renderkid/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } + "node_modules/request-light": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.7.0.tgz", + "integrity": "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==", + "license": "MIT" }, "node_modules/require-from-string": { "version": "2.0.2", @@ -23490,129 +16543,80 @@ "node": ">=0.10.0" } }, - "node_modules/require-like": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", - "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", - "engines": { - "node": "*" - } - }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "license": "MIT" }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "license": "MIT" - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "license": "MIT", - "engines": { - "node": ">=4" + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==", - "license": "MIT" - }, - "node_modules/responselike": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "node_modules/retext": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", "license": "MIT", "dependencies": { - "lowercase-keys": "^3.0.0" - }, - "engines": { - "node": ">=14.16" + "@types/nlcst": "^2.0.0", + "retext-latin": "^4.0.0", + "retext-stringify": "^4.0.0", + "unified": "^11.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, + "node_modules/retext-latin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", "license": "MIT", "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" + "@types/nlcst": "^2.0.0", + "parse-latin": "^7.0.0", + "unified": "^11.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, + "node_modules/retext-smartypants": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", "license": "MIT", "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" + "node_modules/retext-stringify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unified": "^11.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "license": "MIT", - "engines": { - "node": ">= 4" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/reusify": { @@ -23625,27 +16629,55 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" + }, + "node_modules/rolldown": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", + "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "@oxc-project/types": "=0.139.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { - "rimraf": "bin.js" + "rolldown": "bin/cli.mjs" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.1.5", + "@rolldown/binding-darwin-arm64": "1.1.5", + "@rolldown/binding-darwin-x64": "1.1.5", + "@rolldown/binding-freebsd-x64": "1.1.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", + "@rolldown/binding-linux-arm64-gnu": "1.1.5", + "@rolldown/binding-linux-arm64-musl": "1.1.5", + "@rolldown/binding-linux-ppc64-gnu": "1.1.5", + "@rolldown/binding-linux-s390x-gnu": "1.1.5", + "@rolldown/binding-linux-x64-gnu": "1.1.5", + "@rolldown/binding-linux-x64-musl": "1.1.5", + "@rolldown/binding-openharmony-arm64": "1.1.5", + "@rolldown/binding-wasm32-wasi": "1.1.5", + "@rolldown/binding-win32-arm64-msvc": "1.1.5", + "@rolldown/binding-win32-x64-msvc": "1.1.5" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "license": "MIT" }, "node_modules/rollup": { "version": "4.50.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.0.tgz", "integrity": "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw==", - "devOptional": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -23682,31 +16714,53 @@ "fsevents": "~2.3.2" } }, - "node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true, - "license": "MIT" + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } }, - "node_modules/rtlcss": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", - "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0", - "postcss": "^8.4.21", - "strip-json-comments": "^3.1.1" - }, - "bin": { - "rtlcss": "bin/rtlcss.js" + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">= 18" + } + }, + "node_modules/router/node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -23730,34 +16784,11 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -23770,6 +16801,8 @@ "resolved": "https://registry.npmjs.org/sass/-/sass-1.91.0.tgz", "integrity": "sha512-aFOZHGf+ur+bp1bCHZ+u8otKGh77ZtmFyXDo4tlYvT7PWql41Kwd8wdkPqhhT+h2879IVblcHFglIMofsFd1EA==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -23785,51 +16818,13 @@ "@parcel/watcher": "^2.4.1" } }, - "node_modules/sass-loader": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.5.tgz", - "integrity": "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==", - "license": "MIT", - "dependencies": { - "neo-async": "^2.6.2" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", - "sass": "^1.3.0", - "sass-embedded": "*", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, "node_modules/sass/node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -23845,6 +16840,8 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 14.18.0" }, @@ -23853,11 +16850,37 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/satteri": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.9.5.tgz", + "integrity": "sha512-ZuWVl+vnM64y+/TtX8Kosv2c00W+hLQiiwnEL6H0UKVVrxFqMw4D2CJHHQaouVd89OAhtBBfjWLqhKi3TVUV4w==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.5", + "@types/hast": "^3.0.4", + "@types/mdast": "^4.0.4", + "@types/unist": "^3.0.3" + }, + "optionalDependencies": { + "@bruits/satteri-darwin-arm64": "0.9.5", + "@bruits/satteri-darwin-x64": "0.9.5", + "@bruits/satteri-linux-arm64-gnu": "0.9.5", + "@bruits/satteri-linux-arm64-musl": "0.9.5", + "@bruits/satteri-linux-x64-gnu": "0.9.5", + "@bruits/satteri-linux-x64-musl": "0.9.5", + "@bruits/satteri-wasm32-wasi": "0.9.5", + "@bruits/satteri-win32-arm64-msvc": "0.9.5", + "@bruits/satteri-win32-x64-msvc": "0.9.5" + } + }, "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "license": "ISC" + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } }, "node_modules/saxes": { "version": "6.0.0", @@ -23865,6 +16888,8 @@ "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "license": "ISC", + "optional": true, + "peer": true, "dependencies": { "xmlchars": "^2.2.0" }, @@ -23873,60 +16898,9 @@ } }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/schema-dts": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-1.1.5.tgz", - "integrity": "sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==", - "license": "Apache-2.0" - }, - "node_modules/schema-utils": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", - "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/schema-utils/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/search-insights": { - "version": "2.17.3", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", - "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, "node_modules/section-matter": { @@ -23942,29 +16916,10 @@ "node": ">=4" } }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "license": "MIT" - }, - "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", - "license": "MIT", - "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -23973,305 +16928,238 @@ "node": ">=10" } }, - "node_modules/semver-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", - "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { - "semver": "^7.3.5" + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, "engines": { - "node": ">=12" + "node": ">= 18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-handler": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", - "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", - "license": "MIT", - "dependencies": { - "bytes": "3.0.0", - "content-disposition": "0.5.2", - "mime-types": "2.1.18", - "minimatch": "3.1.2", - "path-is-inside": "1.0.2", - "path-to-regexp": "3.3.0", - "range-parser": "1.2.0" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/serve-handler/node_modules/mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/serve-handler/node_modules/mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "node_modules/send/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { - "mime-db": "~1.33.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-handler/node_modules/path-to-regexp": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", - "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", - "license": "MIT" - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "node": ">=18" }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", "license": "ISC" }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "license": "MIT" }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "license": "MIT", + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, "engines": { - "node": ">= 0.6" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" } }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "node_modules/shiki": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.3.1.tgz", + "integrity": "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw==", "license": "MIT", "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" + "@shikijs/core": "4.3.1", + "@shikijs/engine-javascript": "4.3.1", + "@shikijs/engine-oniguruma": "4.3.1", + "@shikijs/langs": "4.3.1", + "@shikijs/themes": "4.3.1", + "@shikijs/types": "4.3.1", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" }, "engines": { - "node": ">= 0.4" + "node": ">=20" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "node_modules/shiki/node_modules/@shikijs/engine-oniguruma": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.3.1.tgz", + "integrity": "sha512-OXyNMzg0pews+msMj4cHeqT4xiYKKvbnn6VbdAXxfoFl3SSx4fJTc8FadECuc5/H9p3BzhNAoAUXKwAu9rWYhg==", "license": "MIT", "dependencies": { - "kind-of": "^6.0.2" + "@shikijs/types": "4.3.1", + "@shikijs/vscode-textmate": "^10.0.2" }, "engines": { - "node": ">=8" - } - }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", - "license": "MIT" + "node": ">=20" + } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/shiki/node_modules/@shikijs/langs": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.3.1.tgz", + "integrity": "sha512-m0l9nsDqgBHvbZbk7A0/kXz/impK3uB/c6rAn6Gpg/uPtdZRQ+alsN/17MU5thb68XTj/4DxkZAotrM0GGSpDQ==", "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "@shikijs/types": "4.3.1" }, "engines": { - "node": ">=8" + "node": ">=20" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/shiki/node_modules/@shikijs/themes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.3.1.tgz", + "integrity": "sha512-dgpoJ4WqNi2yTmizQHBJ5zcX6j2lE6icN/0yt4l1kkf16jrY/pwPLoTb1ETsWMz0OBLf9ZNvwmxft+cH+N9qSA==", "license": "MIT", + "dependencies": { + "@shikijs/types": "4.3.1" + }, "engines": { - "node": ">=8" + "node": ">=20" } }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "node_modules/shiki/node_modules/@shikijs/types": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.1.tgz", + "integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=20" } }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -24283,13 +17171,13 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -24348,18 +17236,17 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, - "node_modules/sirv": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", - "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", - "license": "MIT", - "dependencies": { - "@polka/url": "^1.0.0-next.24", - "mrmime": "^2.0.0", - "totalist": "^3.0.0" - }, + "node_modules/simple-icons": { + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-13.21.0.tgz", + "integrity": "sha512-LI5pVJPBv6oc79OMsffwb6kEqnmB8P1Cjg1crNUlhsxPETQ5UzbCKQdxU+7MW6+DD1qfPkla/vSKlLD4IfyXpQ==", + "license": "CC0-1.0", "engines": { - "node": ">= 10" + "node": ">=0.12.18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/simple-icons" } }, "node_modules/sisteransi": { @@ -24368,89 +17255,25 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "license": "MIT" }, - "node_modules/sitemap": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.2.tgz", - "integrity": "sha512-ARCqzHJ0p4gWt+j7NlU5eDlIO9+Rkr/JhPFZKKQ1l5GCus7rJH4UdrlVAh0xC/gDS/Qir2UMxqYNHtsKr2rpCw==", - "license": "MIT", - "dependencies": { - "@types/node": "^17.0.5", - "@types/sax": "^1.2.1", - "arg": "^5.0.0", - "sax": "^1.2.4" - }, - "bin": { - "sitemap": "dist/cli.js" - }, - "engines": { - "node": ">=12.0.0", - "npm": ">=5.6.0" - } - }, - "node_modules/sitemap/node_modules/@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", - "license": "MIT" - }, - "node_modules/skin-tone": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", - "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", - "license": "MIT", - "dependencies": { - "unicode-emoji-modifier-base": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/slugify": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.9.tgz", + "integrity": "sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==", "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/snake-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", - "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", - "license": "MIT", - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "license": "MIT", - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/sockjs/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "node": ">=8.0.0" } }, - "node_modules/sort-css-media-queries": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz", - "integrity": "sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==", - "license": "MIT", + "node_modules/smol-toml": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.1.tgz", + "integrity": "sha512-PPlsspAZ4jbMBu5DMFhfUGDQLu/vrL4SyBROVS37x8ynnVmFIs1VPBz1Co8Xks3TvpIaZXmU85y4DrQ+UyVFoQ==", + "license": "BSD-3-Clause", "engines": { - "node": ">= 6.3.0" + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" } }, "node_modules/source-map": { @@ -24476,6 +17299,8 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -24486,6 +17311,8 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "license": "BSD-3-Clause", + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -24500,54 +17327,12 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "license": "MIT", - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "license": "MIT", - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "license": "BSD-3-Clause" }, - "node_modules/srcset": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", - "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -24556,58 +17341,35 @@ "license": "MIT" }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/std-env": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", - "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", - "license": "MIT" - }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, - "node_modules/string-width": { + "node_modules/string_decoder/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" }, "node_modules/stringify-entities": { "version": "4.0.4", @@ -24623,27 +17385,13 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "license": "BSD-2-Clause", - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -24653,9 +17401,9 @@ } }, "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz", - "integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -24682,57 +17430,6 @@ "node": ">=6" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-literal": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", - "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/strip-literal/node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/style-mod": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", - "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", - "license": "MIT" - }, "node_modules/style-to-js": { "version": "1.1.17", "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.17.tgz", @@ -24744,160 +17441,64 @@ }, "node_modules/style-to-object": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz", - "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==", - "license": "MIT", - "dependencies": { - "inline-style-parser": "0.2.4" - } - }, - "node_modules/stylehacks": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", - "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", - "license": "MIT", - "dependencies": { - "browserslist": "^4.23.0", - "postcss-selector-parser": "^6.0.16" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/supertokens-js-override": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/supertokens-js-override/-/supertokens-js-override-0.0.4.tgz", - "integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg==", - "license": "Apache-2.0" - }, - "node_modules/supertokens-website": { - "version": "20.1.6", - "resolved": "https://registry.npmjs.org/supertokens-website/-/supertokens-website-20.1.6.tgz", - "integrity": "sha512-WSehco2PsrFp4WY7h6tDutYyi2nPgJS8lahUadcL/cpBqgEuZ3pjnvN1NDASSNSTfXeO1smm3HrvvLZG5C7qHA==", - "license": "Apache-2.0", - "dependencies": { - "browser-tabs-lock": "^1.3.0", - "supertokens-js-override": "^0.0.4" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "license": "MIT" - }, - "node_modules/svgo": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", - "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", - "license": "MIT", - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.3.1", - "css-what": "^6.1.0", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/svgo" - } - }, - "node_modules/svgo/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/swc-loader": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz", - "integrity": "sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==", - "devOptional": true, + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz", + "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==", "license": "MIT", "dependencies": { - "@swc/counter": "^0.1.3" - }, - "peerDependencies": { - "@swc/core": "^1.2.147", - "webpack": ">=2" + "inline-style-parser": "0.2.4" } }, + "node_modules/stylis": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", + "license": "MIT" + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true, - "license": "MIT" - }, - "node_modules/tabbable": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, - "node_modules/tailwind-merge": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", - "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", "license": "MIT", + "engines": { + "node": ">=20" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tailwindcss": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", - "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", - "license": "MIT", - "peer": true + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "license": "MIT" + }, + "node_modules/takumi-js": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/takumi-js/-/takumi-js-2.5.3.tgz", + "integrity": "sha512-OIrWzoxTo8BJw8VpVtMpqMAsaoWXyhnyiBFwY7DlKVog/Y+CPIaU7+kB7Onlu1iKAxXJxJWtCoXlWnIGwwFQ7w==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@takumi-rs/core": "2.5.3", + "@takumi-rs/helpers": "2.5.3", + "@takumi-rs/wasm": "2.5.3" + }, + "engines": { + "node": ">=18" + } }, "node_modules/tapable": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz", - "integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "license": "MIT", "engines": { "node": ">=6" @@ -24907,11 +17508,38 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/tar": { + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/terser": { "version": "5.43.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "license": "BSD-2-Clause", + "optional": true, + "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.14.0", @@ -24925,76 +17553,18 @@ "node": ">=10" } }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.14", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", - "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", - "terser": "^5.31.1" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "license": "MIT" - }, - "node_modules/tiny-invariant": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, - "node_modules/tiny-warning": { + "node_modules/tiny-inflate": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", "license": "MIT" }, "node_modules/tinybench": { @@ -25004,22 +17574,32 @@ "dev": true, "license": "MIT" }, + "node_modules/tinyclip": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.15.tgz", + "integrity": "sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A==", + "license": "MIT", + "engines": { + "node": "^16.14.0 || >= 17.3.0" + } + }, "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, - "license": "MIT" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/tinyglobby": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", - "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", - "dev": true, + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "license": "MIT", "dependencies": { - "fdir": "^6.4.4", - "picomatch": "^4.0.2" + "fdir": "^6.5.0", + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -25028,29 +17608,10 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinypool": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", - "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", - "license": "MIT", - "engines": { - "node": "^18.0.0 || >=20.0.0" - } - }, "node_modules/tinyrainbow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", - "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", "dev": true, "license": "MIT", "engines": { @@ -25063,6 +17624,8 @@ "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "tldts-core": "^6.1.86" }, @@ -25075,7 +17638,9 @@ "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -25098,21 +17663,14 @@ "node": ">=0.6" } }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/tough-cookie": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", "dev": true, "license": "BSD-3-Clause", + "optional": true, + "peer": true, "dependencies": { "tldts": "^6.1.32" }, @@ -25126,6 +17684,8 @@ "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "punycode": "^2.3.1" }, @@ -25255,26 +17815,47 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ts-deepmerge": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-7.0.3.tgz", - "integrity": "sha512-Du/ZW2RfwV/D4cmA5rXafYjBQVuvu4qGiEEla4EmEHVHgRdx68Gftx7i66jn2bzHPwSVZY36Ae6OuDn9el4ZKA==", - "license": "ISC", + "node_modules/ts-dedent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", + "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", + "license": "MIT", "engines": { - "node": ">=14.13.1" + "node": ">=6.10" } }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" + "license": "0BSD", + "optional": true + }, + "node_modules/twoslash": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.3.9.tgz", + "integrity": "sha512-rDclk+OtzuTX+tnea7DYLCkqGQ3eP0IyfD+kzUJ7t46X/NzlaxwrhecmEBNuSCuEn3V+n1PhcjUUQQ7gUJzX5Q==", + "license": "MIT", + "dependencies": { + "@typescript/vfs": "^1.6.4", + "twoslash-protocol": "0.3.9" + }, + "peerDependencies": { + "typescript": "^5.5.0 || ^6.0.0" + } + }, + "node_modules/twoslash-protocol": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.3.9.tgz", + "integrity": "sha512-9/iwp+CXOnjFMPQuPL5PkuRbZnDoNpBvtJCLs9t8kDYkL3YHujbvnHfZA1i5fApDftVEdBw+T/4F+dH5kIzpYQ==", + "license": "MIT" }, "node_modules/type-fest": { "version": "4.41.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=16" }, @@ -25283,39 +17864,73 @@ } }, "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { - "is-typedarray": "^1.0.0" + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/typedoc": { - "version": "0.28.12", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.12.tgz", - "integrity": "sha512-H5ODu4f7N+myG4MfuSp2Vh6wV+WLoZaEYxKPt2y8hmmqNEMVrH69DAjjdmYivF4tP/C2jrIZCZhPalZlTU/ipA==", + "version": "0.28.20", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.20.tgz", + "integrity": "sha512-uSKqkh8Cr48vllnEy+jdaAgOeR6Y+QCBW7usgUsKj7gJEfR7stw9U/fE49LBnj2tPRKPY0c0EBJSWe9Appmplg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@gerrit0/mini-shiki": "^3.12.0", + "@gerrit0/mini-shiki": "^3.23.0", "lunr": "^2.3.9", - "markdown-it": "^14.1.0", - "minimatch": "^9.0.5", - "yaml": "^2.8.1" + "markdown-it": "^14.3.0", + "minimatch": "^10.2.5", + "yaml": "^2.9.0" }, "bin": { "typedoc": "bin/typedoc" @@ -25325,7 +17940,7 @@ "pnpm": ">= 10" }, "peerDependencies": { - "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x" + "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x" } }, "node_modules/typedoc-plugin-frontmatter": { @@ -25374,70 +17989,16 @@ "typedoc": "0.27.x || 0.28.x" } }, - "node_modules/typedoc-plugin-merge-modules": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/typedoc-plugin-merge-modules/-/typedoc-plugin-merge-modules-7.0.0.tgz", - "integrity": "sha512-DQyfbbPNBElhpdpGrlkS+CrhGD3iooDjp/PHT8O1D/jumLCB+7XAY3jHiqob7d01o25EfwEOJWVwJK+9J6WlBg==", - "dev": true, - "license": "ISC", - "peerDependencies": { - "typedoc": "0.28.x" - } - }, - "node_modules/typedoc-plugin-missing-exports": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-4.1.0.tgz", - "integrity": "sha512-p1M5jXnEbQ4qqy0erJz41BBZEDb8XDrbLjndlH4RhYEcymbdQr0xLF6yUw1GWBrhSIfkU98m3BELMAiQh+R1zA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "typedoc": "^0.28.1" - } - }, - "node_modules/typedoc/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typedoc/node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } + "node_modules/typesafe-path": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/typesafe-path/-/typesafe-path-0.2.2.tgz", + "integrity": "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==", + "license": "MIT" }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "devOptional": true, + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -25447,6 +18008,15 @@ "node": ">=14.17" } }, + "node_modules/typescript-auto-import-cache": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/typescript-auto-import-cache/-/typescript-auto-import-cache-0.3.6.tgz", + "integrity": "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.8" + } + }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", @@ -25454,76 +18024,40 @@ "dev": true, "license": "MIT" }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", "license": "MIT" }, - "node_modules/unhead": { - "version": "1.11.20", - "resolved": "https://registry.npmjs.org/unhead/-/unhead-1.11.20.tgz", - "integrity": "sha512-3AsNQC0pjwlLqEYHLjtichGWankK8yqmocReITecmpB1H0aOabeESueyy+8X1gyJx4ftZVwo9hqQ4O3fPWffCA==", - "license": "MIT", - "dependencies": { - "@unhead/dom": "1.11.20", - "@unhead/schema": "1.11.20", - "@unhead/shared": "1.11.20", - "hookable": "^5.5.3" - }, - "funding": { - "url": "https://github.com/sponsors/harlan-zw" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-emoji-modifier-base": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", - "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "license": "MIT", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } + "node_modules/ultrahtml": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.7.0.tgz", + "integrity": "sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==", + "license": "MIT" }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", - "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", - "license": "MIT", - "engines": { - "node": ">=4" - } + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "node_modules/undici": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.9.0.tgz", + "integrity": "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA==", "license": "MIT", "engines": { - "node": ">=4" + "node": ">=22.19.0" } }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "devOptional": true, + "license": "MIT" + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -25543,21 +18077,36 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unique-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", - "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "node_modules/unifont": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.4.tgz", + "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==", + "license": "MIT", + "dependencies": { + "css-tree": "^3.1.0", + "ofetch": "^1.5.1", + "ohash": "^2.0.11" + } + }, + "node_modules/unifont/node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "license": "MIT", "dependencies": { - "crypto-random-string": "^4.0.0" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/unifont/node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" + }, "node_modules/unist-util-find-after": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", @@ -25585,6 +18134,20 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-modify-children": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "array-iterate": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-position": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", @@ -25611,6 +18174,20 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", @@ -25625,9 +18202,9 @@ } }, "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -25639,10 +18216,23 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-visit-children": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -25657,6 +18247,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -25671,245 +18262,177 @@ "node": ">= 0.8" } }, - "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "node_modules/unstorage": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz", + "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^5.0.0", + "destr": "^2.0.5", + "h3": "^1.15.10", + "lru-cache": "^11.2.7", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.3" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6 || ^7 || ^8", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1 || ^2 || ^3", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" + "@azure/cosmos": { + "optional": true }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/update-notifier": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", - "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", - "license": "BSD-2-Clause", - "dependencies": { - "boxen": "^7.0.0", - "chalk": "^5.0.1", - "configstore": "^6.0.0", - "has-yarn": "^3.0.0", - "import-lazy": "^4.0.0", - "is-ci": "^3.0.1", - "is-installed-globally": "^0.4.0", - "is-npm": "^6.0.0", - "is-yarn-global": "^0.4.0", - "latest-version": "^7.0.0", - "pupa": "^3.1.0", - "semver": "^7.3.7", - "semver-diff": "^4.0.0", - "xdg-basedir": "^5.1.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" } }, - "node_modules/update-notifier/node_modules/boxen": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", - "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "node_modules/unstorage/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "license": "MIT", "dependencies": { - "ansi-align": "^3.0.1", - "camelcase": "^7.0.1", - "chalk": "^5.2.0", - "cli-boxes": "^3.0.0", - "string-width": "^5.1.2", - "type-fest": "^2.13.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.1.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/update-notifier/node_modules/camelcase": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", - "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", - "license": "MIT", - "engines": { - "node": ">=14.16" + "readdirp": "^5.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/update-notifier/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=12.20" + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/url-loader": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", - "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", - "license": "MIT", - "dependencies": { - "loader-utils": "^2.0.0", - "mime-types": "^2.1.27", - "schema-utils": "^3.0.0" - }, + "node_modules/unstorage/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "file-loader": "*", - "webpack": "^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "file-loader": { - "optional": true - } - } - }, - "node_modules/url-loader/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/url-loader/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" + "node": "20 || >=22" } }, - "node_modules/url-loader/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" - }, - "node_modules/url-loader/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "node_modules/unstorage/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, "engines": { - "node": ">= 10.13.0" + "node": ">= 20.19.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/use-callback-ref": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", - "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } - } - }, - "node_modules/use-sidecar": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", - "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + ], "license": "MIT", "dependencies": { - "detect-node-es": "^1.1.0", - "tslib": "^2.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, - "engines": { - "node": ">=10" + "bin": { + "update-browserslist-db": "cli.js" }, "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "browserslist": ">= 4.21.0" } }, - "node_modules/use-sync-external-store": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", - "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "punycode": "^2.1.0" } }, "node_modules/util-deprecate": { @@ -25918,30 +18441,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", - "license": "MIT" - }, - "node_modules/utility-types": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", - "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/uuid": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", @@ -25955,11 +18454,14 @@ "uuid": "dist/esm/bin/uuid" } }, - "node_modules/value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==", - "license": "MIT" + "node_modules/vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/vary": { "version": "1.1.2", @@ -26016,7 +18518,6 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.4.tgz", "integrity": "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw==", - "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", @@ -26087,89 +18588,99 @@ } } }, - "node_modules/vite-node": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", - "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", - "dev": true, + "node_modules/vitefu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.4.1", - "es-module-lexer": "^1.7.0", - "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, - "funding": { - "url": "https://opencollective.com/vitest" + "peerDependenciesMeta": { + "vite": { + "optional": true + } } }, "node_modules/vitest": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", - "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", "dev": true, "license": "MIT", "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.4", - "@vitest/mocker": "3.2.4", - "@vitest/pretty-format": "^3.2.4", - "@vitest/runner": "3.2.4", - "@vitest/snapshot": "3.2.4", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "debug": "^4.4.1", - "expect-type": "^1.2.1", - "magic-string": "^0.30.17", + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", "pathe": "^2.0.3", - "picomatch": "^4.0.2", - "std-env": "^3.9.0", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.14", - "tinypool": "^1.1.1", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.4", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.4", - "@vitest/ui": "3.2.4", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { "optional": true }, - "@types/debug": { + "@opentelemetry/api": { "optional": true }, "@types/node": { "optional": true }, - "@vitest/browser": { + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { "optional": true }, "@vitest/ui": { @@ -26180,490 +18691,362 @@ }, "jsdom": { "optional": true + }, + "vite": { + "optional": false } } }, - "node_modules/vue": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.20.tgz", - "integrity": "sha512-2sBz0x/wis5TkF1XZ2vH25zWq3G1bFEPOfkBcx2ikowmphoQsPH6X0V3mmPCXA2K1N/XGTnifVyDQP4GfDDeQw==", + "node_modules/vitest/node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/volar-service-css": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-css/-/volar-service-css-0.0.71.tgz", + "integrity": "sha512-wRRFt9BpjMKCazcgOh67MSjUjiWUCAh99DyYSDIOTuxaRjEtDC7PpB0k1Y1wbJIW/pVtMUSVbpPo3UGSm0Byxw==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.20", - "@vue/compiler-sfc": "3.5.20", - "@vue/runtime-dom": "3.5.20", - "@vue/server-renderer": "3.5.20", - "@vue/shared": "3.5.20" + "vscode-css-languageservice": "^6.3.0", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" }, "peerDependencies": { - "typescript": "*" + "@volar/language-service": "~2.4.0" }, "peerDependenciesMeta": { - "typescript": { + "@volar/language-service": { "optional": true } } }, - "node_modules/vue-component-type-helpers": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-3.0.6.tgz", - "integrity": "sha512-6CRM8X7EJqWCJOiKPvSLQG+hJPb/Oy2gyJx3pLjUEhY7PuaCthQu3e0zAGI1lqUBobrrk9IT0K8sG2GsCluxoQ==", - "license": "MIT" - }, - "node_modules/vue-router": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz", - "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==", + "node_modules/volar-service-emmet": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-emmet/-/volar-service-emmet-0.0.71.tgz", + "integrity": "sha512-zqjzt6bN95e3CUstBm0PBFAJnrfz0ZAARka87fart46/gNCLLuP3Vujy8V/J8HEziTFLnfkgIASLFYPUhonJcA==", "license": "MIT", "dependencies": { - "@vue/devtools-api": "^6.6.4" - }, - "funding": { - "url": "https://github.com/sponsors/posva" + "@emmetio/css-parser": "^0.4.1", + "@emmetio/html-matcher": "^1.3.0", + "@vscode/emmet-helper": "^2.9.3", + "vscode-uri": "^3.0.8" }, "peerDependencies": { - "vue": "^3.2.0" - } - }, - "node_modules/vue-sonner": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/vue-sonner/-/vue-sonner-1.3.2.tgz", - "integrity": "sha512-UbZ48E9VIya3ToiRHAZUbodKute/z/M1iT8/3fU8zEbwBRE11AKuHikssv18LMk2gTTr6eMQT4qf6JoLHWuj/A==", - "license": "MIT" - }, - "node_modules/w3c-keyname": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", - "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "license": "MIT" - }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/watchpack": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", - "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", - "license": "MIT", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" + "@volar/language-service": "~2.4.0" }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "license": "MIT", - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/web-namespaces": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", - "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/web-vitals": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-5.1.0.tgz", - "integrity": "sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==", - "license": "Apache-2.0" - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + } } }, - "node_modules/webpack": { - "version": "5.101.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.101.3.tgz", - "integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==", + "node_modules/volar-service-html": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-html/-/volar-service-html-0.0.71.tgz", + "integrity": "sha512-e8tHPhgQ7ooLfudAEIku+kgd9pWkq3SSz8RbnQDI1+Eb8wbenkLGHqoirLqz5ORLV6wIMr2Iv08RWBG5eOcgpw==", "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.8", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", - "acorn-import-phases": "^1.0.3", - "browserslist": "^4.24.0", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.3", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.2", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.11", - "watchpack": "^2.4.1", - "webpack-sources": "^3.3.3" + "vscode-html-languageservice": "^5.3.0", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "peerDependencies": { + "@volar/language-service": "~2.4.0" }, "peerDependenciesMeta": { - "webpack-cli": { + "@volar/language-service": { "optional": true } } }, - "node_modules/webpack-bundle-analyzer": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", - "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "node_modules/volar-service-prettier": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-prettier/-/volar-service-prettier-0.0.71.tgz", + "integrity": "sha512-Rz7JVH3qD108UCdmIEiZvOBNljMt2nLFdbN8AXcDfn7xD9F5I2aCIsDVqBbXw21PsnxG0b7MfwtNF+zPS/NKUg==", "license": "MIT", "dependencies": { - "@discoveryjs/json-ext": "0.5.7", - "acorn": "^8.0.4", - "acorn-walk": "^8.0.0", - "commander": "^7.2.0", - "debounce": "^1.2.1", - "escape-string-regexp": "^4.0.0", - "gzip-size": "^6.0.0", - "html-escaper": "^2.0.2", - "opener": "^1.5.2", - "picocolors": "^1.0.0", - "sirv": "^2.0.3", - "ws": "^7.3.1" + "vscode-uri": "^3.0.8" }, - "bin": { - "webpack-bundle-analyzer": "lib/bin/analyzer.js" + "peerDependencies": { + "@volar/language-service": "~2.4.0", + "prettier": "^2.2 || ^3.0" }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/webpack-bundle-analyzer/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "license": "MIT", - "engines": { - "node": ">= 10" + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + }, + "prettier": { + "optional": true + } } }, - "node_modules/webpack-bundle-analyzer/node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "node_modules/volar-service-typescript": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-typescript/-/volar-service-typescript-0.0.71.tgz", + "integrity": "sha512-yTtM/BVT6hoyEYnDtaCyAtNhdNeS/mhTTABlBOdw3NNiRBUin3IznFJpgfjer4c6RYopiPjjQjc9VFhxVl1mLw==", "license": "MIT", - "engines": { - "node": ">=8.3.0" + "dependencies": { + "path-browserify": "^1.0.1", + "semver": "^7.6.2", + "typescript-auto-import-cache": "^0.3.5", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-nls": "^5.2.0", + "vscode-uri": "^3.0.8" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "@volar/language-service": "~2.4.0" }, "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { + "@volar/language-service": { "optional": true } } }, - "node_modules/webpack-dev-middleware": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "node_modules/volar-service-typescript-twoslash-queries": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-typescript-twoslash-queries/-/volar-service-typescript-twoslash-queries-0.0.71.tgz", + "integrity": "sha512-9K2k72s4n7rV9s4bX0MyjbX9iBribvKZbBJKuEmTCZfeWJXs6Yh7bGpY4eoc7UufAjvpheBqwyZCOIPBvxCv0A==", "license": "MIT", "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "vscode-uri": "^3.0.8" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "@volar/language-service": "~2.4.0" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + } } }, - "node_modules/webpack-dev-middleware/node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "node_modules/volar-service-yaml": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-yaml/-/volar-service-yaml-0.0.71.tgz", + "integrity": "sha512-qYGWGuVpUTnZGu5P/CR4KLK4aIR8RrcVnmfZ2eRcj9q/I8VZCoC5yy9FtEvfNvnDp4MU17yhdJcvpQPIqhJS2Q==", "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-server": { - "version": "4.15.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", - "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", - "license": "MIT", - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.5", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.4", - "ws": "^8.13.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "dependencies": { + "vscode-uri": "^3.0.8", + "yaml-language-server": "~1.23.0" }, "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "@volar/language-service": "~2.4.0" }, "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { + "@volar/language-service": { "optional": true } } }, - "node_modules/webpack-merge": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", - "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "node_modules/vscode-css-languageservice": { + "version": "6.3.10", + "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-6.3.10.tgz", + "integrity": "sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==", "license": "MIT", "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.1" - }, - "engines": { - "node": ">=18.0.0" + "@vscode/l10n": "^0.0.18", + "vscode-languageserver-textdocument": "^1.0.12", + "vscode-languageserver-types": "3.17.5", + "vscode-uri": "^3.1.0" } }, - "node_modules/webpack-sources": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "node_modules/vscode-css-languageservice/node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/vscode-html-languageservice": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.6.2.tgz", + "integrity": "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==", "license": "MIT", - "engines": { - "node": ">=10.13.0" + "dependencies": { + "@vscode/l10n": "^0.0.18", + "vscode-languageserver-textdocument": "^1.0.12", + "vscode-languageserver-types": "^3.17.5", + "vscode-uri": "^3.1.0" } }, - "node_modules/webpackbar": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-6.0.1.tgz", - "integrity": "sha512-TnErZpmuKdwWBdMoexjio3KKX6ZtoKHRVvLIU0A47R0VVBDtx3ZyOJDktgYixhoJokZTYTt1Z37OkO9pnGJa9Q==", + "node_modules/vscode-json-languageservice": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.8.tgz", + "integrity": "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==", "license": "MIT", "dependencies": { - "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", - "consola": "^3.2.3", - "figures": "^3.2.0", - "markdown-table": "^2.0.0", - "pretty-time": "^1.1.0", - "std-env": "^3.7.0", - "wrap-ansi": "^7.0.0" + "jsonc-parser": "^3.0.0", + "vscode-languageserver-textdocument": "^1.0.1", + "vscode-languageserver-types": "^3.16.0", + "vscode-nls": "^5.0.0", + "vscode-uri": "^3.0.2" }, "engines": { - "node": ">=14.21.3" - }, - "peerDependencies": { - "webpack": "3 || 4 || 5" + "npm": ">=7.0.0" } }, - "node_modules/webpackbar/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/vscode-json-languageservice/node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.1.tgz", + "integrity": "sha512-rfuA6T75H6m5EkbhtEPzre9pT0HPcDI2MMy4+nPFIBks5J8JBAUHD4tRYSgaBOijIEC7SRkC1kKyXTLqbmh9jw==", "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=14.0.0" } }, - "node_modules/webpackbar/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "vscode-languageserver-protocol": "3.17.5" }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" } }, - "node_modules/webpackbar/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/webpackbar/node_modules/markdown-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", - "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "node_modules/vscode-languageserver-protocol": { + "version": "3.18.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.2.tgz", + "integrity": "sha512-XRyDbT0Pp3sSNti3JmxVEUMySWCSi1hhM+/KUlCy1hV1zmrqpM1OwO12EAki8blhmLuIMpaJrYbo0OzGVfK2Qg==", "license": "MIT", "dependencies": { - "repeat-string": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "vscode-jsonrpc": "9.0.1", + "vscode-languageserver-types": "3.18.0" } }, - "node_modules/webpackbar/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.0.tgz", + "integrity": "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g==", + "license": "MIT" + }, + "node_modules/vscode-languageserver/node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, "engines": { - "node": ">=8" + "node": ">=14.0.0" } }, - "node_modules/webpackbar/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/vscode-languageserver/node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" } }, - "node_modules/webpackbar/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/vscode-languageserver/node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/vscode-nls": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", + "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.20.tgz", + "integrity": "sha512-2sBz0x/wis5TkF1XZ2vH25zWq3G1bFEPOfkBcx2ikowmphoQsPH6X0V3mmPCXA2K1N/XGTnifVyDQP4GfDDeQw==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "has-flag": "^4.0.0" + "@vue/compiler-dom": "3.5.20", + "@vue/compiler-sfc": "3.5.20", + "@vue/runtime-dom": "3.5.20", + "@vue/server-renderer": "3.5.20", + "@vue/shared": "3.5.20" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/webpackbar/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/vue-router": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz", + "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" + "@vue/devtools-api": "^6.6.4" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" } }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "license": "Apache-2.0", + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=0.8.0" + "node": ">=18" } }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "license": "Apache-2.0", + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, "engines": { - "node": ">=0.8.0" + "node": ">=12" } }, "node_modules/whatwg-encoding": { @@ -26672,6 +19055,8 @@ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "iconv-lite": "0.6.3" }, @@ -26685,6 +19070,8 @@ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -26696,7 +19083,10 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=18" } @@ -26707,6 +19097,8 @@ "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" @@ -26730,6 +19122,16 @@ "node": ">= 8" } }, + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -26747,79 +19149,19 @@ "node": ">=8" } }, - "node_modules/widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", - "license": "MIT", - "dependencies": { - "string-width": "^5.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "license": "MIT" - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=10.0.0" }, @@ -26836,28 +19178,29 @@ } } }, - "node_modules/xdg-basedir": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", - "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "node_modules/xdg-app-paths": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/xdg-app-paths/-/xdg-app-paths-5.5.1.tgz", + "integrity": "sha512-hI3flOB4PLZIy5prbtTpirobtPE2ZtZ52szO+2mM9Efp6ErM398La+C1lIpNWDfNoQk+6Lsi6nMcCwVB7pxeMQ==", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "os-paths": "^4.0.1", + "xdg-portable": "^7.2.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 6.0" } }, - "node_modules/xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "node_modules/xdg-portable": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/xdg-portable/-/xdg-portable-7.3.0.tgz", + "integrity": "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==", "license": "MIT", "dependencies": { - "sax": "^1.2.4" + "os-paths": "^4.0.1" }, - "bin": { - "xml-js": "bin/cli.js" + "engines": { + "node": ">= 6.0" } }, "node_modules/xml-name-validator": { @@ -26866,6 +19209,8 @@ "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "engines": { "node": ">=18" } @@ -26875,8 +19220,25 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/xxhash-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", + "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", "license": "MIT" }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -26884,21 +19246,135 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yaml-language-server": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/yaml-language-server/-/yaml-language-server-1.23.0.tgz", + "integrity": "sha512-3qVyCOexLCWw06PQa5kRPwvMWMZ/eZeCRWUvgD6a0OkqL/4iCnxy2WumbWifa937Uo5xhyWJ0uxlU39ljhNh7A==", + "license": "MIT", + "dependencies": { + "@vscode/l10n": "^0.0.18", + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "ajv-i18n": "^4.2.0", + "prettier": "^3.8.1", + "request-light": "^0.5.7", + "vscode-json-languageservice": "4.1.8", + "vscode-languageserver": "^9.0.0", + "vscode-languageserver-textdocument": "^1.0.1", + "vscode-languageserver-types": "^3.16.0", + "vscode-uri": "^3.0.2", + "yaml": "2.8.3" + }, + "bin": { + "yaml-language-server": "bin/yaml-language-server" + } + }, + "node_modules/yaml-language-server/node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/yaml-language-server/node_modules/request-light": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.5.8.tgz", + "integrity": "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==", + "license": "MIT" + }, + "node_modules/yaml-language-server/node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz", + "integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==", + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^8.2.1", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yocto-queue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", "license": "MIT", "engines": { "node": ">=12.20" @@ -26907,24 +19383,53 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/zhead": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/zhead/-/zhead-2.2.4.tgz", - "integrity": "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==", + "node_modules/yocto-spinner": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-0.2.3.tgz", + "integrity": "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18.19" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", + "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, "funding": { - "url": "https://github.com/sponsors/harlan-zw" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/zod": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.5.tgz", - "integrity": "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/package.json b/package.json index e2bd1fc0e7..5063d0ca12 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,22 @@ { - "name": "v-3", + "name": "@supertokens/docs", "version": "0.0.0", "private": true, "scripts": { - "docusaurus": "docusaurus", + "dev": "blume dev", + "start": "blume dev", + "build": "npm run routes:manifest && blume build --strict", + "validate": "blume validate --strict", + "preview": "blume preview", + "serve": "blume preview", "lint:prettier": "prettier . --write", + "lint:prettier:check": "prettier . --check", "lint:vale": "vale", - "start": "docusaurus start --no-open --hot-only", - "build": "docusaurus build", - "swizzle": "docusaurus swizzle", - "deploy": "docusaurus deploy", - "clear": "docusaurus clear", - "serve": "docusaurus serve", - "write-translations": "docusaurus write-translations", - "write-heading-ids": "docusaurus write-heading-ids", - "typecheck": "tsc", + "typecheck": "blume check", + "routes:manifest": "node scripts/blume/create-route-manifest.mjs", "write-code-blocks": "bun run ./scripts/write-code-blocks.ts", "format-code-blocks": "bun run ./scripts/format-code-blocks.ts", "check-code-blocks": "./scripts/check-code-blocks.sh", - "ai": "bun run scripts/ai.ts", - "search:update": "bun run scripts/search/index.ts", "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", @@ -28,90 +25,36 @@ "generate:references:typescript": "bun run ./scripts/sdk-references/typescript-references.ts" }, "dependencies": { - "@algolia/client-search": "^5.29.0", - "@amplitude/analytics-browser": "^2.11.11", - "@amplitude/plugin-session-replay-browser": "^1.13.9", - "@docsearch/react": "^3.6.2", - "@docusaurus/core": "^3.8.1", - "@docusaurus/plugin-client-redirects": "^3.8.1", - "@docusaurus/plugin-debug": "^3.8.1", - "@docusaurus/preset-classic": "^3.8.1", - "@docusaurus/theme-search-algolia": "^3.8.1", - "@mdx-js/react": "^3.0.0", - "@radix-ui/react-accordion": "^1.2.2", - "@radix-ui/react-form": "^0.1.0", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/themes": "^3.1.6", - "@scalar/api-client": "^2.5.22", - "@scalar/api-client-react": "^1.3.27", - "@scalar/api-reference-react": "^0.7.38", - "@scalar/openapi-parser": "^0.10.14", - "@scalar/openapi-types": "^0.2.0", - "axios": "^1.7.9", - "class-variance-authority": "^0.7.1", - "clsx": "^2.0.0", - "docusaurus-plugin-sass": "^0.2.5", - "dotenv": "^16.4.5", - "js-cookie": "^3.0.5", - "lucide-react": "^0.534.0", - "motion": "^11.13.1", - "prism-react-renderer": "^2.4.1", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "react-markdown": "^10.1.0", - "sass": "^1.80.6", - "search-insights": "^2.17.3", - "supertokens-website": "^20.1.5", - "tailwind-merge": "^2.5.5", - "uuid": "^11.0.3", - "zod": "^4.0.17" + "@vercel/microfrontends": "^2.4.0", + "blume": "1.2.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" }, "devDependencies": { - "@docusaurus/faster": "^3.8.1", - "@docusaurus/module-type-aliases": "^3.8.1", - "@docusaurus/tsconfig": "^3.8.1", - "@docusaurus/types": "^3.8.1", - "@testing-library/jest-dom": "^6.6.3", - "@testing-library/react": "^16.2.0", - "@testing-library/user-event": "^14.6.1", + "@mdx-js/mdx": "^3.1.0", "@types/bun": "^1.2.9", "@types/fs-extra": "^11.0.4", - "@vitejs/plugin-react": "^4.3.4", - "algoliasearch": "^5.32.0", - "chalk": "^5.4.1", + "@types/node": "^22.10.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", "fs-extra": "^11.2.0", + "glob": "^11.0.0", "js-yaml": "^4.1.0", - "jsdom": "^26.0.0", - "ora": "^8.2.0", "prettier": "3.3.3", "tree-sitter": "^0.21.0", "tree-sitter-go": "^0.21.2", "tree-sitter-python": "^0.21.0", "tree-sitter-typescript": "^0.21.2", - "typedoc": "^0.28.12", + "typedoc": "^0.28.20", "typedoc-plugin-frontmatter": "^1.3.0", "typedoc-plugin-inline-sources": "^1.3.0", "typedoc-plugin-markdown": "^4.8.1", "typedoc-plugin-mdn-links": "^5.0.9", - "typedoc-plugin-merge-modules": "^7.0.0", - "typedoc-plugin-missing-exports": "^4.1.0", - "typescript": "~5.6.2", - "vitest": "^3.0.9", - "ws": "^8.18.0" - }, - "browserslist": { - "production": [ - ">0.5%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 3 chrome version", - "last 3 firefox version", - "last 5 safari version" - ] + "typescript": "^6.0.3", + "unist-util-visit": "^5.0.0", + "vitest": "^4.0.0" }, "engines": { - "node": ">=18.0" + "node": ">=22.12.0" } } diff --git a/static/.nojekyll b/public/.nojekyll similarity index 100% rename from static/.nojekyll rename to public/.nojekyll diff --git a/static/cdi-file-paths.json b/public/cdi-file-paths.json similarity index 100% rename from static/cdi-file-paths.json rename to public/cdi-file-paths.json diff --git a/static/cdi-mapping.json b/public/cdi-mapping.json similarity index 100% rename from static/cdi-mapping.json rename to public/cdi-mapping.json diff --git a/static/cdi.json b/public/cdi.json similarity index 100% rename from static/cdi.json rename to public/cdi.json diff --git a/public/cdi.yml b/public/cdi.yml new file mode 100644 index 0000000000..3ec100562e --- /dev/null +++ b/public/cdi.yml @@ -0,0 +1,10747 @@ +openapi: 3.0.0 +info: + description: | + This is the API exposed by the SuperTokens Core. To be consumed by your backend only. + + `appid-{appId}` and `{tenantId}` in all the APIs are optional. Their default values are `appid-public` and `public` respectively. + + Those that do not have `{tenantId}` in the path will enforce that the API is called from `public` tenant only. + + version: 5.1.1 + title: Core Driver Interface + contact: + email: support@supertokens.io +tags: + - name: EmailPassword Recipe + - name: ThirdParty Recipe + - name: Passwordless Recipe + - name: EmailVerification Recipe + - name: User Metadata Recipe + - name: User Roles Recipe + - name: UserIdMapping Recipe + - name: Session Recipe + - name: Multitenancy Recipe + - name: Core + - name: Dashboard Recipe + - name: Totp Recipe + - name: Account Linking Recipe + - name: WebAuthn Recipe + - name: JWT Recipe + - name: Bulk Import + +paths: + /appid-{appId}/recipe/accountlinking/user/primary/check: + get: + tags: + - Account Linking Recipe + operationId: canCreatePrimaryUser + summary: Check primary user creation possibility + description: | + Check if primary user can be created for given user id + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/accountLinkingRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: recipeUserId + schema: + type: string + description: The recipe user ID to check + example: fa7a0841-b533-4478-9253-0fde890c576 + required: true + responses: + "200": + description: Indicates success with the status and canCreatePrimaryUser properties + content: + application/json: + schema: + oneOf: + - type: object + title: Primary User Check Success + description: Response when user can be created as primary + properties: + status: + $ref: "#/components/schemas/statusOK" + wasAlreadyAPrimaryUser: + type: boolean + description: Indicates if the user was already a primary user + example: true + - type: object + title: Account Info Already Associated Error + description: Response when account info is already associated with another primary user + properties: + status: + type: string + enum: ["ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"] + primaryUserId: + type: string + description: The ID of the primary user that already has this account info + example: fa7a0841-b533-4478-9253-0fde890c576 + description: + type: string + description: Error description + - type: object + title: Recipe User Already Linked Error + description: Response when recipe user is already linked with a primary user + properties: + status: + type: string + enum: ["RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR"] + primaryUserId: + type: string + description: The ID of the primary user this recipe user is already linked to + example: fa7a0841-b533-4478-9253-0fde890c576 + description: + type: string + description: Error description + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/accountlinking/user/link/check: + get: + tags: + - Account Linking Recipe + operationId: canLinkAccounts + summary: Check account linking possibility + description: | + Check if accounts can be linked for given primary and recipe user id + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/accountLinkingRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: primaryUserId + schema: + type: string + description: The primary user ID to check + example: fa7a0841-b533-4478-9253-0fde890c576 + required: true + - in: query + name: recipeUserId + schema: + type: string + description: The recipe user ID to check + example: fa7a0841-b533-4478-9253-0fde890c576 + required: true + responses: + "200": + description: Indicates success with the status prop + content: + application/json: + schema: + oneOf: + - type: object + title: Account Linking Check Success + description: Response when accounts can be linked + properties: + status: + $ref: "#/components/schemas/statusOK" + accountsAlreadyLinked: + type: boolean + description: Indicates if accounts are already linked + example: true + - type: object + title: Account Info Already Associated Error + description: Response when account info is already associated with another primary user + properties: + status: + type: string + enum: ["ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"] + primaryUserId: + type: string + description: The ID of the primary user that already has this account info + example: fa7a0841-b533-4478-9253-0fde890c576 + description: + type: string + description: Error description + - type: object + title: Recipe User Already Linked Error + description: Response when recipe user is already linked with another primary user + properties: + status: + type: string + enum: ["RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"] + primaryUserId: + type: string + description: The ID of the primary user this recipe user is already linked to + example: fa7a0841-b533-4478-9253-0fde890c576 + description: + type: string + description: Error description + - type: object + title: Not Primary User Error + description: Response when input user is not a primary user + properties: + status: + type: string + enum: ["INPUT_USER_IS_NOT_A_PRIMARY_USER"] + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/accountlinking/user/primary: + post: + tags: + - Account Linking Recipe + operationId: createPrimaryUser + summary: Create primary user account + description: | + Create a primary user for given user id + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/accountLinkingRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + recipeUserId: + type: string + description: The recipe user ID to create as primary user + example: fa7a0841-b533-4478-9253-0fde890c576 + required: + - recipeUserId + responses: + "200": + description: Indicates success with the status and primaryUserId properties + content: + application/json: + schema: + oneOf: + - type: object + title: Primary User Creation Success + description: Response when primary user is created successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + wasAlreadyAPrimaryUser: + type: boolean + description: Indicates if the user was already a primary user + example: true + user: + $ref: "#/components/schemas/authRecipeUser" + - type: object + title: Account Info Already Associated Error + description: Response when account info is already associated with another primary user + properties: + status: + type: string + enum: ["ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"] + primaryUserId: + type: string + description: The ID of the primary user that already has this account info + example: fa7a0841-b533-4478-9253-0fde890c576 + description: + type: string + description: Error description + - type: object + title: Recipe User Already Linked Error + description: Response when recipe user is already linked with a primary user + properties: + status: + type: string + enum: ["RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR"] + primaryUserId: + type: string + description: The ID of the primary user this recipe user is already linked to + example: fa7a0841-b533-4478-9253-0fde890c576 + description: + type: string + description: Error description + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/accountlinking/user/link: + post: + tags: + - Account Linking Recipe + operationId: linkAccounts + summary: Link user accounts together + description: | + Link accounts for given primary and recipe user id + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/accountLinkingRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + primaryUserId: + type: string + description: The primary user ID to link with + example: fa7a0841-b533-4478-9253-0fde890c576 + recipeUserId: + type: string + description: The recipe user ID to link + example: fa7a0841-b533-4478-9253-0fde890c576 + required: + - primaryUserId + - recipeUserId + responses: + "200": + description: Indicates success with the status and accountsAlreadyLinked properties + content: + application/json: + schema: + oneOf: + - type: object + title: Account Linking Success + description: Response when accounts are linked successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + accountsAlreadyLinked: + type: boolean + description: Indicates if accounts were already linked + example: true + user: + $ref: "#/components/schemas/authRecipeUser" + - type: object + title: Account Info Already Associated Error + description: Response when account info is already associated with another primary user + properties: + status: + type: string + enum: ["ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"] + primaryUserId: + type: string + description: The ID of the primary user that already has this account info + example: fa7a0841-b533-4478-9253-0fde890c576 + description: + type: string + description: Error description + - type: object + title: Recipe User Already Linked Error + description: Response when recipe user is already linked with another primary user + properties: + status: + type: string + enum: ["RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"] + primaryUserId: + type: string + description: The ID of the primary user this recipe user is already linked to + example: fa7a0841-b533-4478-9253-0fde890c576 + user: + $ref: "#/components/schemas/authRecipeUser" + description: + type: string + description: Error description + - type: object + title: Not Primary User Error + description: Response when input user is not a primary user + properties: + status: + type: string + enum: ["INPUT_USER_IS_NOT_A_PRIMARY_USER"] + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/accountlinking/user/unlink: + post: + tags: + - Account Linking Recipe + operationId: unlinkAccounts + summary: Unlink user accounts + description: | + Unlink accounts for given recipe user id + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/accountLinkingRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + recipeUserId: + type: string + description: The recipe user ID to unlink + example: fa7a0841-b533-4478-9253-0fde890c576 + required: + - recipeUserId + responses: + "200": + description: Indicates success with the status and accountsUnlinked properties + content: + application/json: + schema: + oneOf: + - type: object + title: Account Unlinking Success + description: Response when accounts are unlinked successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + wasRecipeUserDeleted: + type: boolean + description: Indicates if the recipe user was deleted + example: true + wasLinked: + type: boolean + description: Indicates if the accounts were linked + example: true + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/totp/device: + post: + tags: + - Totp Recipe + operationId: createTotpDevice + summary: Add TOTP device for user + description: | + Add a TOTP device for a user and enable TOTP if not already enabled. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + deviceName: + type: string + description: Name of the TOTP device + example: "My Authy App" + skew: + type: number + description: Time skew in seconds for TOTP validation + example: 0 + period: + type: number + description: Time period in seconds for TOTP code generation + example: 30 + required: + - userId + - skew + - period + responses: + "200": + description: Indicates success with the status and secret properties + content: + application/json: + schema: + oneOf: + - type: object + title: TOTP Device Creation Success + description: Response when TOTP device is created successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + secret: + type: string + description: The TOTP secret key for the device + example: "JBSWY3DPEHPK3PXP" + deviceName: + type: string + description: Name of the created TOTP device + example: d1 + - type: object + title: Device Already Exists Error + description: Response when TOTP device already exists + properties: + status: + type: string + enum: ["DEVICE_ALREADY_EXISTS_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + put: + tags: + - Totp Recipe + operationId: updateTotpDeviceName + summary: Update TOTP device name + description: | + Update the name of a TOTP device for a user. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + existingDeviceName: + type: string + description: Current name of the TOTP device + example: "My Authy App" + newDeviceName: + type: string + description: New name for the TOTP device + example: "A better name for my TOTP device" + required: + - userId + - existingDeviceName + - newDeviceName + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + title: Device Name Update Success + description: Response when TOTP device name is updated successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + - type: object + title: Unknown Device Error + description: Response when TOTP device is not found + properties: + status: + type: string + enum: ["UNKNOWN_DEVICE_ERROR"] + - type: object + title: Device Already Exists Error + description: Response when new device name already exists + properties: + status: + type: string + enum: ["DEVICE_ALREADY_EXISTS_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/totp/device/list: + get: + tags: + - Totp Recipe + operationId: getTotpDevices + summary: List user TOTP devices + description: | + Retrieve a list of TOTP devices for a user. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: userId + schema: + type: string + description: The user ID to get TOTP devices for + required: true + responses: + "200": + description: Retrives all TOTP devices + content: + application/json: + schema: + oneOf: + - type: object + title: TOTP Devices List + description: Response containing list of TOTP devices + properties: + status: + $ref: "#/components/schemas/statusOK" + devices: + type: array + description: List of TOTP devices + items: + type: object + properties: + name: + type: string + description: Name of the TOTP device + period: + type: number + description: Time period in seconds for TOTP code generation + skew: + type: number + description: Time skew in seconds for TOTP validation + verified: + type: boolean + description: Whether the device has been verified + required: + - status + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /recipe/totp/device/import: + post: + tags: + - Totp Recipe + operationId: importTotpDevice + summary: Import existing TOTP device + description: | + Add a TOTP device for a user and enable TOTP if not already enabled. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + deviceName: + type: string + description: Name of the TOTP device + example: "My Authy App" + skew: + type: number + description: Time skew in seconds for TOTP validation + example: 0 + period: + type: number + description: Time period in seconds for TOTP code generation + example: 30 + secretKey: + type: string + description: The TOTP secret key for the device + example: "BSWY3DPEMOWNFUWJLDIWNDNDPONBIUFG" + required: + - userId + - skew + - period + - secretKey + responses: + "200": + description: Indicates success with the status and secret properties + content: + application/json: + schema: + oneOf: + - type: object + title: TOTP Device Import Success + description: Response when TOTP device is imported successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + deviceName: + type: string + description: Name of the imported TOTP device + example: d1 + - type: object + title: Device Already Exists Error + description: Response when TOTP device already exists + properties: + status: + type: string + enum: ["DEVICE_ALREADY_EXISTS_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/totp/device/remove: + post: + tags: + - Totp Recipe + operationId: removeTotpDevice + summary: Remove TOTP device + description: | + Remove a TOTP device for a user. If all devices are removed, TOTP is disabled for the user. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + deviceName: + type: string + description: Name of the TOTP device to remove + example: "My Authy App" + required: + - userId + - deviceName + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + title: TOTP Device Removal Success + description: Response when TOTP device is removed successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + didDeviceExist: + type: boolean + description: Indicates if the device existed before removal + example: true + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/totp/verify: + post: + tags: + - Totp Recipe + operationId: verifyTotpCode + summary: Verify TOTP code + description: | + Check if a TOTP code is valid against any of the TOTP devices for a user. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + totp: + type: string + description: The TOTP code to verify + example: "123456" + allowUnverifiedDevices: + type: boolean + description: Whether to allow verification against unverified devices + example: false + required: + - userId + - totp + - allowUnverifiedDevices + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + title: TOTP Verification Success + description: Response when TOTP code is valid + properties: + status: + $ref: "#/components/schemas/statusOK" + - type: object + title: Invalid TOTP Error + description: Response when TOTP code is invalid + properties: + status: + type: string + enum: ["INVALID_TOTP_ERROR"] + currentNumberOfFailedAttempts: + type: number + description: Current number of failed verification attempts + example: 2 + maxNumberOfFailedAttempts: + type: number + description: Maximum allowed failed verification attempts + example: 5 + - type: object + title: Unknown User Error + description: Response when user ID is not found + properties: + status: + type: string + enum: ["UNKNOWN_USER_ID_ERROR"] + - type: object + title: Rate Limit Error + description: Response when rate limit is reached + properties: + status: + type: string + enum: ["LIMIT_REACHED_ERROR"] + retryAfterMs: + type: number + description: Time in milliseconds to wait before retrying + example: 90000 + currentNumberOfFailedAttempts: + type: number + description: Current number of failed verification attempts + example: 2 + maxNumberOfFailedAttempts: + type: number + description: Maximum allowed failed verification attempts + example: 5 + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/totp/device/verify: + post: + tags: + - Totp Recipe + operationId: verifyTotpDevice + summary: Verify TOTP device + description: | + Mark a TOTP device as verified if the given TOTP code is valid for that device. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + deviceName: + type: string + description: Name of the TOTP device to verify + example: "My Authy App" + totp: + type: string + description: The TOTP code to verify + example: "123456" + required: + - userId + - deviceName + - totp + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + title: Device Verification Success + description: Response when TOTP device is verified successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + wasAlreadyVerified: + type: boolean + description: Indicates if the device was already verified + example: false + - type: object + title: Unknown Device Error + description: Response when TOTP device is not found + properties: + status: + type: string + enum: ["UNKNOWN_DEVICE_ERROR"] + - type: object + title: Invalid TOTP Error + description: Response when TOTP code is invalid + properties: + status: + type: string + enum: ["INVALID_TOTP_ERROR"] + currentNumberOfFailedAttempts: + type: number + description: Current number of failed verification attempts + example: 2 + maxNumberOfFailedAttempts: + type: number + description: Maximum allowed failed verification attempts + example: 5 + - type: object + title: Rate Limit Error + description: Response when rate limit is reached + properties: + status: + type: string + enum: ["LIMIT_REACHED_ERROR"] + retryAfterMs: + type: number + description: Time in milliseconds to wait before retrying + example: 90000 + currentNumberOfFailedAttempts: + type: number + description: Current number of failed verification attempts + example: 2 + maxNumberOfFailedAttempts: + type: number + description: Maximum allowed failed verification attempts + example: 5 + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/userid/map: + post: + tags: + - UserIdMapping Recipe + operationId: userIdMappingCreateMapping + summary: Create user ID mapping + description: | + Create a mapping between a SuperTokens userId and an external userId. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userIdMappingRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + superTokensUserId: + $ref: "#/components/schemas/userId" + externalUserId: + type: string + description: The external user ID to map to + example: "externalId" + externalUserIdInfo: + type: string + description: Additional information about the external user ID + example: "Info about external userId" + force: + type: boolean + description: Whether to force create the mapping even if it exists + required: + - superTokensUserId + - externalUserId + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + + - type: object + properties: + status: + type: string + enum: ["UNKNOWN_SUPERTOKENS_USER_ID_ERROR"] + + - type: object + properties: + status: + type: string + enum: ["USER_ID_MAPPING_ALREADY_EXISTS_ERROR"] + doesSuperTokensUserIdExist: + type: boolean + doesExternalUserIdExist: + type: boolean + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + get: + tags: + - UserIdMapping Recipe + operationId: userIdMappingGetMapping + summary: Get user ID mapping + description: | + Retrieve a UserIdMapping + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userIdMappingRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: userId + schema: + type: string + description: The user ID to get mapping for + required: true + - in: query + name: userIdType + schema: + type: string + description: Type of user ID to search for + enum: ["SUPERTOKENS", "EXTERNAL", "ANY"] + responses: + "200": + description: Retrives a userId mapping + content: + application/json: + schema: + oneOf: + - type: object + title: User ID Mapping Found + description: Response containing the user ID mapping + properties: + status: + $ref: "#/components/schemas/statusOK" + superTokensUserId: + $ref: "#/components/schemas/userId" + externalUserId: + type: string + description: The external user ID + example: "externalId" + externalUserIdInfo: + type: string + description: Additional information about the external user ID + example: "Info about external userId" + required: + - status + - superTokensUserId + - externalUserId + - type: object + title: Unknown Mapping Error + description: Response when user ID mapping is not found + properties: + status: + type: string + enum: ["UNKNOWN_MAPPING_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/userid/map/remove: + post: + tags: + - UserIdMapping Recipe + operationId: userIdMappingRemoveMapping + summary: Remove user ID mapping + description: | + Delete a mapping between a SuperTokens userId and an external userId. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userIdMappingRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + userIdType: + type: string + description: Type of user ID to remove mapping for + enum: ["SUPERTOKENS", "EXTERNAL", "ANY"] + force: + type: boolean + description: Whether to force remove the mapping + required: + - userId + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + type: object + title: User ID Mapping Removal Success + description: Response when user ID mapping is removed successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + didMappingExist: + type: boolean + description: Indicates if the mapping existed before removal + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/userid/external-user-id-info: + put: + tags: + - UserIdMapping Recipe + operationId: userIdMappingUpateExternalUserIdInfo + summary: Update external user info + description: | + Update or delete externalUserIdInfo + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userIdMappingRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + userIdType: + type: string + description: Type of user ID to update info for + enum: ["SUPERTOKENS", "EXTERNAL", "ANY"] + externalUserIdInfo: + type: string + description: New external user ID information + example: "new external userId info" + nullable: true + required: + - userId + - externalUserIdInfo + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + title: External User Info Update Success + description: Response when external user info is updated successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + - type: object + title: Unknown Mapping Error + description: Response when user ID mapping is not found + properties: + status: + type: string + enum: ["UNKNOWN_MAPPING_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/signinup/code/check: + post: + tags: + - Passwordless Recipe + operationId: passwordlessCheckCode + summary: Check passwordless code + description: | + Tries to check if the passed userInputCode+deviceId combo or the linkCode is valid + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + title: Link Code Check + description: Request to check a link code + properties: + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + linkCode: + $ref: "#/components/schemas/linkCode" + required: + - preAuthSessionId + - linkCode + - type: object + title: User Input Code Check + description: Request to check a user input code + properties: + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + deviceId: + $ref: "#/components/schemas/deviceId" + userInputCode: + $ref: "#/components/schemas/userInputCode" + required: + - preAuthSessionId + - deviceId + - userInputCode + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + title: Code Check Success + description: Response when code is valid + properties: + status: + $ref: "#/components/schemas/statusOK" + consumedDevice: + type: object + description: Information about the consumed device + required: + - preAuthSessionId + - failedCodeInputAttemptCount + properties: + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + failedCodeInputAttemptCount: + type: number + description: Number of failed code input attempts + example: 2 + email: + $ref: "#/components/schemas/email" + phoneNumber: + $ref: "#/components/schemas/phoneNumber" + - type: object + title: Invalid Code Error + description: Response when code is invalid or expired + properties: + status: + type: string + enum: ["INCORRECT_USER_INPUT_CODE_ERROR", "EXPIRED_USER_INPUT_CODE_ERROR"] + failedCodeInputAttemptCount: + type: number + description: Number of failed code input attempts + example: 2 + maximumCodeInputAttempts: + type: number + description: Maximum allowed code input attempts + example: 5 + - type: object + title: Restart Flow Error + description: Response when flow needs to be restarted + properties: + status: + type: string + enum: ["RESTART_FLOW_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/signinup/code/consume: + post: + tags: + - Passwordless Recipe + operationId: passwordlessTryUseCode + summary: Consume passwordless code + description: | + Tries to consume the passed userInputCode+deviceId combo or the linkCode to sign the user in + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + title: Link Code Consume + description: Request to consume a link code + properties: + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + linkCode: + $ref: "#/components/schemas/linkCode" + required: + - preAuthSessionId + - linkCode + - type: object + title: User Input Code Consume + description: Request to consume a user input code + properties: + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + deviceId: + $ref: "#/components/schemas/deviceId" + userInputCode: + $ref: "#/components/schemas/userInputCode" + required: + - preAuthSessionId + - deviceId + - userInputCode + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + title: Code Consume Success + description: Response when code is consumed successfully + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNewUser: + type: boolean + description: Indicates if a new user was created + example: true + user: + $ref: "#/components/schemas/authRecipeUser" + recipeUserId: + $ref: "#/components/schemas/userId" + consumedDevice: + type: object + description: Information about the consumed device + required: + - preAuthSessionId + - failedCodeInputAttemptCount + properties: + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + failedCodeInputAttemptCount: + type: number + description: Number of failed code input attempts + example: 2 + email: + $ref: "#/components/schemas/email" + phoneNumber: + $ref: "#/components/schemas/phoneNumber" + - type: object + title: Invalid Code Error + description: Response when code is invalid or expired + properties: + status: + type: string + enum: ["INCORRECT_USER_INPUT_CODE_ERROR", "EXPIRED_USER_INPUT_CODE_ERROR"] + failedCodeInputAttemptCount: + type: number + description: Number of failed code input attempts + example: 2 + maximumCodeInputAttempts: + type: number + description: Maximum allowed code input attempts + example: 5 + - type: object + title: Restart Flow Error + description: Response when flow needs to be restarted + properties: + status: + type: string + enum: ["RESTART_FLOW_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/signinup/code: + post: + tags: + - Passwordless Recipe + operationId: passwordlessStartSignIn + summary: Start passwordless sign in + description: | + Starts a sign in process by requesting a linkCode and a deviceId + userInputCode combination the user can use to sign in. + Passing the optional deviceId signifies a resend code flow. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + title: Email Sign In + description: Request to start email-based sign in + properties: + email: + $ref: "#/components/schemas/email" + userInputCode: + $ref: "#/components/schemas/userInputCode" + example: + email: "test@example.com" + required: + - email + - type: object + title: Phone Sign In + description: Request to start phone-based sign in + properties: + phoneNumber: + $ref: "#/components/schemas/phoneNumber" + userInputCode: + $ref: "#/components/schemas/userInputCode" + required: + - phoneNumber + - type: object + title: Resend Code + description: Request to resend code to existing device + properties: + deviceId: + $ref: "#/components/schemas/deviceId" + userInputCode: + $ref: "#/components/schemas/userInputCode" + required: + - deviceId + responses: + "200": + description: Starts the passwordless login process + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + + codeId: + $ref: "#/components/schemas/codeId" + + deviceId: + $ref: "#/components/schemas/deviceId" + + userInputCode: + $ref: "#/components/schemas/userInputCode" + + linkCode: + $ref: "#/components/schemas/linkCode" + + timeCreated: + $ref: "#/components/schemas/timeCreated" + + codeLifetime: + $ref: "#/components/schemas/codeLifetime" + - type: object + properties: + status: + type: string + enum: ["RESTART_FLOW_ERROR", "USER_INPUT_CODE_ALREADY_USED_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/signinup/code/remove: + post: + tags: + - Passwordless Recipe + operationId: passwordlessRevokeCode + summary: Revoke passwordless code + description: | + Revokes a code by id + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + properties: + codeId: + $ref: "#/components/schemas/codeId" + required: + - codeId + - type: object + properties: + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + required: + - preAuthSessionId + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/signinup/codes: + get: + tags: + - Passwordless Recipe + operationId: passwordlessListCodes + summary: List passwordless codes + description: | + Lists all active passwordless codes of the user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: email + description: Use this parameter to get information about all devices associated with an email (without the other query params) + schema: + type: string + - in: query + name: phoneNumber + description: Use this parameter to get information about all devices associated with a phoneNumber (without the other query params) + schema: + $ref: "#/components/schemas/phoneNumber" + - in: query + name: deviceId + description: Use this parameter to get information about a single device (without the other query params) + schema: + $ref: "#/components/schemas/deviceId" + - in: query + name: preAuthSessionId + description: Use this parameter to get information about a single device (without the other query params) + schema: + $ref: "#/components/schemas/preAuthSessionId" + responses: + "200": + description: List of all active passwordless codes of the user + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + devices: + type: array + items: + type: object + properties: + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + failedCodeInputAttemptCount: + type: number + example: 2 + email: + $ref: "#/components/schemas/email" + phoneNumber: + $ref: "#/components/schemas/phoneNumber" + codes: + type: array + items: + type: object + properties: + codeId: + $ref: "#/components/schemas/codeId" + timeCreated: + $ref: "#/components/schemas/timeCreated" + codeLifetime: + $ref: "#/components/schemas/codeLifetime" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/signinup/codes/remove: + post: + tags: + - Passwordless Recipe + operationId: passwordlessRevokeAllCodesOfUser + summary: Revoke all user codes + description: | + Revokes all codes issued for the user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + properties: + email: + $ref: "#/components/schemas/email" + required: + - email + - type: object + properties: + phoneNumber: + $ref: "#/components/schemas/phoneNumber" + required: + - phoneNumber + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user ⠀: + get: + tags: + - Passwordless Recipe + operationId: passwordlessGetUser + summary: Get passwordless user + deprecated: true + description: | + Get a user's information. + + API is tenant specific if querying by email or phone number. + If querying by userId, tenantId will be ignored. + + Note that there is an invisible character at the end of the path, this was to avoid a conflict with the OpenAPI spec. + + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/userId" + - in: query + name: email + description: Use exactly one of phoneNumber, email or userId + schema: + $ref: "#/components/schemas/email" + - in: query + name: phoneNumber + description: Use exactly one of phoneNumber, email or userId + schema: + $ref: "#/components/schemas/phoneNumber" + responses: + "200": + description: Get a user's information. + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/authRecipeUser" + - type: object + properties: + status: + type: string + enum: ["UNKNOWN_USER_ID_ERROR", "UNKNOWN_EMAIL_ERROR", "UNKNOWN_PHONE_NUMBER_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + put: + tags: + - Passwordless Recipe + operationId: passwordlessPutUser + summary: Update passwordless user + description: | + Update a user's information. + If the email or phoneNumber is set to null the previous value will be deleted. If they are not set (i.e., undefined/missing from the request), they are left as-is. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + recipeUserId: + $ref: "#/components/schemas/userId" + email: + type: string + example: johndoe@gmail.com + nullable: true + phoneNumber: + type: string + example: "+14155552671" + nullable: true + required: + - userId + + responses: + "200": + description: update user's information + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + type: string + enum: + [ + "OK", + "UNKNOWN_USER_ID_ERROR", + "EMAIL_ALREADY_EXISTS_ERROR", + "PHONE_NUMBER_ALREADY_EXISTS_ERROR", + ] + - type: object + properties: + status: + type: string + enum: ["EMAIL_CHANGE_NOT_ALLOWED_ERROR", "PHONE_NUMBER_CHANGE_NOT_ALLOWED_ERROR"] + reason: + type: string + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/signin: + post: + tags: + - EmailPassword Recipe + operationId: emailPasswordSignin + summary: Sign in user + description: | + Signin a user with email ID and password + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/rid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + $ref: "#/components/schemas/email" + password: + $ref: "#/components/schemas/password" + responses: + "200": + description: signin response + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/authRecipeUser" + recipeUserId: + $ref: "#/components/schemas/userId" + + - $ref: "#/components/schemas/wrongCredentialsResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/signup: + post: + tags: + - EmailPassword Recipe + operationId: emailPasswordSignup + summary: Sign up user + description: | + Signup a user with email ID and password + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/rid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + $ref: "#/components/schemas/email" + password: + $ref: "#/components/schemas/password" + responses: + "200": + description: signup response + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/authRecipeUser" + recipeUserId: + $ref: "#/components/schemas/userId" + - type: object + properties: + status: + type: string + enum: ["EMAIL_ALREADY_EXISTS_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user: + get: + tags: + - EmailPassword Recipe + operationId: emailPasswordGetUser + summary: Get email password user + deprecated: true + description: | + Get a user's information + + API is tenant specific if querying by email. + If querying by userId, tenantId will be ignored. + + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/rid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: email + description: use either email or userId, not both + schema: + $ref: "#/components/schemas/email" + - in: query + name: userId + description: use either email or userId, not both + schema: + $ref: "#/components/schemas/userId" + + responses: + "200": + description: get user's information + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/authRecipeUser" + - type: object + properties: + status: + type: string + enum: ["UNKNOWN_USER_ID_ERROR", "UNKNOWN_EMAIL_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + put: + tags: + - EmailPassword Recipe + operationId: emailPasswordPutUser + summary: Update user info + description: | + Update a user's information + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/rid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + recipeUserId: + $ref: "#/components/schemas/userId" + email: + $ref: "#/components/schemas/email" + password: + $ref: "#/components/schemas/password" + + responses: + "200": + description: update user's information + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + type: string + enum: ["OK", "UNKNOWN_USER_ID_ERROR", "EMAIL_ALREADY_EXISTS_ERROR"] + - type: object + properties: + status: + type: string + enum: ["EMAIL_CHANGE_NOT_ALLOWED_ERROR"] + reason: + type: string + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user/password/reset/token: + post: + tags: + - EmailPassword Recipe + operationId: emailPasswordGetPasswordResetToken + summary: Generate password reset token + description: | + Generate a new reset password token for this user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/rid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - userId + - email + properties: + userId: + $ref: "#/components/schemas/userId" + email: + $ref: "#/components/schemas/email" + responses: + "200": + description: Generate a new reset password token for this user + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + token: + $ref: "#/components/schemas/token" + - $ref: "#/components/schemas/unknownUserIdResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user/password/reset: + post: + tags: + - EmailPassword Recipe + operationId: emailPasswordGetPasswordReset + summary: Reset user password + deprecated: true + description: | + Reset a password using password reset token + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/rid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + method: + type: string + enum: + - token + token: + $ref: "#/components/schemas/token" + newPassword: + type: string + example: newpassword123 + responses: + "200": + description: Reset a password using password reset token + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + userId: + $ref: "#/components/schemas/userId" + - type: object + properties: + status: + type: string + enum: ["RESET_PASSWORD_INVALID_TOKEN_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user/passwordhash/import: + post: + tags: + - EmailPassword Recipe + operationId: userImport + summary: Import user with hash + description: | + Import a user with email ID and password hash + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/rid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + $ref: "#/components/schemas/email" + passwordHash: + $ref: "#/components/schemas/passwordHash" + hashingAlgorithm: + type: string + enum: ["argon2", "bcrypt", "firebase_scrypt"] + + responses: + "200": + description: import user response + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/authRecipeUser" + didUserAlreadyExist: + type: boolean + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user/password/reset/token/consume: + post: + tags: + - EmailPassword Recipe + operationId: emailPasswordResetPasswordConsumeToken + summary: Consume password reset token + description: | + Consume a password reset token + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/rid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + token: + $ref: "#/components/schemas/token" + responses: + "200": + description: Consume a password reset token + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + userId: + $ref: "#/components/schemas/userId" + email: + $ref: "#/components/schemas/email" + - type: object + properties: + status: + type: string + enum: ["RESET_PASSWORD_INVALID_TOKEN_ERROR"] + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/signinup: + post: + tags: + - ThirdParty Recipe + operationId: thirdPartySigninup + summary: Sign in/up third party user + description: | + Signin/up a user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/thirdPartyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + thirdPartyId: + $ref: "#/components/schemas/thirdPartyId" + thirdPartyUserId: + $ref: "#/components/schemas/thirdPartyUserId" + email: + $ref: "#/components/schemas/thirdPartyEmail" + responses: + "200": + description: Signin/up a user + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNewUser: + type: boolean + example: true + user: + $ref: "#/components/schemas/authRecipeUser" + recipeUserId: + $ref: "#/components/schemas/userId" + - type: object + properties: + status: + type: string + enum: ["EMAIL_CHANGE_NOT_ALLOWED_ERROR"] + reason: + type: string + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user⠀: + get: + tags: + - ThirdParty Recipe + operationId: thirdPartyGetUser + summary: Get third party user + deprecated: true + description: | + Get a user's information. + + API is tenant specific if querying by email. + If querying by userId, tenantId will be ignored. + + Note that there is an invisible character at the end of the path, this was to avoid a conflict with the OpenAPI spec. + + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/thirdPartyRid" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/userId" + - in: query + name: thirdPartyId + description: Either use userId or thirdPartyId and thirdPartyUserId + schema: + $ref: "#/components/schemas/thirdPartyId" + - in: query + name: thirdPartyUserId + description: Either use userId or thirdPartyId and thirdPartyUserId + schema: + $ref: "#/components/schemas/thirdPartyUserId" + responses: + "200": + description: Get a user's information. + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/authRecipeUser" + - type: object + properties: + status: + type: string + enum: ["UNKNOWN_USER_ID_ERROR", "UNKNOWN_THIRD_PARTY_USER_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/users/by-email: + get: + operationId: thirdPartyGetUsersByEmail + summary: Get users by email + deprecated: true + tags: + - ThirdParty Recipe + description: | + Get all users accounts associated with given email + + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/thirdPartyRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: email + required: true + description: User's email + schema: + type: string + example: john.doe@example.com + + responses: + "200": + description: Get all users associated with given email + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + users: + type: array + items: + $ref: "#/components/schemas/authRecipeUser" + + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user/email/verify/token: + post: + tags: + - EmailVerification Recipe + operationId: emailVerificationVerifyToken + summary: Generate email verification token + description: | + Generate a new email verification token for this user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/emailVerificationRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/emailVerificationVerifyTokenRequest" + responses: + "200": + description: Generate a new email verification token for this user + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + token: + $ref: "#/components/schemas/token" + - type: object + properties: + status: + type: string + enum: ["EMAIL_ALREADY_VERIFIED_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user/email/verify/token/remove: + post: + tags: + - EmailVerification Recipe + operationId: emailVerificationVerifyTokenRemove + summary: Remove email verification tokens + description: | + Remove all unused email verification tokens for this user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/emailVerificationRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/emailVerificationVerifyTokenRequest" + responses: + "200": + description: OK response + content: + application/json: + schema: + type: object + properties: + status: + type: string + enum: ["OK"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user/email/verify: + post: + tags: + - EmailVerification Recipe + operationId: emailVerificationVerify + summary: Verify email + description: | + Verify an email + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/emailVerificationRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + method: + type: string + enum: + - token + token: + $ref: "#/components/schemas/token" + + responses: + "200": + description: Verify an email + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + userId: + $ref: "#/components/schemas/userId" + email: + $ref: "#/components/schemas/email" + - type: object + properties: + status: + type: string + enum: ["EMAIL_VERIFICATION_INVALID_TOKEN_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/user/email/verify: + get: + tags: + - EmailVerification Recipe + operationId: emailVerificationVerifyGet + summary: Check email verification + description: | + Check if an email is verified + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/emailVerificationRid" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/userId" + - $ref: "#/components/parameters/email" + responses: + "200": + description: Verify an email + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + isVerified: + $ref: "#/components/schemas/isVerified" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/user/email/verify/remove: + post: + tags: + - EmailVerification Recipe + operationId: emailVerificationVerifyRemove + summary: Unverify email + description: | + Unverify an email + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/emailVerificationRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/emailVerificationVerifyTokenRequest" + + responses: + "200": + description: OK response + content: + application/json: + schema: + type: object + properties: + status: + type: string + enum: ["OK"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/user/metadata: + get: + tags: + - User Metadata Recipe + operationId: userMetadataRead + summary: Get user metadata + description: | + Gets the stored metadata object of the user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userMetadataRid" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/userIdRequired" + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + metadata: + $ref: "#/components/schemas/userMetadata" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + put: + tags: + - User Metadata Recipe + operationId: userMetadataUpdate + summary: Update user metadata + description: | + Updates the metadata object stored about the user by doing a shallow merge of the stored and the update JSONs + and removing properties set to null on the root level of the update object. The merged object is then reserialized and stored. + + e.g.: + - stored: `{ "preferences": { "theme":"dark" }, "notifications": { "email": true }, "todos": ["example"] }` + + - update: `{ "notifications": { "sms": true }, "todos": null }` + + - result: `{ "preferences": { "theme":"dark" }, "notifications": { "sms": true } }` + + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userMetadataRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + metadataUpdate: + $ref: "#/components/schemas/userMetadataUpdate" + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + metadata: + $ref: "#/components/schemas/userMetadata" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/user/metadata/remove: + post: + tags: + - User Metadata Recipe + operationId: userMetadataDelete + summary: Remove user metadata + description: | + Removes the entire metadata JSON stored about the user. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userMetadataRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user/role: + put: + tags: + - User Roles Recipe + operationId: addUserRole + summary: Add user role + description: | + Creates a User Role mapping + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/userRolesRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + role: + $ref: "#/components/schemas/role" + required: [userId, role] + + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + didUserAlreadyHaveRole: + type: boolean + example: true + - $ref: "#/components/schemas/unknownRoleResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user/role/remove: + post: + tags: + - User Roles Recipe + operationId: removeUserRole + summary: Remove user role + description: | + Removes a User Role mapping + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/userRolesRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + role: + $ref: "#/components/schemas/role" + required: [userId, role] + + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + didUserHaveRole: + type: boolean + example: true + - $ref: "#/components/schemas/unknownRoleResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/user/roles: + get: + tags: + - User Roles Recipe + operationId: getUserRoles + summary: Get user roles + description: | + Retrive the roles associated with the user. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/userRolesRid" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/userIdRequired" + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + roles: + type: array + items: + $ref: "#/components/schemas/role" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/role/users: + get: + tags: + - User Roles Recipe + operationId: getRoleUsers + summary: Get users with role + description: | + Retrive the users associated with the role. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/userRolesRid" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/roleRequired" + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + users: + type: array + items: + $ref: "#/components/schemas/userId" + - $ref: "#/components/schemas/unknownRoleResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/role: + put: + tags: + - User Roles Recipe + operationId: putRole + summary: Create or update role + description: | + Creates a role with permissions, can also be used to add permissions to a role + + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userRolesRid" + - $ref: "#/components/parameters/cdi-version" + + requestBody: + content: + application/json: + schema: + type: object + properties: + role: + $ref: "#/components/schemas/role" + permissions: + type: array + items: + type: string + example: permission + required: [role] + + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNewRole: + type: boolean + example: true + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/role/permissions: + get: + tags: + - User Roles Recipe + operationId: getRolePermissions + summary: Get role permissions + description: | + Retrive the permissions associated with a role + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userRolesRid" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/roleRequired" + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + permissions: + type: array + items: + type: string + example: permission + - $ref: "#/components/schemas/unknownRoleResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/role/permissions/remove: + post: + tags: + - User Roles Recipe + operationId: removeRolePermissions + summary: Remove role permissions + description: | + Removes permissions mapped to a role, if no permissions are passed all permissions mapped to the role are removed + + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userRolesRid" + - $ref: "#/components/parameters/cdi-version" + + requestBody: + content: + application/json: + schema: + type: object + properties: + role: + $ref: "#/components/schemas/role" + permissions: + type: array + items: + type: string + example: permission + required: [role] + + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - $ref: "#/components/schemas/unknownRoleResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/permission/roles: + get: + tags: + - User Roles Recipe + operationId: getPermissionRoles + summary: Get permission roles + description: | + Retrive the roles associated with the permission + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userRolesRid" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/permissionRequired" + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + roles: + type: array + items: + type: string + example: admin + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/role/remove: + post: + tags: + - User Roles Recipe + operationId: removeRole + summary: Delete role + description: | + Deletes a role + + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userRolesRid" + - $ref: "#/components/parameters/cdi-version" + + requestBody: + content: + application/json: + schema: + type: object + properties: + role: + $ref: "#/components/schemas/role" + required: [role] + + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + didRoleExist: + type: boolean + example: true + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/roles: + get: + tags: + - User Roles Recipe + operationId: getRoles + summary: Get all roles + description: | + Retrive all created roles + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/userRolesRid" + - $ref: "#/components/parameters/cdi-version" + responses: + "200": + description: "The operation was successful" + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + roles: + type: array + items: + type: string + example: admin + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/session: + post: + tags: + - Session Recipe + operationId: createNewSession + summary: Create new session + description: | + Create a new Session + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + userDataInJWT: + $ref: "#/components/schemas/userDataInJWT" + userDataInDatabase: + $ref: "#/components/schemas/userDataInDatabase" + enableAntiCsrf: + $ref: "#/components/schemas/enableAntiCsrf" + useDynamicSigningKey: + type: boolean + description: Decides if the token should be signed with a dynamic or static key, defaults to true + example: false + responses: + "200": + description: Create a new Session + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + session: + $ref: "#/components/schemas/session" + accessToken: + $ref: "#/components/schemas/cookieInfo" + refreshToken: + $ref: "#/components/schemas/cookieInfo" + antiCsrfToken: + $ref: "#/components/schemas/token" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/session: + get: + tags: + - Session Recipe + operationId: getSessionInfo + summary: Get session info + description: | + Get user and session information for a given session handle + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: sessionHandle + schema: + $ref: "#/components/schemas/handle" + responses: + "200": + description: Get user and session information for a given session handle + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + userDataInDatabase: + $ref: "#/components/schemas/userDataInDatabase" + userDataInJWT: + $ref: "#/components/schemas/userDataInJWT" + userId: + $ref: "#/components/schemas/userId" + expiry: + $ref: "#/components/schemas/expiry" + timeCreated: + $ref: "#/components/schemas/timeCreated" + sessionHandle: + $ref: "#/components/schemas/handle" + tenantId: + $ref: "#/components/schemas/tenantId" + - $ref: "#/components/schemas/unauthorisedMessageResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/session/remove: + post: + tags: + - Session Recipe + operationId: deleteSession + summary: Delete session + description: | + Delete a sesion + + If revoking session by `userId`, the sessions are cleared across all tenants by default. + + Note: If `revokeAcrossAllTenants` is set to `true`, this API can only be called from `public` tenant. + + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + properties: + sessionHandles: + $ref: "#/components/schemas/sessionHandles" + - type: object + required: + - userId + properties: + userId: + $ref: "#/components/schemas/userId" + revokeAcrossAllTenants: + type: boolean + + responses: + "200": + description: Delete a session + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + sessionHandlesRevoked: + $ref: "#/components/schemas/sessionHandles" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/session/verify: + post: + tags: + - Session Recipe + operationId: verifySession + summary: Verify session + description: | + Verify a Session + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + accessToken: + $ref: "#/components/schemas/token" + enableAntiCsrf: + $ref: "#/components/schemas/enableAntiCsrf" + doAntiCsrfCheck: + type: boolean + example: false + checkDatabase: + type: boolean + description: Decides if we always check if the session exists in the DB or just do token validation, defaults to false. + example: false + antiCsrfToken: + $ref: "#/components/schemas/token" + responses: + "200": + description: Verify a session + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + session: + $ref: "#/components/schemas/session" + accessToken: + $ref: "#/components/schemas/cookieInfo" + - $ref: "#/components/schemas/unauthorisedMessageResponse" + - type: object + properties: + status: + $ref: "#/components/schemas/tryRefreshTokenResponse" + message: + $ref: "#/components/schemas/message" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/session/refresh: + post: + tags: + - Session Recipe + operationId: refreshSession + summary: Refresh session + description: | + Refresh a Session + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + refreshToken: + $ref: "#/components/schemas/token" + enableAntiCsrf: + $ref: "#/components/schemas/enableAntiCsrf" + antiCsrfToken: + $ref: "#/components/schemas/token" + useDynamicSigningKey: + type: boolean + required: [refreshToken, enableAntiCsrf, useDynamicSigningKey] + responses: + "200": + description: Refresh a session + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + session: + $ref: "#/components/schemas/session" + accessToken: + $ref: "#/components/schemas/cookieInfo" + refreshToken: + $ref: "#/components/schemas/cookieInfo" + antiCsrfToken: + $ref: "#/components/schemas/token" + - type: object + properties: + status: + $ref: "#/components/schemas/tokenTheftResponse" + session: + type: object + properties: + handle: + $ref: "#/components/schemas/handle" + userId: + $ref: "#/components/schemas/userId" + - $ref: "#/components/schemas/unauthorisedMessageResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/session/user: + get: + tags: + - Session Recipe + operationId: getUserSessionHandles + summary: Get user session handles + description: | + Get session handles for a user + + By default, the session handles are fetched across all tenants. Set `fetchAcrossAllTenants` to `false` to get sessionHandles for the user for a particular tenant. + + Note: If `fetchAcrossAllTenants` is set to `true`, this API can only be called from `public` tenant. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/userId" + - name: fetchAcrossAllTenants + schema: + type: string + enum: ["true", "false"] + required: false + in: query + responses: + "200": + description: Get user Session Handles + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + sessionHandles: + $ref: "#/components/schemas/sessionHandles" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/session/regenerate: + post: + tags: + - Session Recipe + operationId: regenerateSession + summary: Regenerate session + description: | + Regenerate a session + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + accessToken: + $ref: "#/components/schemas/token" + userDataInJWT: + $ref: "#/components/schemas/userDataInJWT" + responses: + "200": + description: Regenerate user session + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + session: + $ref: "#/components/schemas/session" + accessToken: + $ref: "#/components/schemas/cookieInfo" + - $ref: "#/components/schemas/unauthorisedMessageResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/session/data: + get: + deprecated: true + tags: + - Session Recipe + operationId: getSessionData + summary: Get session data + description: | + Get session data + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: sessionHandle + description: Users session handle + schema: + $ref: "#/components/schemas/handle" + responses: + "200": + description: Get Session Data + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + userDataInDatabase: + $ref: "#/components/schemas/userDataInDatabase" + - $ref: "#/components/schemas/unauthorisedMessageResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + put: + tags: + - Session Recipe + operationId: putSessionData + summary: Update session data + description: | + Change session data + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + sessionHandle: + $ref: "#/components/schemas/handle" + userDataInDatabase: + $ref: "#/components/schemas/userDataInDatabase" + responses: + "200": + description: Change Session Data + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/statusOKResponse" + - $ref: "#/components/schemas/unauthorisedMessageResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/jwt: + post: + tags: + - JWT Recipe + operationId: createSignedJWT + summary: Create signed JWT + description: | + Create a signed JWT + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/jwtRID" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + payload: + $ref: "#/components/schemas/createJWTPayload" + algorithm: + $ref: "#/components/schemas/createJWTAlgorithm" + jwksDomain: + $ref: "#/components/schemas/jwksDomain" + validity: + $ref: "#/components/schemas/jwtValidity" + useStaticSigningKey: + type: boolean + description: Decides if the token should be signed with a dynamic or static key, defaults to true + example: true + + responses: + "200": + description: Create a signed JWT + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + jwt: + type: string + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + - type: object + properties: + status: + type: string + enum: ["UNSUPPORTED_ALGORITHM_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/jwt/jwks: + get: + deprecated: true + tags: + - JWT Recipe + operationId: getJWKS + summary: Get JWT keys + description: | + Retrieve JWKs for JWT verification, containing both static and dynamic keys. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/jwtRID" + - $ref: "#/components/parameters/cdi-version" + responses: + "200": + description: Retrieve JWKs for JWT verification, containing both static and dynamic keys. + content: + application/json: + schema: + type: object + properties: + status: + type: string + enum: ["OK"] + keys: + type: array + items: + $ref: "#/components/schemas/jwk" + + "400": + $ref: "#/components/responses/400" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/.well-known/jwks.json: + get: + tags: + - Core + operationId: getWellKnownJWKS + summary: Get well-known JWT keys + description: | + Retrieve JWKs for JWT verification, containing both static and dynamic keys. + responses: + "200": + description: Retrieve JWKs for JWT verification, containing both static and dynamic keys. + content: + application/json: + schema: + type: object + properties: + keys: + type: array + items: + $ref: "#/components/schemas/jwk" + + "400": + $ref: "#/components/responses/400" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/jwt/data: + get: + deprecated: true + tags: + - Session Recipe + operationId: getJWTData + summary: Get JWT data + description: | + Get JWT data for a session + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: sessionHandle + description: Users session handle + schema: + $ref: "#/components/schemas/handle" + responses: + "200": + description: Get JWT Data + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + userDataInJWT: + $ref: "#/components/schemas/userDataInJWT" + - $ref: "#/components/schemas/unauthorisedMessageResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + put: + tags: + - Session Recipe + operationId: putJWTData + summary: Update JWT data + description: | + Change JWT data for a session + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/sessionRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + sessionHandle: + $ref: "#/components/schemas/handle" + userDataInJWT: + $ref: "#/components/schemas/userDataInJWT" + responses: + "200": + description: Change JWT Data for a session + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/statusOKResponse" + - $ref: "#/components/schemas/unauthorisedMessageResponse" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/dashboard/user: + post: + tags: + - Dashboard Recipe + operationId: createDashboardUser + summary: Create dashboard user + description: | + Create a dashboard user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/dashboardRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + type: string + example: test@example.com + password: + type: string + example: password@123 + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + type: string + enum: ["OK"] + user: + type: object + properties: + userId: + type: string + example: "example-userid" + email: + type: string + example: "test@example.com" + timeCreated: + type: number + example: 1231321231 + - type: object + properties: + status: + type: string + enum: ["EMAIL_ALREADY_EXISTS_ERROR"] + - type: object + properties: + status: + type: string + enum: ["PASSWORD_WEAK_ERROR"] + message: + type: string + example: "Your password must have at least 8 characters" + - type: object + properties: + status: + type: string + enum: ["INVALID_EMAIL_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + description: Indicates ayment required + content: + application/json: + schema: + type: object + properties: + status: + type: string + enum: ["USER_LIMIT_REACHED_ERROR"] + message: + type: string + example: "You have reached the free limit for creating users, please purchase the dashboard feature to create new users" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + put: + tags: + - Dashboard Recipe + operationId: updateDashboardUser + summary: Update dashboard user + description: | + Update a user's email or password + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/dashboardRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + properties: + email: + type: string + example: test@example.com + newPassword: + type: string + example: password@123 + newEmail: + type: string + example: test2@example.com + - type: object + properties: + userId: + type: string + example: "ue21r-fw32r3-d121-d1" + newPassword: + type: string + example: "password@123" + newEmail: + type: string + example: test2@example.com + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + type: string + enum: ["OK"] + user: + type: object + properties: + userId: + type: string + example: "r23r-f235th54-g3413gf-r32dr2" + email: + type: string + example: "test@example.com" + timeCreated: + type: number + example: 391238234792 + - type: object + properties: + status: + type: string + enum: ["EMAIL_ALREADY_EXISTS_ERROR"] + - type: object + properties: + status: + type: string + enum: ["PASSWORD_WEAK_ERROR"] + message: + type: string + example: "Your password must have at least 8 characters" + - type: object + properties: + status: + type: string + enum: ["INVALID_EMAIL_ERROR"] + - type: object + properties: + status: + type: string + enum: ["UNKNOWN_USER_ERROR"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + delete: + tags: + - Dashboard Recipe + operationId: deleteDashboardUser + summary: Delete dashboard user + description: | + Delete a dashboard user with their userId or email + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/dashboardRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: email + schema: + type: string + example: "test@example.com" + required: false + + - in: query + name: userId + schema: + type: string + example: "ue1231-f32f290f2-f23r23f-323f2" + required: false + + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + didUserExist: + type: boolean + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/dashboard/users: + get: + tags: + - Dashboard Recipe + operationId: getAllDashboardUsers + summary: Get all dashboard users + description: | + Get a list of call the dashboard users + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/dashboardRid" + - $ref: "#/components/parameters/cdi-version" + responses: + "200": + description: get a list of dashboard users + content: + application/json: + schema: + type: object + properties: + status: + type: string + enum: ["OK"] + users: + type: array + items: + type: object + properties: + email: + type: string + example: "test@example.com" + userId: + type: string + example: "uf2323-f223r233-f23-f23-f2f32" + timeCreated: + type: number + example: 16382348324 + isSuspended: + type: boolean + example: false + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/dashboard/session/verify: + post: + tags: + - Dashboard Recipe + operationId: verifyDashboardUserSession + summary: Verify dashboard user session + description: | + Verify a Dashboard user's sessionId + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/dashboardRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + sessionId: + type: string + example: "rf32f-f32342f-32f-323r2f3-23" + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + type: string + enum: ["OK"] + email: + type: string + - type: object + properties: + status: + type: string + enum: ["USER_SUSPENDED_ERROR"] + message: + type: string + example: "You have crossed the free dashboard user limit. Please purchase the dashboard feature or login with a valid user account" + - type: object + properties: + status: + type: string + enum: ["INVAlID_SESSION_ERROR"] + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/dashboard/session: + delete: + tags: + - Dashboard Recipe + operationId: RevokeDashboardUsersSession + summary: Revoke dashboard user session + description: | + Revoke a Dashboard user's session + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/dashboardRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: sessionId + schema: + type: string + example: "ue1231-f32f290f2-f23r23f-323f2" + + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/dashboard/signin: + post: + tags: + - Dashboard Recipe + operationId: signInDashboardUser + summary: Sign in dashboard user + description: | + Signin a Dashboard user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/dashboardRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + type: string + example: test@example.com + password: + type: string + example: password@123 + responses: + "200": + description: Indicates success with the status property + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + type: string + enum: ["OK"] + sessionId: + type: string + example: + - type: object + properties: + status: + type: string + enum: ["USER_SUSPENDED_ERROR"] + message: + type: string + example: "You have crossed the free dashboard user limit. Please purchase the dashboard feature or login with a valid user account" + - type: object + properties: + status: + type: string + enum: ["INVAlID_CREDENTIALS_ERROR"] + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/dashboard/user/sessions: + get: + tags: + - Dashboard Recipe + operationId: getAllSessionsForDashboardUser + summary: Get all sessions for dashboard user + description: | + Get a list of the sessions for the dashboard user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/dashboardRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: userId + schema: + type: string + example: "ue1231-f32f290f2-f23r23f-323f2" + required: false + responses: + "200": + description: get a list of sessions for dashboard user + content: + application/json: + schema: + type: object + properties: + sessions: + type: array + items: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + sessionId: + type: string + example: "fni29f-f23f23-f2fq32qt-h35evf" + timeCreated: + type: number + example: 16382348324 + expiry: + type: number + example: 16382348324 + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/apiversion: + get: + tags: + - Core + operationId: getApiVersion + summary: Get API version + description: | + Get a list of compatible CDI versions + security: + - ApiKey: [] + parameters: + - in: query + name: websiteDomain + schema: + type: string + example: https://example.com + required: false + - in: query + name: apiDomain + schema: + type: string + example: https://api.example.com + required: false + responses: + "200": + description: get api version + content: + application/json: + schema: + type: object + properties: + versions: + type: array + items: + type: string + example: ["2.13"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /config: + get: + tags: + - Core + operationId: getConfig + summary: Get config file path + description: | + Get path to the loaded config file + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + - in: query + name: pid + schema: + type: string + example: 21307 + + responses: + "200": + description: get api version + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + path: + type: string + example: /usr/lib/supertokens/config.yaml + - type: object + properties: + status: + type: string + enum: ["NOT_ALLOWED"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/: + get: + tags: + - Core + operationId: getHelloOnRootPath + summary: Get hello message on root path + description: | + Return a simple hello message + responses: + "200": + $ref: "#/components/responses/hello" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/hello: + get: + tags: + - Core + operationId: getHello + summary: Get hello message + description: | + Return a simple hello message + responses: + "200": + $ref: "#/components/responses/hello" + "500": + $ref: "#/components/responses/500" + put: + tags: + - Core + operationId: putHello + summary: Put hello message + description: | + Return a simple hello message + responses: + "200": + $ref: "#/components/responses/hello" + "500": + $ref: "#/components/responses/500" + + post: + tags: + - Core + operationId: postHello + summary: Post hello message + description: | + Return a simple hello message + responses: + "200": + $ref: "#/components/responses/hello" + "500": + $ref: "#/components/responses/500" + + delete: + tags: + - Core + operationId: deleteHello + summary: Delete hello message + description: | + Return a simple hello message + responses: + "200": + $ref: "#/components/responses/hello" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/telemetry: + get: + tags: + - Core + operationId: getTelemetry + summary: Get telemetry ID + description: | + Returns the telemetryID if it exists + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/cdi-version" + responses: + "200": + description: Returns the telemetryID if it exists + content: + application/json: + schema: + oneOf: + - type: object + properties: + exists: + type: boolean + enum: [true] + telemetryId: + type: string + example: 99c87c72-1807-22d-9b39-7a88f95re56c + - type: object + properties: + exists: + type: boolean + example: [false] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/users/count: + get: + tags: + - Core + operationId: getUsersCount + summary: Get users count + description: | + Get number of users. + + API is tenant specific if `includeAllTenants` is false. + Else, `tenantId` is ignored. + security: + - ApiKey: [] + + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/includeRecipeIds" + - name: includeAllTenants + description: if set to true, will count users across all tenants in the app + in: query + schema: + type: boolean + default: false + responses: + "200": + description: Get number of users + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + count: + type: number + example: 1000000 + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/users/count/active: + get: + tags: + - Core + operationId: getActiveUsersCount + summary: Get active users count + description: | + Get number of active users. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + - in: query + name: since + schema: + type: number + example: 1679875200000 + required: true + responses: + "200": + description: Get number of active users + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + count: + type: number + example: 100000 + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/users: + get: + tags: + - Core + operationId: getUsers + summary: Get users + description: | + Get users. + + API is tenant specific if `includeAllTenants` is false. + Else, `tenantId` is ignored. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/includeRecipeIds" + - $ref: "#/components/parameters/paginationToken" + - $ref: "#/components/parameters/limit" + - $ref: "#/components/parameters/timeJoinedOrder" + - in: query + name: email + schema: + type: string + example: "test@example.com" + required: false + - in: query + name: phone + schema: + type: number + example: +911234567890 + required: false + - in: query + name: recipe + schema: + type: string + example: "emailpassword" + required: false + - in: query + name: provider + schema: + type: string + example: "google" + required: false + responses: + "200": + description: User Pagination + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + users: + type: array + items: + type: object + properties: + user: + $ref: "#/components/schemas/authRecipeUser" + additionalProperties: false + nextPaginationToken: + $ref: "#/components/schemas/paginationToken" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/user/remove: + post: + tags: + - Core + operationId: deleteUser + summary: Delete user + description: | + Delete user + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - userId + properties: + userId: + $ref: "#/components/schemas/userId" + removeAllLinkedAccounts: + type: boolean + example: true + responses: + "200": + description: Returns OK if the operation succeeded (even if the user didn't exist before the call) + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/user/search/tags: + get: + tags: + - Core + operationId: getSearchTags + summary: Get search tags + description: | + Retrieve available tags for search + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + + responses: + "200": + description: Returns available tags for search + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + tags: + type: array + items: + type: string + example: ["email", "phone", "provider"] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/ee/featureflag: + get: + tags: + - Core + operationId: getFeatureFlag + summary: Get enterprise features + description: | + Get a list of the enabled enterprise features + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + responses: + "200": + description: The operation was successful + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + features: + type: array + items: + type: string + example: ["feature_1", "feature_2"] + usageStats: + type: object + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/ee/license: + put: + tags: + - Core + operationId: setLicense + summary: Set license key + description: | + Set or sync license key + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + licenseKey: + type: string + example: "eyJhbGciOiJIUzI1NiIsIn..." + responses: + "200": + description: The operation was successful + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + + - type: object + properties: + status: + type: string + enum: ["MISSING_EE_FOLDER_ERROR"] + + - type: object + properties: + status: + type: string + enum: ["INVALID_LICENSE_KEY_ERROR"] + + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + + delete: + tags: + - Core + operationId: deleteLicense + summary: Delete license key + description: | + Delete license key + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + + responses: + "200": + description: The operation was successful + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + + get: + tags: + - Core + operationId: getLicense + summary: Get license key + description: | + Retrieve license key + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + + responses: + "200": + description: The operation was successful + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + licenseKey: + type: string + example: "eyJhbGciOiJIUzI1NiIsIn..." + + - type: object + properties: + status: + type: string + enum: ["NO_LICENSE_KEY_FOUND_ERROR"] + + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/user/id: + get: + tags: + - Core + operationId: getUserId + summary: Get user ID + description: | + Get user id from email or phone number + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/userId" + responses: + "200": + description: The operation was successful + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/authRecipeUser" + - type: object + properties: + status: + type: string + enum: ["UNKNOWN_USER_ID_ERROR"] + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/users/by-accountinfo: + get: + tags: + - Core + operationId: getUsersByAccountInfo + summary: Get users by account info + description: | + Get users by email, phoneNumber or thirdParty info + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: email + required: false + schema: + type: string + example: "test@example.com" + - in: query + name: phoneNumber + required: false + schema: + type: string + example: "+911234567890" + - in: query + name: thirdPartyId + required: false + schema: + type: string + example: "google" + - in: query + name: thirdPartyUserId + required: false + schema: + type: string + example: "1234567890" + - in: query + name: doUnionOfAccountInfo + required: true + schema: + type: boolean + example: true + responses: + "200": + description: The operation was successful + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + users: + type: array + items: + $ref: "#/components/schemas/authRecipeUser" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/requests/stats: + get: + tags: + - Core + operationId: getRequestsStats + summary: Get requests stats + description: | + Get requests stats for last 24 hours + + `averageRequestsPerSecond` and `peakRequestsPerSecond` would countain `1440` values corresponding to `now - 1440 minutes` until `now - 1 minute`. + + A value of `-1` would mean that there is no data for that minute. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + responses: + "200": + description: The operation was successful + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + atMinute: + type: number + example: 16382348 + averageRequestsPerSecond: + type: array + items: + type: number + example: 10.5 + peakRequestsPerSecond: + type: array + items: + type: number + example: 20 + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /recipe/multitenancy/connectionuridomain: + put: + tags: + - Multitenancy Recipe + + summary: Upsert connection URI domain + description: | + This API is deprecated. Please use the v2 version of this API. In the v2 version of the API, the login methods are no longer enabled using the `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` inputs. Instead, they are enabled using factorIds (such as emailpassword, otp-email, etc) specified in the `firstFactors` and `requiredSecondaryFactors` inputs. Please refer [Multitenancy Docs](https://supertokens.com/docs/multitenancy/new-tenant) to know the list of factorIds available. + + Note: This deprecated API still accepts those `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` inputs for backward compatibility. + + Create or update a connection uri domain. + + SuperTokens subscription license key is required, if not using the base connection uri domain. + + This request must originate from public app and public tenant on the base + connection uri domain. + + If creating a new connection uri domain, only the login methods set to true will be enabled and rest will be disabled by default. + + `firstFactors` and `requiredSecondaryFactors` can be set to null to remove all entries in the core, or a non empty string array to be updated in the core. Setting of empty array is disallowed. + + Note: the create/update will fail if a login method is not enabled and a relavant factor is added to either `firstFactors` or `requiredSecondaryFactors`. For example, `emailPasswordEnabled` cannot be set to `false` if `emailpassword` is present in the `firstFactors` array. + + If updating an existing connection uri domain, + 1. core will keep the existing state of login methods and only update the ones that are specified in the request body. + 2. Core config will be merged into existing config. To delete a key in the config, use a null value + + Note: The core config must contain a unique connection to the storage layer, because sharing of database between 2 different connection uri domains is not allowed. + + Note: Updation of core config is not allowed for the default connectionUriDomain. In order to update config for the default connectionUriDomain, you must edit the config.yaml or the docker env directly. + + operationId: createOrUpdateConnectionURIDomainPUT + deprecated: true + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - connectionUriDomain + properties: + connectionUriDomain: + type: string + example: core-1234.supertokens.io:3567 + emailPasswordEnabled: + type: boolean + thirdPartyEnabled: + type: boolean + passwordlessEnabled: + type: boolean + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + responses: + 200: + description: Create or Update connection uri domain result + content: + application/json: + schema: + type: object + required: + - status + - createdNew + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNew: + type: boolean + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /recipe/multitenancy/connectionuridomain/v2: + put: + summary: Upsert connection uri domain + tags: + - Multitenancy Recipe + + description: | + Create or update a connection uri domain. + + SuperTokens subscription license key is required, if not using the base connection uri domain. + + This request must originate from public app and public tenant on the base + connection uri domain. + + The `firstFactors` can be set to following values: + + - `null`: When set to `null`, all the login methods will be available for the connection URI domain (public app, public tenant). + - `[]` (empty array): No login methods will be enabled for the connection URI domain (public app, public tenant). + - `['factor1', 'factor2', ...]` (non-empty array): The list of login methods to enable for the connection URI domain (public app, public tenant). For eg. if this is set to `['emailpassword', 'thirdparty']`, the users of the tenant will be able to login using emailpassword and third party providers. + + List of built-in first factors are as follows: + + - Email password auth: `emailpassword` + - Social login / enterprise SSO auth: `thirdparty` + - Passwordless: + - With email OTP: `otp-email` + - With SMS OTP: `otp-phone` + - With email magic link: `link-email` + - With SMS magic link: `link-phone` + + If first factors are not specified while creating a new connection uri domain, all the login methods will be enabled by default. + + The `requiredSecondaryFactors` can be set to following values: + - `null`: When set to `null`, no secondary factors will be required for the users of the connection URI domain (public app, public tenant). + - `['factor1', 'factor2', ...]` (non-empty array): The list of factors that the users of the connection URI domain (public app, public tenant) must complete post the first factor login. For eg. if this is set to `['otp-phone', 'totp']`, the users of the tenant will be required to complete either phone OTP or TOTP post the first factor login. + + List of built-in secondary factors are as follows: + + - Email password auth: `emailpassword` + - Social login / enterprise SSO auth: `thirdparty` + - Passwordless: + - With email OTP: `otp-email` + - With SMS OTP: `otp-phone` + - With email magic link: `link-email` + - With SMS magic link: `link-phone` + - Time based OTP: `totp` + + If updating an existing connection uri domain, + 1. core will keep the existing state of login methods and only update the ones that are specified in the request body. + 2. Core config will be merged into existing config. To delete a key in the config, use a null value + + Note: The core config must contain a unique connection to the storage layer, because sharing of database between 2 different connection uri domains is not allowed. + + Note: Updation of core config is not allowed for the default connectionUriDomain. In order to update config for the default connectionUriDomain, you must edit the config.yaml or the docker env directly. + + operationId: createOrUpdateConnectionURIDomainV2PUT + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - connectionUriDomain + properties: + connectionUriDomain: + type: string + example: core-1234.supertokens.io:3567 + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + responses: + 200: + description: Create or Update connection uri domain result + content: + application/json: + schema: + type: object + required: + - status + - createdNew + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNew: + type: boolean + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /recipe/multitenancy/connectionuridomain/remove: + post: + summary: Remove connection uri domain + tags: + - Multitenancy Recipe + description: | + Delete a connection uri domain. + + Deletion of base connection uri domain is not allowed. + + The request must originate from base connection uri domain and public app and tenant. + + Note: There should be no apps or tenants (other than the public app and public tenant) belonging to the connection uri domain to be able to delete it. + + operationId: deleteConnectionUriDomainPOST + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - connectionUriDomain + properties: + connectionUriDomain: + type: string + example: core-1234.supertokens.io:3567 + responses: + 200: + description: Remove connection uri domain result + content: + application/json: + schema: + type: object + required: + - status + - didExist + properties: + status: + $ref: "#/components/schemas/statusOK" + didExist: + type: boolean + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /recipe/multitenancy/connectionuridomain/list: + get: + summary: List connection uri domains + tags: + - Multitenancy Recipe + description: | + This API is deprecated. Please use the v2 version of this API. In the v2 version of the API, the login methods are no longer enabled using the `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` inputs. Instead, they are enabled using factorIds (such as emailpassword, otp-email, etc) specified in the `firstFactors` and `requiredSecondaryFactors` inputs. Please refer [Multitenancy Docs](https://supertokens.com/docs/multitenancy/new-tenant) to know the list of factorIds available. + + Note: This deprecated API still returns `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` values for backward compatibility, and it's values are derived from the `firstFactors` and `requiredSecondaryFactors` configured for the tenant. The detailed computation of the values as per CDI version is described here: https://github.com/supertokens/supertokens-core/issues/979#issuecomment-2099971371 + + Get a list of all connection uri domains. + + Request must originate from base connection uri domain and public app and tenant. + + operationId: connectionUriDomainListGET + deprecated: true + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + responses: + 200: + description: List of connection uri domains + + content: + application/json: + schema: + type: object + required: + - status + - connectionUriDomains + properties: + status: + $ref: "#/components/schemas/statusOK" + connectionUriDomains: + type: array + items: + type: object + properties: + connectionUriDomain: + type: string + example: core-1234.supertokens.io:3567 + apps: + type: array + items: + type: object + properties: + appId: + type: string + example: app1 + tenants: + type: array + items: + $ref: "#/components/schemas/tenantConfig" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /recipe/multitenancy/connectionuridomain/list/v2: + get: + summary: List connection uri domains + tags: + - Multitenancy Recipe + description: | + Get a list of all connection uri domains. + + The value of `firstFactors` can be as follows: + - `null`: When set to `null`, the SDK will use firstFactors defined in the SDK + - `[]` (empty array): No first factors would be enabled for the tenant + - non-empty array: The first factors that are enabled for the tenant + + Request must originate from base connection uri domain and public app and tenant. + + operationId: connectionUriDomainListV2GET + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + responses: + 200: + description: List of connection uri domains + + content: + application/json: + schema: + type: object + required: + - status + - connectionUriDomains + properties: + status: + $ref: "#/components/schemas/statusOK" + connectionUriDomains: + type: array + items: + type: object + properties: + connectionUriDomain: + type: string + example: core-1234.supertokens.io:3567 + apps: + type: array + items: + type: object + properties: + appId: + type: string + example: app1 + tenants: + type: array + items: + $ref: "#/components/schemas/tenantConfigV2" + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /recipe/multitenancy/app: + put: + summary: Upsert app + tags: + - Multitenancy Recipe + + description: | + This API is deprecated. Please use the v2 version of this API. In the v2 version of the API, the login methods are no longer enabled using the `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` inputs. Instead, they are enabled using factorIds (such as emailpassword, otp-email, etc) specified in the `firstFactors` and `requiredSecondaryFactors` inputs. Please refer [Multitenancy Docs](https://supertokens.com/docs/multitenancy/new-tenant) to know the list of factorIds available. + + Note: This deprecated API still accepts those `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` inputs for backward compatibility. + + Create or update an app. + SuperTokens subscription license key is required. + + If creating a new app, only the login methods set to true will be enabled and rest will be disabled by default. + + `firstFactors` and `requiredSecondaryFactors` can be set to null to remove all entries in the core, or a non empty string array to be updated in the core. Setting of empty array is disallowed. + + Note: the create/update will fail if a login method is not enabled and a relavant factor is added to either `firstFactors` or `requiredSecondaryFactors`. For example, `emailPasswordEnabled` cannot be set to `false` if `emailpassword` is present in the `firstFactors` array. + + If updating an existing app, + 1. core will keep the existing state of login methods and only update the ones that are specified in the request body. + 2. Core config will be merged into existing config. To delete a key in the config, use a null value + + Note: the newly created app will use the same connection uri domain from which + this request originates and the request must originate from public app and public tenant. + + Note: Updation of core config is not allowed for the default connectionUriDomain, public app. In order to update config for the default connectionUriDomain and public app, you must edit the config.yaml or the docker env directly. + + operationId: createOrUpdateAppPUT + deprecated: true + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - appId + properties: + appId: + type: string + example: app1 + emailPasswordEnabled: + type: boolean + thirdPartyEnabled: + type: boolean + passwordlessEnabled: + type: boolean + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + responses: + 200: + description: Create or Update app result + content: + application/json: + schema: + type: object + required: + - status + - createdNew + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNew: + type: boolean + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /recipe/multitenancy/app/v2: + put: + summary: Upsert app + tags: + - Multitenancy Recipe + + description: | + Create or update an app. + + SuperTokens subscription license key is required. + + The `firstFactors` can be set to following values: + + - `null`: When set to `null`, all the login methods will be available for the app (public tenant). + - `[]` (empty array): No login methods will be enabled for the app (public tenant). + - `['factor1', 'factor2', ...]` (non-empty array): The list of login methods to enable for the app (public tenant). For eg. if this is set to `['emailpassword', 'thirdparty']`, the users of the tenant will be able to login using emailpassword and third party providers. + + List of built-in first factors are as follows: + + - Email password auth: `emailpassword` + - Social login / enterprise SSO auth: `thirdparty` + - Passwordless: + - With email OTP: `otp-email` + - With SMS OTP: `otp-phone` + - With email magic link: `link-email` + - With SMS magic link: `link-phone` + + If first factors are not specified while creating a new app, all the login methods will be enabled by default. + + The `requiredSecondaryFactors` can be set to following values: + - `null`: When set to `null`, no secondary factors will be required for the users of the app (public tenant). + - `['factor1', 'factor2', ...]` (non-empty array): The list of factors that the users of the app (public tenant) must complete post the first factor login. For eg. if this is set to `['otp-phone', 'totp']`, the users of the tenant will be required to complete either phone OTP or TOTP post the first factor login. + + List of built-in secondary factors are as follows: + + - Email password auth: `emailpassword` + - Social login / enterprise SSO auth: `thirdparty` + - Passwordless: + - With email OTP: `otp-email` + - With SMS OTP: `otp-phone` + - With email magic link: `link-email` + - With SMS magic link: `link-phone` + - Time based OTP: `totp` + + If updating an existing app, + 1. core will keep the existing state of login methods and only update the ones that are specified in the request body. + 2. Core config will be merged into existing config. To delete a key in the config, use a null value + + Note: the newly created app will use the same connection uri domain from which + this request originates and the request must originate from public app and public tenant. + + Note: Updation of core config is not allowed for the default connectionUriDomain, public app. In order to update config for the default connectionUriDomain and public app, you must edit the config.yaml or the docker env directly. + + operationId: createOrUpdateAppV2PUT + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - appId + properties: + appId: + type: string + example: app1 + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + responses: + 200: + description: Create or Update app result + content: + application/json: + schema: + type: object + required: + - status + - createdNew + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNew: + type: boolean + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /recipe/multitenancy/app/remove: + post: + summary: Delete app + tags: + - Multitenancy Recipe + description: | + Delete an app. + + Request must originate from public app and tenant. + + Note: No tenants (other than the public tenant) must belong to the app to be able to delete it. + + operationId: deleteAppPOST + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - appId + properties: + appId: + type: string + example: app1 + responses: + 200: + description: Remove app result + content: + application/json: + schema: + type: object + required: + - status + - didExist + properties: + status: + $ref: "#/components/schemas/statusOK" + didExist: + type: boolean + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /recipe/multitenancy/app/list: + get: + summary: List apps + tags: + - Multitenancy Recipe + description: | + This API is deprecated. Please use the v2 version of this API. In the v2 version of the API, the login methods are no longer enabled using the `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` inputs. Instead, they are enabled using factorIds (such as emailpassword, otp-email, etc) specified in the `firstFactors` and `requiredSecondaryFactors` inputs. Please refer [Multitenancy Docs](https://supertokens.com/docs/multitenancy/new-tenant) to know the list of factorIds available. + + Note: This deprecated API still returns `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` values for backward compatibility, and it's values are derived from the `firstFactors` and `requiredSecondaryFactors` configured for the tenant. The detailed computation of the values as per CDI version is described here: https://github.com/supertokens/supertokens-core/issues/979#issuecomment-2099971371 + + Get a list of all apps in a connection uri domain. + + Request must originate from public app and tenant. + + operationId: appListGET + deprecated: true + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + responses: + 200: + description: List of apps + + content: + application/json: + schema: + type: object + required: + - status + - apps + properties: + status: + $ref: "#/components/schemas/statusOK" + apps: + type: array + items: + type: object + properties: + appId: + type: string + example: app1 + tenants: + type: array + items: + $ref: "#/components/schemas/tenantConfig" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /recipe/multitenancy/app/list/v2: + get: + summary: List apps + tags: + - Multitenancy Recipe + description: | + Get a list of all apps in a connection uri domain. + + The value of `firstFactors` can be as follows: + - `null`: When set to `null`, the SDK will use firstFactors defined in the SDK + - `[]` (empty array): No first factors would be enabled for the tenant + - non-empty array: The first factors that are enabled for the tenant + + Request must originate from public app and tenant. + + operationId: appListV2GET + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + responses: + 200: + description: List of apps + + content: + application/json: + schema: + type: object + required: + - status + - apps + properties: + status: + $ref: "#/components/schemas/statusOK" + apps: + type: array + items: + type: object + properties: + appId: + type: string + example: app1 + tenants: + type: array + items: + $ref: "#/components/schemas/tenantConfigV2" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/multitenancy/tenant: + put: + summary: Upsert tenant + tags: + - Multitenancy Recipe + description: | + This API is deprecated. Please use the v2 version of this API. In the v2 version of the API, the login methods are no longer enabled using the `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` inputs. Instead, they are enabled using factorIds (such as emailpassword, otp-email, etc) specified in the `firstFactors` and `requiredSecondaryFactors` inputs. Please refer [Multitenancy Docs](https://supertokens.com/docs/multitenancy/new-tenant) to know the list of factorIds available. + + Note: This deprecated API still accepts those `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` inputs for backward compatibility. + + Creates or updates a tenant. + + SuperTokens subscription license key is required. + + If creating a new tenant, only the login methods set to true will be enabled and rest will be disabled by default. + + `firstFactors` and `requiredSecondaryFactors` can be set to null to remove all entries in the core, or a non empty string array to be updated in the core. Setting of empty array is disallowed. + + Note: the create/update will fail if a login method is not enabled and a relavant factor is added to either `firstFactors` or `requiredSecondaryFactors`. For example, `emailPasswordEnabled` cannot be set to `false` if `emailpassword` is present in the `firstFactors` array. + + If updating an existing tenant, + 1. core will keep the existing state of login methods and only update the ones that are specified in the request body. + 2. Core config will be merged into existing config. To delete a key in the config, use a null value + + The request must originate from public tenant, and the new tenant will use connectionUriDomain and app from which the request originates. + + Note: Updation of core config is not allowed for the default connectionUriDomain, public app and tenant. In order to update config for the default connectionUriDomain, public app and tenant, you must edit the config.yaml or the docker env directly. + + operationId: createOrUpdateTenantPUT + deprecated: true + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - tenantId + properties: + tenantId: + $ref: "#/components/schemas/tenantId" + emailPasswordEnabled: + type: boolean + thirdPartyEnabled: + type: boolean + passwordlessEnabled: + type: boolean + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + responses: + 200: + description: Create or Update tenant result + content: + application/json: + schema: + type: object + required: + - status + - createdNew + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNew: + type: boolean + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/multitenancy/tenant/v2: + put: + summary: Upsert tenant + tags: + - Multitenancy Recipe + description: | + Creates or updates a tenant. + + SuperTokens subscription license key is required. + + The `firstFactors` can be set to following values: + + - `null`: When set to `null`, all the login methods will be available for the tenant. + - `[]` (empty array): No login methods will be enabled for the tenant. + - `['factor1', 'factor2', ...]` (non-empty array): The list of login methods to enable for the tenant. For eg. if this is set to `['emailpassword', 'thirdparty']`, the users of the tenant will be able to login using emailpassword and third party providers. + + List of built-in first factors are as follows: + + - Email password auth: `emailpassword` + - Social login / enterprise SSO auth: `thirdparty` + - Passwordless: + - With email OTP: `otp-email` + - With SMS OTP: `otp-phone` + - With email magic link: `link-email` + - With SMS magic link: `link-phone` + + If first factors are not specified while creating a new tenant, all the login methods will be disabled by default. + + The `requiredSecondaryFactors` can be set to following values: + - `null`: When set to `null`, no secondary factors will be required for the users of the tenant. + - `['factor1', 'factor2', ...]` (non-empty array): The list of factors that the users of the tenant must complete post the first factor login. For eg. if this is set to `['otp-phone', 'totp']`, the users of the tenant will be required to complete either phone OTP or TOTP post the first factor login. + + List of built-in secondary factors are as follows: + + - Email password auth: `emailpassword` + - Social login / enterprise SSO auth: `thirdparty` + - Passwordless: + - With email OTP: `otp-email` + - With SMS OTP: `otp-phone` + - With email magic link: `link-email` + - With SMS magic link: `link-phone` + - Time based OTP: `totp` + + If updating an existing tenant, + 1. core will keep the existing state of login methods and only update the ones that are specified in the request body. + 2. Core config will be merged into existing config. To delete a key in the config, use a null value + + The request must originate from public tenant, and the new tenant will use connectionUriDomain and app from which the request originates. + + Note: Updation of core config is not allowed for the default connectionUriDomain, public app and tenant. In order to update config for the default connectionUriDomain, public app and tenant, you must edit the config.yaml or the docker env directly. + + operationId: createOrUpdateTenantV2PUT + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - tenantId + properties: + tenantId: + $ref: "#/components/schemas/tenantId" + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + responses: + 200: + description: Create or Update tenant result + content: + application/json: + schema: + type: object + required: + - status + - createdNew + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNew: + type: boolean + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/multitenancy/tenant: + get: + summary: Get tenant configuration + tags: + - Multitenancy Recipe + description: | + This API is deprecated. Please use the v2 version of this API. In the v2 version of the API, the login methods are no longer enabled using the `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` inputs. Instead, they are enabled using factorIds (such as emailpassword, otp-email, etc) specified in the `firstFactors` and `requiredSecondaryFactors` inputs. Please refer [Multitenancy Docs](https://supertokens.com/docs/multitenancy/new-tenant) to know the list of factorIds available. + + Note: This deprecated API still returns `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` values for backward compatibility, and it's values are derived from the `firstFactors` and `requiredSecondaryFactors` configured for the tenant. The detailed computation of the values as per CDI version is described here: https://github.com/supertokens/supertokens-core/issues/979#issuecomment-2099971371 + + Get a tenant config of the tenant specified by the url prefix. + + SuperTokens subscription license key is required if querying any tenant other than the base tenant. + + Returns recipes with their enabled flag and recipe specific configs saved in core + + operationId: tenantConfigGet + deprecated: true + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + responses: + 200: + description: Tenant config result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + tenantId: + $ref: "#/components/schemas/tenantId" + emailPassword: + type: object + required: + - enabled + properties: + enabled: + type: boolean + thirdParty: + type: object + required: + - enabled + properties: + enabled: + type: boolean + providers: + type: array + items: + $ref: "#/components/schemas/thirdPartyProviderConfig" + passwordless: + type: object + required: + - enabled + properties: + enabled: + type: boolean + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + - type: object + properties: + status: + type: string + enum: [TENANT_NOT_FOUND_ERROR] + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/multitenancy/tenant/v2: + get: + summary: Get tenant configuration + tags: + - Multitenancy Recipe + description: | + Get a tenant config of the tenant specified by the url prefix. + + The value of `firstFactors` can be as follows: + - `null`: When set to `null`, the SDK will use firstFactors defined in the SDK + - `[]` (empty array): No first factors would be enabled for the tenant + - non-empty array: The first factors that are enabled for the tenant + + SuperTokens subscription license key is required if querying any tenant other than the base tenant. + + Returns recipes with their enabled flag and recipe specific configs saved in core + + operationId: tenantConfigV2Get + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + responses: + 200: + description: Tenant config result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + tenantId: + $ref: "#/components/schemas/tenantId" + thirdParty: + type: object + properties: + providers: + type: array + items: + $ref: "#/components/schemas/thirdPartyProviderConfig" + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + - type: object + properties: + status: + type: string + enum: [TENANT_NOT_FOUND_ERROR] + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/{tenantId}/recipe/dashboard/tenant/core-config: + get: + tags: + - Dashboard Recipe + summary: Get the core config + description: | + Get the core config of the tenant specified by the url prefix, along with the metadata of each of the fields. + + operationId: tenantCoreConfigForDashboardGET + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + responses: + "200": + description: Tenant core config result + content: + application/json: + schema: + type: object + required: + - status + - config + properties: + status: + $ref: "#/components/schemas/statusOK" + config: + type: array + items: + type: object + properties: + key: + type: string + example: password_reset_token_lifetime + valueType: + type: string + enum: ["string", "number", "boolean"] + nullable: true + example: "number" + value: + nullable: true + type: number + example: 3600000 + description: + type: string + example: "Time in milliseconds for how long a password reset token / link is valid for. [Default: 3600000 (1 hour)]" + isDifferentAcrossTenants: + type: boolean + possibleValues: + nullable: true + type: array + items: + type: string + isNullable: + type: boolean + example: false + defaultValue: + nullable: true + type: number + example: 3600000 + isPluginProperty: + type: boolean + example: false + isPluginPropertyEditable: + type: boolean + example: false + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/multitenancy/tenant/remove: + post: + summary: Delete a tenant + tags: + - Multitenancy Recipe + description: | + Delete a tenant. + + Request must originate from public tenant. + + operationId: deleteTenantPOST + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - tenantId + properties: + tenantId: + $ref: "#/components/schemas/tenantId" + responses: + 200: + description: Remove tenant result + content: + application/json: + schema: + type: object + required: + - status + - didExist + properties: + status: + $ref: "#/components/schemas/statusOK" + didExist: + type: boolean + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/multitenancy/tenant/list: + get: + summary: List tenants in an app + tags: + - Multitenancy Recipe + description: | + This API is deprecated. Please use the v2 version of this API. In the v2 version of the API, the login methods are no longer enabled using the `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` inputs. Instead, they are enabled using factorIds (such as emailpassword, otp-email, etc) specified in the `firstFactors` and `requiredSecondaryFactors` inputs. Please refer [Multitenancy Docs](https://supertokens.com/docs/multitenancy/new-tenant) to know the list of factorIds available. + + Note: This deprecated API still returns `emailPasswordEnabled`, `thirdPartyEnabled` and `passwordlessEnabled` values for backward compatibility, and it's values are derived from the `firstFactors` and `requiredSecondaryFactors` configured for the tenant. The detailed computation of the values as per CDI version is described here: https://github.com/supertokens/supertokens-core/issues/979#issuecomment-2099971371 + + Get a list of all tenants in an app. + + Request must originate from public tenant. + + operationId: tenantListGET + deprecated: true + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + responses: + 200: + description: List of tenants + + content: + application/json: + schema: + type: object + required: + - status + - tenants + properties: + status: + $ref: "#/components/schemas/statusOK" + tenants: + type: array + items: + $ref: "#/components/schemas/tenantConfig" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/multitenancy/tenant/list/v2: + get: + summary: List tenants in an app + tags: + - Multitenancy Recipe + description: | + Get a list of all tenants in an app. + + The value of `firstFactors` can be as follows: + - `null`: When set to `null`, the SDK will use firstFactors defined in the SDK + - `[]` (empty array): No first factors would be enabled for the tenant + - non-empty array: The first factors that are enabled for the tenant + + Request must originate from public tenant. + + operationId: tenantListV2GET + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + responses: + 200: + description: List of tenants + + content: + application/json: + schema: + type: object + required: + - status + - tenants + properties: + status: + $ref: "#/components/schemas/statusOK" + tenants: + type: array + items: + $ref: "#/components/schemas/tenantConfigV2" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/multitenancy/config/thirdparty: + put: + summary: Upsert ThirdParty Provider configuration + tags: + - Multitenancy Recipe + description: | + Creates or updates ThirdParty Provider Config for a tenant. + + If `skipValidation` is set to true, the config will be saved without any validation. + + If the config already exists for the given `tenantId` and `thirdPartyId`, the config in the core will be completely replaced with the config provided in the request body. + + **Validations done by the core:** + + `thirdPartyId` and `name` are required + + Common to all providers: + - `clients` list: + - can be undefined or empty + - if contains 1 element, clientType can be empty or undefined + - if contains more than 1 element, clientType must be defined and unique + - for each element in `clients`: + - `clientId` must not be empty + + Built-in provider's specific validation is invoked if the `thirdPartyId` starts with the provider's id + + Apple (id: apple): + - `clients` + - if it contains elements, each of them are validated as follows: + - `clientSecret` must be empty or undefined + - `additionalConfig` should contain the following keys: + - `keyId` must be a non empty string + - `teamId` must be a non empty string + - `privateKey` must be a non empty string + + Google Workspaces (id: google-workspaces): + - `clients` + - if it contains elements, each of them are validated as follows: + - `additionalConfig` may contain the key `hd` + - `hd` is optional + - if specified, it must be either `"*"`, or a valid domain + + Boxy SAML (id: boxy-saml): + - `clients` + - `additionalConfig` in the each element must contain `boxyURL` and must be non-empty string + + operationId: createOrUpdateTenantConfigPUT + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - config + properties: + config: + $ref: "#/components/schemas/thirdPartyProviderConfig" + skipValidation: + type: boolean + example: false + + responses: + 200: + description: Create or Update result + content: + application/json: + schema: + oneOf: + - type: object + required: + - status + - createdNew + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNew: + type: boolean + - type: object + required: + - status + - reason + properties: + status: + type: string + enum: ["CONFIG_VALIDATION_ERROR"] + reason: + type: string + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/multitenancy/config/thirdparty/remove: + post: + summary: Delete ThirdParty Provider configuration + tags: + - Multitenancy Recipe + description: | + Delete ThirdParty Provider configuration for a tenant. + + operationId: deleteTenantConfigPOST + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - thirdPartyId + properties: + thirdPartyId: + $ref: "#/components/schemas/thirdPartyId" + + responses: + 200: + description: Remove thirdParty config result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + didConfigExist: + type: boolean + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/multitenancy/tenant/user: + post: + summary: Add user tenant association + tags: + - Multitenancy Recipe + description: | + Add user's association with the tenant. + + User will be added to the tenant based on the url prefix of the request. + + Note: To associate a user to a tenant, the tenant must be in the same database + and user must already exist in the app + + operationId: addUserToTenant + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - recipeUserId + properties: + recipeUserId: + $ref: "#/components/schemas/userId" + responses: + 200: + description: Association result + content: + application/json: + schema: + oneOf: + - type: object + required: + - status + - wasAlreadyAssociated + properties: + status: + $ref: "#/components/schemas/statusOK" + wasAlreadyAssociated: + type: boolean + - type: object + required: + - status + properties: + status: + type: string + enum: + [ + "UNKNOWN_USER_ID_ERROR", + "EMAIL_ALREADY_EXISTS_ERROR", + "PHONE_NUMBER_ALREADY_EXISTS_ERROR", + "THIRD_PARTY_USER_ALREADY_EXISTS_ERROR", + ] + - type: object + properties: + status: + type: string + enum: ["ASSOCIATION_NOT_ALLOWED_ERROR"] + reason: + type: string + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/multitenancy/tenant/user/remove: + post: + summary: Remove user tenant association + tags: + - Multitenancy Recipe + description: | + Remove user's association with the tenant + + User will be removed from the tenant based on the url prefix of the request. + + operationId: removeUserFromTenant + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/multitenancyRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - recipeUserId + properties: + recipeUserId: + $ref: "#/components/schemas/userId" + + responses: + 200: + description: Disassociation result + content: + application/json: + schema: + type: object + required: + - status + - wasAssociated + properties: + status: + $ref: "#/components/schemas/statusOK" + wasAssociated: + type: boolean + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/recipe/oauth/clients: + get: + summary: Get OAuth2 Client + tags: + - OAuth2Provider Recipe + description: | + Get OAuth2 Client + operationId: getOAuth2Client + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + - name: clientId + in: query + required: true + schema: + type: string + example: abcd + responses: + "200": + description: OAuth2 Client Result + content: + application/json: + schema: + oneOf: + - allOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - $ref: "#/components/schemas/oauthClient" + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + post: + summary: Create OAuth2 Client + tags: + - OAuth2Provider Recipe + description: | + Create OAuth2 Client + operationId: createOAuth2Client + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/oauthClient" + responses: + "200": + description: OAuth2 Client Result + content: + application/json: + schema: + oneOf: + - allOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - $ref: "#/components/schemas/oauthClient" + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + put: + summary: Update OAuth2 Client + tags: + - OAuth2Provider Recipe + description: | + Update OAuth2 Client + operationId: updateOAuth2Client + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/oauthClient" + responses: + "200": + description: OAuth2 Client Result + content: + application/json: + schema: + oneOf: + - allOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - $ref: "#/components/schemas/oauthClient" + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/clients/list: + get: + summary: List OAuth2 Clients + tags: + - OAuth2Provider Recipe + description: | + List OAuth2 Clients + operationId: listOAuth2Clients + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + - name: pageSize + in: query + required: false + schema: + type: integer + example: 250 + - name: pageToken + in: query + required: false + schema: + type: string + example: "1234567890" + - name: clientName + in: query + required: false + schema: + type: string + example: "My App" + responses: + "200": + description: OAuth2 Client Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + clients: + type: array + items: + $ref: "#/components/schemas/oauthClient" + nextPaginationToken: + type: string + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/clients/remove: + post: + summary: Remove OAuth2 Client + tags: + - OAuth2Provider Recipe + description: | + Remove OAuth2 Client + operationId: removeOAuth2Client + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + clientId: + type: string + example: "stcl_c6dd9189-33b8-4ec0-8aea-a0ffdaf75fcb" + responses: + "200": + description: OAuth2 Client Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + didExist: + type: boolean + example: true + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/auth/requests/consent: + get: + summary: Get OAuth2 Consent Request + tags: + - OAuth2Provider Recipe + description: | + Get OAuth2 Consent Request + operationId: getOAuth2ConsentRequest + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + - name: consentChallenge + in: query + required: true + schema: + type: string + example: "1234567890" + responses: + "200": + description: OAuth2 Consent Request Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + client: + $ref: "#/components/schemas/oauthClient" + requestedScope: + type: array + items: + type: string + requestedAudience: + type: array + items: + type: string + requestedClaims: + type: object + properties: + idToken: + type: object + properties: + property1: + type: string + property2: + type: string + loginHint: + type: string + uiLocales: + type: array + items: + type: string + acrValues: + type: array + items: + type: string + subject: + type: string + requestUrl: + type: string + skip: + type: boolean + clientId: + type: string + redirectUri: + type: string + forceSubjectIdentifier: + type: string + requestedAccessTokenAudience: + type: array + items: + type: string + context: + type: object + sessionId: + type: string + loginSessionId: + type: string + loginChallenge: + type: string + loginRequestedAt: + type: string + consentRequestedAt: + type: string + consentChallenge: + type: string + consentSkip: + type: boolean + consentRemember: + type: boolean + consentRememberFor: + type: integer + consentError: + type: object + properties: + name: + type: string + description: + type: string + consentErrorDebug: + type: string + consentErrorDescription: + type: string + consentErrorHint: + type: string + consentErrorCode: + type: string + consentStatusCode: + type: integer + sessionIdToken: + type: object + properties: + property1: + type: string + property2: + type: string + sessionAccessToken: + type: object + properties: + property1: + type: string + property2: + type: string + sessionToken: + type: object + properties: + property1: + type: string + property2: + type: string + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/auth/requests/consent/accept: + put: + summary: Accept OAuth2 Consent Request + tags: + - OAuth2Provider Recipe + description: | + Accept OAuth2 Consent Request + operationId: acceptOAuth2ConsentRequest + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + - name: consentChallenge + in: query + required: true + schema: + type: string + example: "1234567890" + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + type: object + grantAccessTokenAudience: + type: array + items: + type: string + grantScope: + type: array + items: + type: string + handledAt: + type: string + format: date-time + example: "2019-08-24T14:15:22Z" + remember: + type: boolean + rememberFor: + type: integer + session: + type: object + properties: + accessToken: + type: object + additionalProperties: true + idToken: + type: object + additionalProperties: true + responses: + "200": + description: OAuth2 Consent Request Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + redirectTo: + type: string + example: "{apiDomain}/oauth/consent?..." + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/auth/requests/consent/reject: + put: + summary: Reject OAuth2 Consent Request + tags: + - OAuth2Provider Recipe + description: | + Reject OAuth2 Consent Request + operationId: rejectOAuth2ConsentRequest + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + - name: consentChallenge + in: query + required: true + schema: + type: string + example: "1234567890" + requestBody: + content: + application/json: + schema: + type: object + properties: + error: + type: string + errorDebug: + type: string + errorDescription: + type: string + errorHint: + type: string + statusCode: + type: integer + example: 400 + + responses: + "200": + description: OAuth2 Consent Request Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + redirectTo: + type: string + example: "{apiDomain}/oauth/consent?..." + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/auth/requests/login: + get: + summary: Get OAuth2 Login Request + tags: + - OAuth2Provider Recipe + description: | + Get OAuth2 Login Request + operationId: getOAuth2LoginRequest + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + - name: loginChallenge + in: query + required: true + schema: + type: string + example: "1234567890" + responses: + "200": + description: OAuth2 Login Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + challenge: + type: string + client: + $ref: "#/components/schemas/oauthClient" + oidcContext: + type: object + properties: + acrValues: + type: array + items: + type: string + display: + type: string + idTokenHintClaims: + type: object + loginHint: + type: string + uiLocales: + type: array + items: + type: string + requestUrl: + type: string + requestedAccessTokenAudience: + type: array + items: + type: string + requestedScope: + type: array + items: + type: string + sessionId: + type: string + skip: + type: boolean + subject: + type: string + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/auth/requests/login/accept: + put: + summary: Accept OAuth2 Login Request + tags: + - OAuth2Provider Recipe + description: | + Accept OAuth2 Login Request + operationId: acceptOAuth2LoginRequest + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + - name: loginChallenge + in: query + required: true + schema: + type: string + example: "1234567890" + requestBody: + content: + application/json: + schema: + type: object + required: + - subject + properties: + acr: + type: string + amr: + type: array + items: + type: string + context: + type: string + nullable: true + extendSessionLifespan: + type: boolean + example: true + forceSubjectIdentifier: + type: string + identityProviderSessionId: + type: string + remember: + type: boolean + example: true + rememberFor: + type: integer + example: 0 + subject: + type: string + + responses: + "200": + description: OAuth2 Login Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + redirectTo: + type: string + example: "{apiDomain}/oauth/login?..." + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/auth/requests/login/reject: + put: + summary: Reject OAuth2 Login Request + tags: + - OAuth2Provider Recipe + description: | + Reject OAuth2 Login Request + operationId: rejectOAuth2LoginRequest + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + - name: loginChallenge + in: query + required: true + schema: + type: string + example: "1234567890" + requestBody: + content: + application/json: + schema: + type: object + properties: + error: + type: string + errorDebug: + type: string + errorDescription: + type: string + errorHint: + type: string + statusCode: + type: integer + example: 0 + responses: + "200": + description: OAuth2 Login Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + redirectTo: + type: string + example: "{apiDomain}/oauth/login?..." + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/auth/requests/logout/accept: + put: + summary: Accept OAuth2 Logout Request + tags: + - OAuth2Provider Recipe + description: | + Accept OAuth2 Logout Request + operationId: acceptOAuth2LogoutRequest + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + challenge: + type: string + responses: + "200": + description: OAuth2 Logout Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + redirectTo: + type: string + example: "{apiDomain}/oauth/logout?..." + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/auth/requests/logout/reject: + put: + summary: Reject OAuth2 Logout Request + tags: + - OAuth2Provider Recipe + description: | + Reject OAuth2 Logout Request + operationId: rejectOAuth2LogoutRequest + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + challenge: + type: string + responses: + "200": + description: OAuth2 Logout Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/session/revoke: + post: + summary: Revoke OAuth2 Session + tags: + - OAuth2Provider Recipe + description: | + Revoke OAuth2 Session + operationId: revokeOAuth2Session + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + sessionHandle: + type: string + responses: + "200": + description: OAuth2 Session Revocation Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + didExist: + type: boolean + example: true + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/token/revoke: + post: + summary: Revoke OAuth2 Token + tags: + - OAuth2Provider Recipe + description: | + Revoke OAuth2 Token + operationId: revokeOAuth2Token + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + token: + type: string + responses: + "200": + description: OAuth2 Token Revocation Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + didExist: + type: boolean + example: true + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/tokens/revoke: + post: + summary: Revoke OAuth2 Token + tags: + - OAuth2Provider Recipe + description: | + Revoke OAuth2 Token + operationId: revokeOAuth2Tokens + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + client_id: + type: string + example: "stcl_fed7cff0-cc6e-406e-b7a6-766148675a4a" + responses: + "200": + description: OAuth2 Token Revocation Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + didExist: + type: boolean + example: true + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/auth: + get: + summary: Get OAuth2 Auth + tags: + - OAuth2Provider Recipe + description: | + Get OAuth2 Auth + operationId: getOAuth2Auth + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + responses: + "200": + description: OAuth2 Auth Result + content: + application/json: + schema: + oneOf: + - allOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - $ref: "#/components/schemas/oauthClient" + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/token: + post: + summary: Get OAuth2 Token + tags: + - OAuth2Provider Recipe + description: | + Get OAuth2 Token + operationId: getOAuth2Token + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + iss: + type: string + example: "https://api.auth.com" + inputBody: + type: object + example: {} + useStaticSigningKey: + type: boolean + example: false + authorizationHeader: + type: string + example: "Bearer 1234567890" + responses: + "200": + description: OAuth2 Token Result + content: + application/json: + schema: + oneOf: + - type: object + required: + - status + - access_token + properties: + status: + $ref: "#/components/schemas/statusOK" + access_token: + type: string + example: "eyJraWQiOiJzLTBjZmVmMDdkLWQ2NDktNGIwOC04MTVjLWJkYjZlYTczNWQyZCIsInR5cCI6IkpXVCIsImFsZyI6IlJTMjU2In0.eyJpYXQiOjE3NDAzODU5MzcsImV4cCI6MTc0MDM4OTUzOCwiY2xpZW50X2lkIjoic3RjbF82NWUwODc1Mi0yYzU5LTQ5NjQtOTM0Yy02OTIwZDJmMDZlNjIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMwMDEvYXV0aCIsImp0aSI6Ijc1NTc2MmFmLTUwYTUtNDc1ZS04YWRkLTg3MDA1ZmU3YWJlNiIsIm5iZiI6MTc0MDM4NTkzNywic2NwIjpbIm9wZW5pZCIsIm9mZmxpbmVfYWNjZXNzIl0sInN1YiI6InNvbWV1c2VyaWQiLCJzdHQiOjEsImdpZCI6ImRjOGQ0OGUzLTcwOTgtNDhhNi1hYjU0LTgxMWMyODQ4N2I4MiIsInRJZCI6InB1YmxpYyIsInJzdWIiOiJzb21ldXNlcmlkIiwic2Vzc2lvbkhhbmRsZSI6InNlc3Npb24taGFuZGxlIn0.DgVgtD2gXgzHrDsC2lIUBa-wsYm8KO4Pg8L1Ov3aSBVgjwtjiCO40ldjBZ9qKdQBq5Qqk0ElAZNj6Bzc40ESfQumLH3_N2XtOj568s71JPuEOIg5hs9XAdK4vYfXMhVQRWn9iPUKHKrpRVf73IIH0mpkN8i6_MhcDoMMOuG5XPlXajG9VOyoY_5saHA61-uTafZLdAgKqnmYGvS8KmNEcEbBWLGwFB4QQKiDAUvatIi5n3juFBUxyt9t6DrqT1D04shesRppa0XhCZbCFBv1dixSrprdtqKhlPOrMgvOGNZ3cBLbYBOG9zoJRD5YlVMGw-j_pE7IbvpDWKL7tTJS1Q" + expires_in: + type: integer + example: 3599 + id_token: + type: string + example: "eyJraWQiOiJzLTBjZmVmMDdkLWQ2NDktNGIwOC04MTVjLWJkYjZlYTczNWQyZCIsInR5cCI6IkpXVCIsImFsZyI6IlJTMjU2In0.eyJpYXQiOjE3NDAzODU5MzgsImV4cCI6MTc0MDM4OTUzOCwiYXRfaGFzaCI6IkNxOGNCSk01Nm5FcG9aaWREcnZvLVEiLCJhdWQiOiJzdGNsXzY1ZTA4NzUyLTJjNTktNDk2NC05MzRjLTY5MjBkMmYwNmU2MiIsImF1dGhfdGltZSI6MTc0MDM4NTkzNywiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDozMDAxL2F1dGgiLCJqdGkiOiIxZDA5OGUxZi04ZGIxLTQyNzUtYmMzYS0zYTA4NjdjOWE2NTAiLCJyYXQiOjE3NDAzODU3MzEsInNpZCI6InNlc3Npb24taGFuZGxlIiwic3ViIjoic29tZXVzZXJpZCIsInN0dCI6MiwiZ2lkIjoiYzk1OTVjYjItMWFjOS00MDI0LWFjNjMtNDJlZDEyODliY2RmIn0.PGsemf1qpLF-cE_616NHvKsRmanFiyba0yqF2j5fy87AWD5McI405A4eqi-wAlKsDxC-MPpuW8bx-08YUhs3x6ku4aFaDyA-M-Xhc65fJJ4SCPVaUL7qlUwl7wJwNs2rMRW3Ayyj4MDSlW5uqm39_K_bBqod2Qj1yqck-N0g78qh86uEcyX6Al3d5KSln1B21nwDsEgegk3xzE8lFMCQUTpZEYb5-1v2D0Bu_PblBfOCjA6mBtT1IIQkmSE27FvkTUS1H50EUyhFP4JH30kP3bUnQ9pOqGMTe405N2ruKtPyWsXHLPlQ4hcJCLO5GT5ZgtUjfz6Y3mCM9l69uDYDHg" + refresh_token: + type: string + example: "st_rt_d7LI9mGYHF2TAaVEFJi7fqOWo8ZQ8zEGpuxhHQs0R18.UZ0nbTuuYuDD8G54PCD8AKHdsh9cezu8BTxVlTy7pYw" + scope: + type: string + example: "openid offline_access" + token_type: + type: string + example: "bearer" + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/sessions/logout: + get: + summary: Get OAuth2 Sessions Logout + tags: + - OAuth2Provider Recipe + description: | + Get OAuth2 Sessions Logout + operationId: getOAuth2SessionsLogout + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + - name: clientId + in: query + required: false + schema: + type: string + example: "stcl_fed7cff0-cc6e-406e-b7a6-766148675a4a" + - name: idTokenHint + in: query + required: false + schema: + type: string + - name: postLogoutRedirectUri + in: query + required: false + schema: + type: string + - name: state + in: query + required: false + schema: + type: string + responses: + "200": + description: OAuth2 Sessions Logout Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + redirectTo: + type: string + example: "{apiDomain}/oauth/logout?..." + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + /appid-{appId}/recipe/oauth/introspect: + post: + summary: Introspect OAuth2 Token + tags: + - OAuth2Provider Recipe + description: | + Introspect OAuth2 Token + operationId: introspectOAuth2Token + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/oauthRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - token + properties: + token: + type: string + responses: + "200": + description: OAuth2 Token Introspection Result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + active: + type: boolean + iat: + type: integer + example: 1740992368 + exp: + type: integer + example: 1740995969 + client_id: + type: string + example: "stcl_fed7cff0-cc6e-406e-b7a6-766148675a4a" + iss: + type: string + example: "http://localhost:3001/auth" + jti: + type: string + example: "1c229efe-c55b-44c1-98cf-9fa3a366502e" + nbf: + type: integer + example: 1740992368 + scp: + type: array + items: + type: string + example: ["openid", "offline_access"] + sub: + type: string + example: "137d053d-0d69-4dea-8a19-06ddbdfa4f96" + stt: + type: integer + example: 1 + sessionHandle: + type: string + example: "87bcc2d8-f159-4e10-a097-0898179a2d7d" + rsub: + type: string + example: "137d053d-0d69-4dea-8a19-06ddbdfa4f96" + tId: + type: string + example: "public" + gid: + type: string + example: "575b7130-d982-4945-be49-3ecde2a49eaa" + token_type: + type: string + example: "Bearer" + token_use: + type: string + example: "access_token" + - $ref: "#/components/schemas/oauthError" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "402": + $ref: "#/components/responses/402" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/bulk-import/users: + get: + summary: List bulk import users + tags: + - Bulk Import + operationId: getBulkImportUsers + description: | + Paginated API to get bulk import users + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/paginationToken" + - $ref: "#/components/parameters/limit" + - $ref: "#/components/parameters/bulkImportUserStatus" + + responses: + "200": + description: Paginated Bulk Import Users + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + users: + type: array + items: + $ref: "#/components/schemas/bulkImportUserResponse" + nextPaginationToken: + $ref: "#/components/schemas/paginationToken" + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + post: + summary: Add bulk import users + tags: + - Bulk Import + operationId: addBulkImportUsers + description: | + Add users for bulk import. Maximum 10000 users can be added in one request. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + users: + type: array + items: + $ref: "#/components/schemas/bulkImportUser" + required: + - users + responses: + "200": + description: Bulk Import Users added successfully + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + users: + $ref: "#/components/schemas/addBulkImportUserResponse" + "400": + description: One or more users have invalid schema + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Data has missing or invalid fields. Please check the users field for more details." + users: + type: array + items: + type: object + properties: + index: + type: number + example: 0 + description: "Index of the user in the users array that has invalid schema" + errors: + type: array + items: + type: string + description: "List of errors for the user" + example: "Invalid recipeId for loginMethod. Pass one of emailpassword, thirdparty or, passwordless!" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/bulk-import/users/remove: + post: + summary: Delete bulk import users + tags: + - Bulk Import + operationId: deleteBulkImportUsers + description: | + Delete bulk import users by id. Multiple ids can be passed in the request body. + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + properties: + ids: + type: array + description: List of bulk import user ids to be deleted + items: + $ref: "#/components/schemas/bulkImportUserId" + required: + - ids + responses: + "200": + description: Bulk Import Users deleted successfully + content: + application/json: + schema: + type: object + properties: + deletedIds: + type: array + description: List of ids that were successfully deleted + items: + $ref: "#/components/schemas/bulkImportUserId" + invalidIds: + type: array + description: List of ids that were invalid + items: + $ref: "#/components/schemas/bulkImportUserId" + example: [] + + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-/bulk-import/users/count: + get: + tags: + - Bulk Import + operationId: countBulkImportUsers + security: + - ApiKey: [] + summary: Count bulk import users + description: | + Count users in the bulk import processing queue, by status or all of them (by passing `null` status). + parameters: + - $ref: "#/components/parameters/api-key" + - $ref: "#/components/parameters/cdi-version" + - $ref: "#/components/parameters/bulkImportUserStatus" + responses: + "200": + description: The number of users in the bulk import processing queue by status + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + count: + type: number + description: The number of users in the bulk import processing queue by status + example: 10 + "400": + $ref: "#/components/responses/400" + + "401": + $ref: "#/components/responses/401" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /appid-/bulk-import/import: + post: + tags: + - Bulk Import + operationId: importOneUserWithBulkImport + security: + - ApiKey: [] + summary: Import one user directly + description: | + Import one user immediately with the Bulk Import functionality. + parameters: + - $ref: "#/components/parameters/api-key" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + $ref: "#/components/schemas/bulkImportUser" + responses: + "200": + description: User added successfully + content: + application/json: + schema: + type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/authRecipeUser" + "400": + description: User has invalid schema + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Data has missing or invalid fields. Please check the users field for more details." + users: + type: array + items: + type: object + properties: + index: + type: number + example: 0 + description: "Index of the user in the users array that has invalid schema" + errors: + type: array + items: + type: string + description: "List of errors for the user" + example: "Invalid recipeId for loginMethod. Pass one of emailpassword, thirdparty or, passwordless!" + + /appid-{appId}/{tenantId}/recipe/webauthn/user/credential: + get: + summary: Get WebAuthn credential + tags: + - WebAuthn Recipe + description: Get the WebAuthn credential for the user. + + operationId: getWebAuthNCredential + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: recipeUserId + schema: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + required: true + - in: query + name: webauthnCredentialId + schema: + type: string + example: ea7a0931-b533-4478-9253-0fde890ca23 + required: true + responses: + "200": + description: WebAuthn credential result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + credential: + type: object + properties: + webauthnCredentialId: + type: string + example: ea7a0931-b533-4478-9253-0fde890ca23 + recipeUserId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + relyingPartyId: + type: string + example: example.com + createdAt: + type: number + example: 1741793746 + updatedAt: + type: number + example: 1741793746 + - type: object + properties: + status: + type: string + enum: ["CREDENTIAL_NOT_FOUND_ERROR"] + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/user/credential/list: + get: + summary: List WebAuthn credentials + tags: + - WebAuthn Recipe + description: List credentials that were created by the user. + operationId: listWebAuthNCredentials + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: recipeUserId + schema: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + required: true + responses: + "200": + description: WebAuthn credentials list result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + credentials: + type: array + items: + type: object + properties: + webauthnCredentialId: + type: string + example: ea7a0931-b533-4478-9253-0fde890ca23 + recipeUserId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + relyingPartyId: + type: string + example: example.com + createdAt: + type: number + example: 1741793746 + updatedAt: + type: number + example: 1741793746 + + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/options: + get: + summary: Get WebAuthn options + tags: + - WebAuthn Recipe + description: Get the WebAuthn options. + operationId: getWebAuthNOptions + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: webauthnGeneratedOptionsId + schema: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + required: true + responses: + "200": + description: WebAuthn options result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + webauthnGeneratedOptionsId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + relyingPartyId: + type: string + example: example.com + relyingPartyName: + type: string + example: Example + challenge: + type: string + example: TQvEVDV8B64w_2zIifzKaPzBPfthqpx2uJkq_2PIB0k + timeout: + type: number + example: 10000 + origin: + type: string + example: http://example.com + email: + type: string + example: email@example.com + userVerification: + type: string + example: required + userPresence: + type: boolean + example: true + createdAt: + type: number + example: 1741793746 + expiresAt: + type: number + example: 1741793746 + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/user/recover: + get: + summary: Recover WebAuthn user + tags: + - WebAuthn Recipe + description: Recover the user using the WebAuthn credential. + operationId: recoverWebAuthNUser + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: token + schema: + type: string + example: ZmE3YTA4NDEtYjUzMy00NDc4LTkyNTMtMGZkZTg5MGM1NzY + required: true + responses: + "200": + description: AuthRecipeUser for the token + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + recipeUserId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + user: + $ref: "#/components/schemas/authRecipeUser" + - type: object + properties: + status: + type: string + enum: ["RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"] + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/options/register: + post: + summary: Generate registration options + tags: + - WebAuthn Recipe + description: Generate the webauthn options for registration. + operationId: generateRegistrationOptions + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - email + - relyingPartyId + - relyingPartyName + - origin + properties: + email: + $ref: "#/components/schemas/email" + displayName: + type: string + example: John Doe + relyingPartyId: + type: string + example: example.com + relyingPartyName: + type: string + example: Example + origin: + type: string + example: http://example.com + timeout: + type: number + example: 10000 + userVerification: + type: string + example: preferred + userPresence: + type: boolean + example: false + attestation: + type: string + example: none + residentKey: + type: string + example: required + supportedAlgorithmIDs: + type: array + items: + type: number + example: -7 + responses: + "200": + description: The generated register options response + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + webauthnGeneratedOptionsId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + rp: + type: object + properties: + id: + type: string + example: example.com + name: + type: string + example: Example + user: + type: object + properties: + id: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + name: + type: string + example: John Doe + displayName: + type: string + example: John Doe + email: + $ref: "#/components/schemas/email" + challenge: + type: string + example: TQvEVDV8B64w_2zIifzKaPzBPfthqpx2uJkq_2PIB0k + timeout: + type: number + example: 10000 + attestation: + type: string + example: none + createdAt: + type: number + example: 1741793746 + expiresAt: + type: number + example: 1741793746 + pubKeyCredParams: + type: array + items: + type: object + properties: + type: + type: string + example: public-key + alg: + type: number + example: -7 + excludeCredentials: + type: array + items: + type: object + properties: + id: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + transport: + type: array + items: + type: string + example: internal + authenticatorSelection: + type: object + properties: + userVerification: + type: string + example: preferred + requireResidentKey: + type: boolean + example: true + - type: object + properties: + status: + type: string + enum: ["INVALID_OPTIONS_ERROR"] + reason: + type: string + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/options/signin: + post: + summary: Generate authentication options + tags: + - WebAuthn Recipe + description: Generate the webauthn options for signin. + operationId: generateSigninOptions + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - relyingPartyId + - relyingPartyName + - origin + - timeout + - userVerification + - userPresence + properties: + relyingPartyId: + type: string + example: example.com + relyingPartyName: + type: string + example: Example + origin: + type: string + example: http://example.com + timeout: + type: number + example: 10000 + userVerification: + type: string + example: preferred + userPresence: + type: boolean + example: false + responses: + "200": + description: AuthRecipeUser for the token + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + webauthnGeneratedOptionsId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + relyingPartyId: + type: string + example: example.com + challenge: + type: string + example: TQvEVDV8B64w_2zIifzKaPzBPfthqpx2uJkq_2PIB0k + timeout: + type: number + example: 10000 + userVerification: + type: string + example: required + userPresence: + type: boolean + example: true + createdAt: + type: number + example: 1741793746 + expiresAt: + type: number + example: 1741793746 + - type: object + properties: + status: + type: string + enum: ["INVALID_OPTIONS_ERROR"] + reason: + type: string + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/user/credential/register: + post: + summary: Register WebAuthn credential + tags: + - WebAuthn Recipe + description: Register a new credential for the user + operationId: registerWebAuthNCredential + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - email + properties: + recipeUserId: + $ref: "#/components/schemas/userId" + webauthnGeneratedOptionsId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + credential: + type: object + description: Credential returned by the browser + responses: + "200": + description: The stored credential + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + webauthnCredentialId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + relyingPartyId: + type: string + example: example.com + relyingPartyName: + type: string + example: Example + recipeUserId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + email: + $ref: "#/components/schemas/email" + - type: object + properties: + status: + type: string + enum: ["INVALID_OPTIONS_ERROR", "INVALID_AUTHENTICATOR_ERROR", "INVALID_CREDENTIALS_ERROR"] + reason: + type: string + - type: object + properties: + status: + type: string + enum: ["OPTIONS_NOT_FOUND_ERROR", "CREDENTIAL_ALREADY_EXISTS_ERROR", "UNKNOWN_USER_ID_ERROR"] + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/signup: + post: + summary: Sign up WebAuthn user + tags: + - WebAuthn Recipe + description: Sign up the user using the WebAuthn credential. + operationId: signUpWebAuthNUser + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - email + properties: + webauthnGeneratedOptionsId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + credential: + type: object + description: Credential returned by the browser + responses: + "200": + description: The signup result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + webauthnCredentialId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + relyingPartyId: + type: string + example: example.com + relyingPartyName: + type: string + example: Example + recipeUserId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + user: + $ref: "#/components/schemas/authRecipeUser" + - type: object + properties: + status: + type: string + enum: ["INVALID_OPTIONS_ERROR", "INVALID_AUTHENTICATOR_ERROR", "INVALID_CREDENTIALS_ERROR"] + reason: + type: string + - type: object + properties: + status: + type: string + enum: ["OPTIONS_NOT_FOUND_ERROR", "EMAIL_ALREADY_EXISTS_ERROR"] + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/signin: + post: + summary: Sign in WebAuthn user + tags: + - WebAuthn Recipe + description: Sign in the user using the WebAuthn credential. + operationId: signInWebAuthNUser + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - email + properties: + webauthnGeneratedOptionsId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + credential: + type: object + description: Credential returned by the browser + responses: + "200": + description: The stored credential + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + recipeUserId: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + user: + $ref: "#/components/schemas/authRecipeUser" + - type: object + properties: + status: + type: string + enum: ["INVALID_OPTIONS_ERROR", "INVALID_AUTHENTICATOR_ERROR", "INVALID_CREDENTIALS_ERROR"] + reason: + type: string + - type: object + properties: + status: + type: string + enum: ["OPTIONS_NOT_FOUND_ERROR", "CREDENTIAL_NOT_FOUND_ERROR", "UNKNOWN_USER_ID_ERROR"] + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/user/recover/token: + post: + summary: Generate recovery token + tags: + - WebAuthn Recipe + description: Generate a token to recover the user. + operationId: generateTokenForRecovery + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - userId + - email + properties: + userId: + $ref: "#/components/schemas/userId" + email: + $ref: "#/components/schemas/email" + responses: + "200": + description: WebAuthn options result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + token: + type: string + example: ZmE3YTA4NDEtYjUzMy00NDc4LTkyNTMtMGZkZTg5MGM1NzY + - type: object + properties: + status: + type: string + enum: ["UNKNOWN_USER_ID_ERROR"] + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/user/recover/token/consume: + post: + summary: Consume recovery token + tags: + - WebAuthn Recipe + description: Consume the token to recover the user. + operationId: consumeWebAuthNToken + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - token + properties: + token: + type: string + example: ZmE3YTA4NDEtYjUzMy00NDc4LTkyNTMtMGZkZTg5MGM1NzY + responses: + "200": + description: Consume token result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + userId: + $ref: "#/components/schemas/userId" + email: + $ref: "#/components/schemas/email" + - type: object + properties: + status: + type: string + enum: ["RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"] + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/user/email: + put: + summary: Update email + tags: + - WebAuthn Recipe + description: Update the email of the user. + operationId: updateEmail + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + requestBody: + content: + application/json: + schema: + type: object + required: + - recipeUserId + - email + properties: + recipeUserId: + $ref: "#/components/schemas/userId" + email: + $ref: "#/components/schemas/email" + responses: + "200": + description: Update email result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - type: object + properties: + status: + type: string + enum: + [ + "UNKNOWN_USER_ID_ERROR", + "EMAIL_ALREADY_EXISTS_ERROR", + "USER_WITH_EMAIL_ALREADY_EXISTS_ERROR", + ] + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/user/credential/remove: + delete: + summary: Remove WebAuthn credential + tags: + - WebAuthn Recipe + description: Remove the WebAuthn credential for the user. + operationId: removeWebAuthNCredential + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: recipeUserId + schema: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + required: true + - in: query + name: webauthnCredentialId + schema: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + required: true + responses: + "200": + description: Delete credential result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - type: object + properties: + status: + type: string + enum: ["CREDENTIAL_NOT_FOUND_ERROR"] + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /appid-{appId}/{tenantId}/recipe/webauthn/options/remove: + delete: + summary: Remove WebAuthn options + tags: + - WebAuthn Recipe + description: Remove the WebAuthn options. + operationId: removeWebAuthNOptions + security: + - ApiKey: [] + parameters: + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/cdi-version" + - in: query + name: webauthnGeneratedOptionsId + schema: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + required: true + responses: + "200": + description: Delete options result + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - type: object + properties: + status: + type: string + enum: ["OPTIONS_NOT_FOUND_ERROR"] + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + +components: + parameters: + tenantId: + name: tenantId + in: path + description: The tenant against which the request is made. If left empty, the default tenant will be used. + required: false + schema: + type: string + example: public + + rid: + name: rid + in: header + example: emailpassword + required: false + schema: + type: string + + thirdPartyRid: + name: rid + in: header + example: thirdparty + required: false + schema: + type: string + + passwordlessRid: + name: rid + in: header + example: passwordless + required: false + schema: + type: string + + emailVerificationRid: + name: rid + in: header + example: emailverification + required: false + schema: + type: string + + multitenancyRid: + name: rid + in: header + example: multitenancy + required: false + schema: + type: string + + userMetadataRid: + name: rid + in: header + example: usermetadata + required: false + schema: + type: string + + userRolesRid: + name: rid + in: header + example: userroles + required: false + schema: + type: string + + sessionRid: + name: rid + in: header + example: session + required: false + schema: + type: string + + jwtRID: + name: rid + in: header + example: jwt + required: false + schema: + type: string + + userIdMappingRid: + name: rid + in: header + example: useridmapping + required: false + schema: + type: string + + dashboardRid: + name: rid + in: header + example: dashboard + required: false + schema: + type: string + + totpRid: + name: rid + in: header + example: totp + required: false + schema: + type: string + + accountLinkingRid: + name: rid + in: header + example: accountlinking + required: false + schema: + type: string + + cdi-version: + name: cdi-version + in: header + description: X.Y of the X.Y.Z CDI version. + example: "5.1" + schema: + type: string + + paginationToken: + name: paginationToken + in: query + example: ZmE3YTA4NDEtY...MjM5MTgwMzIyMzE= + schema: + type: string + + limit: + name: limit + in: query + example: 1 + schema: + type: number + + timeJoinedOrder: + name: timeJoinedOrder + in: query + schema: + type: string + enum: ["ASC", "DESC"] + + email: + name: email + in: query + required: false + schema: + type: string + example: johndoe@gmail.com + + userId: + name: userId + in: query + required: false + schema: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + + userIdRequired: + name: userId + in: query + required: true + schema: + type: string + example: fa7a0841-b533-4478-9253-0fde890c576 + + roleRequired: + name: role + in: query + required: true + schema: + type: string + example: admin + + permissionRequired: + name: permission + in: query + required: true + schema: + type: string + example: permission + + includeRecipeIds: + name: includeRecipeIds + in: query + required: false + description: The param should take an array of comma seperated strings + schema: + type: string + example: val1,val2,val3.. + + responses: + 500: + description: error code 500 + content: + text/plain: + schema: + $ref: "#/components/schemas/internalError" + 404: + description: error code 404 + content: + text/plain: + schema: + $ref: "#/components/schemas/notFound" + 405: + description: error code 405 + content: + text/plain: + schema: + $ref: "#/components/schemas/methodNotSupported" + 400: + description: error code 400 + content: + text/plain: + schema: + $ref: "#/components/schemas/invalidJSON" + 401: + description: error code 401 + content: + text/plain: + schema: + $ref: "#/components/schemas/requestUnauthorised" + + 402: + description: error code 402 + content: + text/plain: + schema: + $ref: "#/components/schemas/licenseError" + + hello: + description: return a simple hello message + content: + application/json: + schema: + $ref: "#/components/schemas/helloResponse" + schemas: + authRecipeUser: + type: object + properties: + id: + $ref: "#/components/schemas/userId" + isPrimaryUser: + type: boolean + example: true + tenantIds: + type: array + items: + $ref: "#/components/schemas/tenantId" + timeJoined: + $ref: "#/components/schemas/timeJoined" + emails: + type: array + items: + $ref: "#/components/schemas/email" + phoneNumbers: + type: array + items: + $ref: "#/components/schemas/phoneNumber" + thirdParty: + type: array + items: + type: object + properties: + id: + $ref: "#/components/schemas/thirdPartyId" + userId: + $ref: "#/components/schemas/thirdPartyUserId" + loginMethods: + type: array + items: + type: object + properties: + tenantIds: + type: array + items: + $ref: "#/components/schemas/tenantId" + recipeUserId: + $ref: "#/components/schemas/userId" + verified: + type: boolean + example: true + timeJoined: + $ref: "#/components/schemas/timeJoined" + recipeId: + $ref: "#/components/schemas/recipeId" + email: + $ref: "#/components/schemas/email" + phoneNumber: + $ref: "#/components/schemas/phoneNumber" + thirdParty: + type: object + properties: + id: + $ref: "#/components/schemas/thirdPartyId" + userId: + $ref: "#/components/schemas/thirdPartyUserId" + + recipeId: + type: string + enum: + - emailpassword + - passwordless + - thirdparty + token: + type: string + example: ZTRiOTBjNz...jI5MTZlODkxw + + emailVerificationVerifyTokenRequest: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + email: + $ref: "#/components/schemas/email" + + thirdPartyId: + type: string + example: google + + thirdPartyUserId: + type: string + example: 106347997792363865062 + + thirdPartyEmail: + type: object + properties: + id: + $ref: "#/components/schemas/email" + isVerified: + $ref: "#/components/schemas/isVerified" + + isVerified: + type: boolean + example: true + + email: + type: string + example: johndoe@gmail.com + + password: + type: string + example: password123 + + userId: + type: string + example: fa7a0841-b533-4478-95533-0fde890c3483 + + role: + type: string + example: admin + + timeJoined: + type: number + example: 1623918032231 + + paginationToken: + type: string + example: ZmE3YTA4ND...OzE2MjM5MTgwMzIyMzE= + + phoneNumber: + type: string + example: "+14155552671" + + codeId: + type: string + description: Uniquely identifies a code + example: QZ0Mx9zG9cfqNXmPI0I/67r9bpKghUBDQZeMMbayi+I= + + deviceId: + type: string + description: A random identifier that should be stored on the device that started the sign in process. + example: TU/52WOcktSv99zqaAZuWJG9BSoS0aRLfCbep8rFEwk= + + preAuthSessionId: + type: string + description: A random identifier that can be used to identify the login attempt/device. + example: kFmkPQEAJtACiT2w/K8fndEuNm+XozJXSZSlWEr+iGs= + + userInputCode: + type: string + description: This can be used to authenticate the user when paired with the deviceId + example: 456123 + + linkCode: + type: string + description: URL-safe string that can be used to authenticate the user, without the deviceId + example: b10lbT_SnDC4flA6Fn7pE5TtG5k5NfigLef4QMBeGA8 + + codeLifetime: + type: number + description: The maximum lifetime of the code in milliseconds + example: 900000 + + statusOK: + type: string + enum: + - OK + + oauthClient: + type: object + properties: + clientId: + type: string + example: "stcl_c6dd9189-33b8-4ec0-8aea-a0ffdaf75fcb" + clientName: + type: string + example: "Hello" + clientSecret: + type: string + example: "T98n1YIMWqr4wOM.~bV4HOPFmO" + redirectUris: + type: array + items: + type: string + example: ["http://localhost:3000/auth/callback/ory"] + grantTypes: + type: array + items: + type: string + example: ["authorization_code", "refresh_token"] + responseTypes: + type: array + items: + type: string + example: ["code", "id_token"] + scope: + type: string + example: "offline_access openid email" + audience: + type: array + items: + type: string + example: [] + policyUri: + type: string + example: "" + allowedCorsOrigins: + type: array + items: + type: string + example: [] + tosUri: + type: string + example: "" + clientUri: + type: string + example: "" + logoUri: + type: string + example: "" + tokenEndpointAuthMethod: + type: string + example: "client_secret_post" + createdAt: + type: string + format: date-time + example: "2025-02-24T08:14:40Z" + updatedAt: + type: string + format: date-time + example: "2025-02-24T08:14:40.362463Z" + postLogoutRedirectUris: + type: array + items: + type: string + example: ["http://localhost:3000"] + metadata: + type: object + additionalProperties: true + example: {} + authorizationCodeGrantAccessTokenLifespan: + type: string + nullable: true + example: 1h0m0s + authorizationCodeGrantIdTokenLifespan: + type: string + nullable: true + example: 1h0m0s + authorizationCodeGrantRefreshTokenLifespan: + type: string + nullable: true + example: 1h0m0s + clientCredentialsGrantAccessTokenLifespan: + type: string + nullable: true + example: 1h0m0s + implicitGrantAccessTokenLifespan: + type: string + nullable: true + example: 1h0m0s + implicitGrantIdTokenLifespan: + type: string + nullable: true + example: 1h0m0s + refreshTokenGrantIdTokenLifespan: + type: string + nullable: true + example: 1h0m0s + refreshTokenGrantAccessTokenLifespan: + type: string + nullable: true + example: 1h0m0s + refreshTokenGrantRefreshTokenLifespan: + type: string + nullable: true + example: 1h0m0s + enableRefreshTokenRotation: + type: boolean + example: false + + userMetadata: + type: object + description: should be a JSON object (not a JSON literal nor an array) + example: { "preferences": { "theme": "dark" }, "notifications": { "email": true }, "todos": ["example"] } + + userMetadataUpdate: + type: object + description: should be a JSON object (not a JSON literal nor an array) + example: { "notifications": { "sms": true }, "todos": null } + + userDataInJWT: + type: object + description: should be a JSON object (not a JSON literal nor an array) + example: { "test": 123 } + + userDataInDatabase: + type: object + description: should be a JSON object (not a JSON literal nor an array) + example: { "test": 123 } + + enableAntiCsrf: + type: boolean + example: false + + handle: + type: string + example: 68en6gd6-865b-4af6-ba00-96e5c153257d + + message: + type: string + example: Error Message + + session: + type: object + properties: + handle: + $ref: "#/components/schemas/handle" + userId: + $ref: "#/components/schemas/userId" + userDataInJWT: + $ref: "#/components/schemas/userDataInJWT" + tenantId: + $ref: "#/components/schemas/tenantId" + recipeUserId: + $ref: "#/components/schemas/userId" + + cookieInfo: + type: object + properties: + token: + $ref: "#/components/schemas/token" + expiry: + $ref: "#/components/schemas/expiry" + createdTime: + $ref: "#/components/schemas/timeCreated" + + expiry: + type: number + example: 1637262633029 + + timeCreated: + type: number + example: 1637262633029 + + sessionHandles: + type: array + items: + $ref: "#/components/schemas/handle" + + createJWTPayload: + type: object + description: The payload of the JWT, should be a JSON object. + example: { "custom-claim": "" } + + createJWTAlgorithm: + type: string + description: The algorithm to use when creating the JWT. + enum: ["RS256"] + + jwksDomain: + type: string + description: This is used as the value for the issuer claim in the JWT payload. + example: https://api.test.com/ + jwtValidity: + type: number + description: Duration in seconds, used to calculate JWT expiry + example: 86400 + jwk: + type: object + description: A JWK that can be used to verify a JWT + properties: + alg: + $ref: "#/components/schemas/createJWTAlgorithm" + kty: + type: string + example: RSA + use: + type: string + example: sig + kid: + type: string + description: Unique identifier for the JWK + x5c: + type: array + description: X.509 Certificate Chain + items: + type: string + + unauthorisedMessageResponse: + type: object + properties: + status: + $ref: "#/components/schemas/unauthorisedResponse" + message: + $ref: "#/components/schemas/message" + + helloResponse: + type: string + enum: ["Hello"] + + statusOKResponse: + type: object + properties: + status: + type: string + enum: ["OK"] + + wrongCredentialsResponse: + type: object + properties: + status: + type: string + enum: ["WRONG_CREDENTIALS_ERROR"] + + unknownUserIdResponse: + type: object + properties: + status: + type: string + enum: ["UNKNOWN_USER_ID_ERROR"] + + unknownRoleResponse: + type: object + properties: + status: + type: string + enum: ["UNKNOWN_ROLE_ERROR"] + + tokenTheftResponse: + type: string + enum: ["TOKEN_THEFT_DETECTED"] + + unauthorisedResponse: + type: string + enum: ["UNAUTHORISED"] + + tryRefreshTokenResponse: + type: string + enum: ["TRY_REFRESH_TOKEN"] + + internalError: + type: string + enum: + - Internal Error + + notFound: + type: string + enum: + - Not Found + + methodNotSupported: + type: string + enum: + - Method not supported + + invalidJSON: + type: string + + requestUnauthorised: + type: string + enum: + - Invalid API key + + licenseError: + type: string + enum: + - License Error + + tenantId: + type: string + example: "customer1" + + thirdPartyProviderConfig: + type: object + required: + - thirdPartyId + properties: + thirdPartyId: + type: string + name: + type: string + clients: + type: array + items: + type: object + properties: + clientType: + type: string + clientId: + type: string + clientSecret: + type: string + scope: + type: array + items: + type: string + forcePKCE: + type: boolean + additionalConfig: + type: object + authorizationEndpoint: + type: string + authorizationEndpointQueryParams: + type: object + tokenEndpoint: + type: string + tokenEndpointBodyParams: + type: object + userInfoEndpoint: + type: string + userInfoEndpointQueryParams: + type: object + userInfoEndpointHeaders: + type: object + jwksURI: + type: string + oidcDiscoveryEndpoint: + type: string + requireEmail: + type: boolean + default: true + userInfoMap: + type: object + properties: + fromIdTokenPayload: + type: object + properties: + userId: + type: string + email: + type: string + emailVerified: + type: string + fromUserInfoAPI: + type: object + properties: + userId: + type: string + email: + type: string + emailVerified: + type: string + + firstFactors: + type: array + items: + type: string + example: "emailpassword" + requiredSecondaryFactors: + type: array + items: + type: string + example: otp-phone + + tenantInput: + type: object + properties: + emailPasswordEnabled: + type: boolean + thirdPartyEnabled: + type: boolean + passwordlessEnabled: + type: boolean + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + + tenantInputV2: + type: object + properties: + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + + tenantConfig: + type: object + required: + - emailPassword + - thirdParty + - passwordless + - coreConfig + - tenantId + properties: + tenantId: + $ref: "#/components/schemas/tenantId" + emailPassword: + type: object + required: + - enabled + properties: + enabled: + type: boolean + thirdParty: + type: object + required: + - enabled + properties: + enabled: + type: boolean + providers: + type: array + items: + $ref: "#/components/schemas/thirdPartyProviderConfig" + passwordless: + type: object + required: + - enabled + properties: + enabled: + type: boolean + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + + tenantConfigV2: + type: object + required: + - thirdParty + - coreConfig + - tenantId + properties: + tenantId: + $ref: "#/components/schemas/tenantId" + thirdParty: + type: object + properties: + providers: + type: array + items: + $ref: "#/components/schemas/thirdPartyProviderConfig" + firstFactors: + $ref: "#/components/schemas/firstFactors" + requiredSecondaryFactors: + $ref: "#/components/schemas/requiredSecondaryFactors" + coreConfig: + type: object + + passwordHash: + type: string + example: "$argon2d$v=19$m=12,t=3,p=1$aGI4enNvMmd0Zm0wMDAwMA$r6p7qbr6HD+8CD7sBi4HVw" + hashingAlgorithm: + type: string + enum: ["argon2", "bcrypt", "firebase_scrypt"] + + bulkImportUserId: + type: string + example: "fa7a0841-b533-4478-9253-0fde890c576" + + bulkImportUserStatus: + type: string + enum: ["NEW", "PROCESSING", "FAILED"] + + bulkImportUserRole: + type: object + properties: + role: + $ref: "#/components/schemas/role" + tenantIds: + type: array + items: + $ref: "#/components/schemas/tenantId" + required: + - role + - tenantIds + + bulkImportTotpDevice: + type: object + properties: + secretKey: + type: string + example: "2PRXZWZAYYDAWCD" + skew: + type: number + example: 0 + period: + type: number + example: 30 + deviceName: + type: string + example: "My Authy App" + required: + - secretKey + + bulkImportUserLoginMethodFields: + type: object + properties: + tenantIds: + type: array + description: List of tenant IDs this login method is associated with + items: + $ref: "#/components/schemas/tenantId" + isVerified: + type: boolean + description: Indicates whether the email is verified + isPrimary: + type: boolean + description: Indicates whether the login method is the primary login method + timeJoinedInMSSinceEpoch: + type: integer + description: Time joined in milliseconds since the epoch + + bulkImportUserEmailPasswordLoginMethod: + name: Email/Password Login Method + allOf: + - $ref: "#/components/schemas/bulkImportUserLoginMethodFields" + - type: object + properties: + recipeId: + type: string + example: "emailpassword" + email: + $ref: "#/components/schemas/email" + passwordHash: + $ref: "#/components/schemas/passwordHash" + plainTextPassword: + type: string + example: passwordExample + hashingAlgorithm: + $ref: "#/components/schemas/hashingAlgorithm" + required: + - email + - passwordHash + - hashingAlgorithm + + addBulkImportUserLoginMethodResponse: + type: object + properties: + recipeId: + type: string + example: "emailpassword" + userId: + $ref: "#/components/schemas/userId" + tenants: + type: array + items: + $ref: "#/components/schemas/tenantId" + email: + $ref: "#/components/schemas/email" + thirdpartyId: + $ref: "#/components/schemas/thirdPartyId" + thirdpartyUserId: + $ref: "#/components/schemas/thirdPartyUserId" + phoneNumber: + $ref: "#/components/schemas/phoneNumber" + required: + - recipeId + - userId + - tenants + - email + + bulkImportUserThirdPartyLoginMethod: + name: Third Party Login Method + allOf: + - $ref: "#/components/schemas/bulkImportUserLoginMethodFields" + - type: object + properties: + recipeId: + type: string + example: "thirdparty" + thirdPartyId: + $ref: "#/components/schemas/thirdPartyId" + thirdPartyUserId: + $ref: "#/components/schemas/thirdPartyUserId" + required: + - thirdPartyId + - thirdPartyUserId + + bulkImportUserPasswordlessLoginMethod: + name: Passwordless Login Method + allOf: + - $ref: "#/components/schemas/bulkImportUserLoginMethodFields" + - type: object + properties: + recipeId: + type: string + example: "passwordless" + oneOf: + - $ref: "#/components/schemas/email" + - $ref: "#/components/schemas/phoneNumber" + + bulkImportUser: + type: object + properties: + externalUserId: + $ref: "#/components/schemas/userId" + userMetadata: + type: array + items: + $ref: "#/components/schemas/userMetadata" + userRoles: + type: array + items: + $ref: "#/components/schemas/bulkImportUserRole" + totpDevices: + type: array + items: + $ref: "#/components/schemas/bulkImportTotpDevice" + loginMethods: + type: array + items: + anyOf: + - $ref: "#/components/schemas/bulkImportUserEmailPasswordLoginMethod" + - $ref: "#/components/schemas/bulkImportUserThirdPartyLoginMethod" + - $ref: "#/components/schemas/bulkImportUserPasswordlessLoginMethod" + + addBulkImportUserResponse: + type: object + properties: + userId: + $ref: "#/components/schemas/userId" + loginMethods: + type: array + items: + $ref: "#/components/schemas/addBulkImportUserLoginMethodResponse" + + bulkImportUserResponse: + properties: + id: + $ref: "#/components/schemas/bulkImportUserId" + status: + $ref: "#/components/schemas/bulkImportUserStatus" + createdAt: + $ref: "#/components/schemas/timeJoined" + updatedAt: + $ref: "#/components/schemas/timeJoined" + allOf: + - $ref: "#/components/schemas/bulkImportUser" + - type: object + + oauthError: + type: object + required: + - status + - error + - errorDescription + - statusCode + properties: + status: + type: string + enum: [OAUTH_ERROR] + error: + type: string + errorDescription: + type: string + statusCode: + type: integer + securitySchemes: + ApiKey: + name: api-key + description: The core service API token. If you are using a self-hosted core service and you have not generated a token, you can omit the header. + type: apiKey + in: header + example: ajs30Nlbs0DjvsdFIne934n8NVee5n diff --git a/static/img/favicon.ico b/public/favicon.ico similarity index 100% rename from static/img/favicon.ico rename to public/favicon.ico diff --git a/static/fdi-file-paths.json b/public/fdi-file-paths.json similarity index 100% rename from static/fdi-file-paths.json rename to public/fdi-file-paths.json diff --git a/static/fdi-mapping.json b/public/fdi-mapping.json similarity index 100% rename from static/fdi-mapping.json rename to public/fdi-mapping.json diff --git a/static/fdi.json b/public/fdi.json similarity index 100% rename from static/fdi.json rename to public/fdi.json diff --git a/public/fdi.yml b/public/fdi.yml new file mode 100644 index 0000000000..891450797b --- /dev/null +++ b/public/fdi.yml @@ -0,0 +1,3812 @@ +openapi: 3.0.0 +servers: [] +info: + description: | + These are the APIs exposed by our backend SDK. To be consumed by the frontend only. + `{tenantId}` in all the APIs are optional. Its default value is `public` + version: "4.1.0" + title: Frontend Driver Interface + contact: + email: support@supertokens.io +tags: + - name: Session Recipe + - name: EmailPassword Recipe + - name: ThirdParty Recipe + - name: Passwordless Recipe + - name: EmailVerification Recipe + - name: MultiFactorAuth Recipe + - name: TOTP Recipe + - name: JWT Recipe + - name: OpenId Recipe + - name: WebAuthn Recipe + - name: OAuth2Provider Recipe +paths: + /{apiBasePath}/mfa/info: + put: + tags: + - MultiFactorAuth Recipe + operationId: getMFAInfo + summary: Get MFA factors information + description: | + Returns information about the auth factors of the current user and refreshes the related session claim + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/multiFactorAuthRid" + - $ref: "#/components/parameters/anti-csrf" + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + responses: + "200": + description: Information about the auth factors of the current user and optionally the session with a refreshed MFA claim + headers: + Set-Cookie: + description: Sent in cookie-based sessions if the access token is updated + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: Sent in cookie-based sessions if the access token is updated + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: Sent if enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + description: Sent if the access token is updated + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token" + content: + application/json: + schema: + oneOf: + - type: object + title: MFA Info Response + description: Successful response containing information about the auth factors of the current user + properties: + status: + $ref: "#/components/schemas/statusOK" + factors: + type: object + properties: + alreadySetup: + type: array + items: + type: string + allowedToSetup: + type: array + items: + type: string + next: + type: array + items: + type: string + emails: + type: object + properties: + emailpassword: + type: array + items: + type: string + otp-email: + type: array + items: + type: string + link-email: + type: array + items: + type: string + phoneNumbers: + type: object + properties: + otp-phone: + type: array + items: + type: string + link-phone: + type: array + items: + type: string + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/totp/device/list: + get: + tags: + - TOTP Recipe + operationId: listTOTPdevices + summary: List TOTP devices + description: | + List the TOTP devices of the current user + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/anti-csrf" + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + responses: + "200": + description: The list of the TOTP devices of the session user + content: + application/json: + schema: + oneOf: + - type: object + title: TOTP Devices List Response + description: Successful response containing the list of TOTP devices for the current user + properties: + status: + $ref: "#/components/schemas/statusOK" + devices: + type: array + items: + type: object + properties: + name: + type: string + example: "asdf123" + period: + type: number + example: 30 + skew: + type: number + example: 30 + verified: + type: boolean + example: false + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/totp/device: + post: + tags: + - TOTP Recipe + operationId: createTOTPDevice + summary: Create TOTP device + description: | + Creates an unverified totp device + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/anti-csrf" + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + requestBody: + content: + application/json: + schema: + type: object + properties: + deviceName: + type: string + example: "asdf123" + responses: + "200": + description: | + Information about the created (unverified) device. Based on the this, + the user can add the device to their TOTP app and verify it. + content: + application/json: + schema: + oneOf: + - type: object + title: TOTP Device Creation Response + description: Successful response containing information about the created TOTP device + properties: + status: + $ref: "#/components/schemas/statusOK" + deviceName: + type: string + example: "asfd123" + qrCodeString: + type: string + example: "otpauth://totp/Supertokens:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Supertokens" + secret: + type: string + example: "JBSWY3DPEHPK3PXP" + - type: object + title: TOTP Device Already Exists Error + description: Error response when attempting to create a TOTP device that already exists + properties: + status: + type: string + enum: ["DEVICE_ALREADY_EXISTS_ERROR"] + - $ref: "#/components/schemas/generalErrorResponse" + + "403": + $ref: "#/components/responses/403-factor-setup" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/totp/device/remove: + post: + tags: + - TOTP Recipe + operationId: removeTOTPDevice + summary: Remove TOTP device + description: | + Removes a totp device + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/anti-csrf" + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + requestBody: + content: + application/json: + schema: + type: object + properties: + deviceName: + type: string + example: "asdf123" + responses: + "200": + description: Success report + content: + application/json: + schema: + oneOf: + - type: object + title: TOTP Device Removal Response + description: Successful response indicating whether the TOTP device was removed + properties: + status: + $ref: "#/components/schemas/statusOK" + didDeviceExist: + type: boolean + example: true + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/totp/device/verify: + post: + tags: + - TOTP Recipe + operationId: verifyTOTPDevice + summary: Verify TOTP device + description: | + Checks that the TOTP sent in the body belongs to the totp device (specified by deviceName, belonging to the session user) + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/anti-csrf" + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + requestBody: + content: + application/json: + schema: + type: object + properties: + totp: + type: string + example: "123456" + deviceName: + type: string + example: "asdf123asdf" + + responses: + "200": + description: Verification result and optionally the session with a refreshed MFA claim + headers: + Set-Cookie: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: Sent if enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + description: Sent if the access token payload is updated + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token" + content: + application/json: + schema: + oneOf: + - type: object + title: TOTP Device Verification Success + description: Successful response when TOTP device verification succeeds + properties: + status: + $ref: "#/components/schemas/statusOK" + - type: object + title: Unknown TOTP Device Error + description: Error response when attempting to verify an unknown TOTP device + properties: + status: + type: string + enum: ["UNKNOWN_DEVICE_ERROR"] + - type: object + title: Invalid TOTP Error + description: Error response when the provided TOTP code is invalid + properties: + status: + type: string + enum: ["INVALID_TOTP_ERROR"] + currentNumberOfFailedAttempts: + type: number + example: 2 + maxNumberOfFailedAttempts: + type: number + example: 5 + - type: object + title: TOTP Rate Limit Error + description: Error response when too many failed TOTP attempts have been made + properties: + status: + type: string + enum: ["LIMIT_REACHED_ERROR"] + retryAfterMs: + type: number + example: 30000 + - $ref: "#/components/schemas/generalErrorResponse" + + "403": + $ref: "#/components/responses/403-factor-setup" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/totp/verify: + post: + tags: + - TOTP Recipe + operationId: verifyTOTP + summary: Verify TOTP code + description: | + Checks that the TOTP sent in the body belongs to a verified totp device of the session user + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/totpRid" + - $ref: "#/components/parameters/anti-csrf" + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + requestBody: + content: + application/json: + schema: + type: object + properties: + totp: + type: string + example: "123456" + responses: + "200": + description: Verification result and optionally the session with a refreshed MFA claim + headers: + Set-Cookie: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: Sent if enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + description: Sent if the access token payload is updated + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token" + content: + application/json: + schema: + oneOf: + - type: object + title: Sign Out Response + description: Successful response when user is signed out + properties: + status: + $ref: "#/components/schemas/statusOK" + - type: object + properties: + status: + type: string + enum: ["INVALID_TOTP_ERROR"] + currentNumberOfFailedAttempts: + type: number + example: 2 + maxNumberOfFailedAttempts: + type: number + example: 5 + - type: object + properties: + status: + type: string + enum: ["LIMIT_REACHED_ERROR"] + retryAfterMs: + type: number + example: 30000 + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/signinup/code: + post: + tags: + - Passwordless Recipe + operationId: passwordlessSignInUpStart + summary: Start passwordless sign in/up + description: | + Start sign in/up process with passwordless + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + properties: + email: + $ref: "#/components/schemas/email" + shouldTryLinkingWithSessionUser: + type: boolean + example: false + required: + - email + - type: object + properties: + phoneNumber: + $ref: "#/components/schemas/phoneNumber" + shouldTryLinkingWithSessionUser: + type: boolean + example: false + required: + - phoneNumber + + responses: + "200": + description: Started the passwordless sign in/up process. + content: + application/json: + schema: + oneOf: + - type: object + title: Passwordless Sign In/Up Start Response + description: Successful response containing information to continue the passwordless sign in/up process + properties: + status: + $ref: "#/components/schemas/statusOK" + deviceId: + $ref: "#/components/schemas/deviceId" + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + flowType: + type: string + enum: ["MAGIC_LINK", "USER_INPUT_CODE_AND_MAGIC_LINK", "USER_INPUT_CODE"] + - type: object + title: Sign In/Up Not Allowed Error + description: Error response when sign in/up is not allowed due to security reasons + properties: + status: + type: string + enum: ["SIGN_IN_UP_NOT_ALLOWED"] + reason: + type: string + example: "Cannot sign in / up due to security reasons. Please contact support. (IS_SIGN_IN_ALLOWED_FALSE)" + - $ref: "#/components/schemas/generalErrorResponse" + + "403": + $ref: "#/components/responses/403-factor-setup" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/signinup/code/resend: + post: + tags: + - Passwordless Recipe + operationId: passwordlessSignInUpResend + summary: Resend passwordless code + description: | + Resend passwordless code + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + requestBody: + content: + application/json: + schema: + type: object + properties: + deviceId: + $ref: "#/components/schemas/deviceId" + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + shouldTryLinkingWithSessionUser: + type: boolean + example: false + required: + - deviceId + - preAuthSessionId + + responses: + "200": + description: Started the passwordless sign in/up process. + content: + application/json: + schema: + oneOf: + - type: object + title: Passwordless Code Resend Response + description: Response indicating the status of the passwordless code resend attempt + properties: + status: + type: string + enum: ["OK", "RESTART_FLOW_ERROR"] + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/signinup/code/consume: + post: + tags: + - Passwordless Recipe + operationId: passwordlessSignInUpConsume + summary: Complete passwordless sign in/up + description: | + Finish sign in/up process with passwordless + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + properties: + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + shouldTryLinkingWithSessionUser: + type: boolean + example: false + linkCode: + type: string + example: b10lbT_SnDC4flA6Fn7pE5TtG5k5NfigLef4QMBeGA8 + required: + - preAuthSessionId + - linkCode + + - type: object + properties: + preAuthSessionId: + $ref: "#/components/schemas/preAuthSessionId" + shouldTryLinkingWithSessionUser: + type: boolean + example: false + deviceId: + $ref: "#/components/schemas/deviceId" + userInputCode: + type: string + example: 432123 + required: + - preAuthSessionId + - deviceId + - userInputCode + responses: + "200": + description: Signin/up a user + headers: + Set-Cookie: + description: In cookie-based sessions + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax; sRefreshToken=K91cQ7ezMbu...cb61c3.V2; Path=/auth/session/refresh; Expires=Thu, 30 Sep 2021 06:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + st-refresh-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: If enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token, st-refresh-token" + content: + application/json: + schema: + oneOf: + - type: object + title: Passwordless Sign In/Up Response + description: Successful response containing user information after passwordless sign in/up + properties: + status: + $ref: "#/components/schemas/statusOK" + createdNewRecipeUser: + type: boolean + example: true + user: + $ref: "#/components/schemas/user" + + - type: object + title: Incorrect User Input Code Error + description: Error response when the user input code is incorrect + properties: + status: + type: string + enum: ["INCORRECT_USER_INPUT_CODE_ERROR", "EXPIRED_USER_INPUT_CODE_ERROR"] + + failedCodeInputAttemptCount: + type: number + example: 2 + maximumCodeInputAttempts: + type: number + example: 5 + - type: object + title: Restart Flow Error + description: Error response indicating the flow needs to be restarted + properties: + status: + type: string + enum: ["RESTART_FLOW_ERROR"] + - type: object + title: Sign In/Up Not Allowed Error + description: Error response when sign in/up is not allowed due to security reasons + properties: + status: + type: string + enum: ["SIGN_IN_UP_NOT_ALLOWED"] + reason: + type: string + example: "Cannot sign in / up due to security reasons. Please contact support. (IS_SIGN_IN_ALLOWED_FALSE)" + + - $ref: "#/components/schemas/generalErrorResponse" + + "403": + $ref: "#/components/responses/403-factor-setup" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/signup/email/exists⠀⠀: + get: + deprecated: true + tags: + - Passwordless Recipe + operationId: passwordlessEmailExistsDepr + summary: Check email exists (deprecated) + description: | + Check if an email exists + Note that there is an invisible character at the end of the path, this was to avoid a conflict with the OpenAPI spec. + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/email" + responses: + "200": + description: Checks if an email exists + content: + application/json: + schema: + oneOf: + - type: object + title: Email Exists Response + description: Response indicating whether the email exists in the system + properties: + status: + $ref: "#/components/schemas/statusOK" + exists: + $ref: "#/components/schemas/exists" + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/passwordless/email/exists: + get: + tags: + - Passwordless Recipe + operationId: passwordlessEmailExists + summary: Check email exists + description: | + Check if an email exists + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/email" + responses: + "200": + description: Checks if an email exists + content: + application/json: + schema: + oneOf: + - type: object + title: Email Exists Response + description: Response indicating whether the email exists in the system + properties: + status: + $ref: "#/components/schemas/statusOK" + exists: + $ref: "#/components/schemas/exists" + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/signup/phoneNumber/exists: + get: + deprecated: true + tags: + - Passwordless Recipe + operationId: passwordlessPhoneNumberExistsDepr + summary: Check phone exists (deprecated) + description: | + Check if a phone number exists + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/phoneNumber" + responses: + "200": + description: Checks if a phone number exists + content: + application/json: + schema: + oneOf: + - type: object + title: Phone Number Exists Response + description: Response indicating whether the phone number exists in the system + properties: + status: + $ref: "#/components/schemas/statusOK" + exists: + $ref: "#/components/schemas/exists" + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/passwordless/phoneNumber/exists: + get: + tags: + - Passwordless Recipe + operationId: passwordlessPhoneNumberExists + summary: Check phone exists + description: | + Check if a phone number exists + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/passwordlessRid" + - $ref: "#/components/parameters/phoneNumber" + responses: + "200": + description: Checks if a phone number exists + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + exists: + $ref: "#/components/schemas/exists" + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/signout: + post: + tags: + - Session Recipe + operationId: signout + summary: Sign out user + description: | + Logout user + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/rid" + - $ref: "#/components/parameters/anti-csrf" + requestBody: + content: + application/json: + schema: + type: object + responses: + "200": + description: Logout user + headers: + Set-Cookie: + schema: + type: string + example: "sAccessToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax sRefreshToken=; Path=/auth/session/refresh; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: Set to an empty string to trigger token clearing in the client SDK + schema: + type: string + example: "" + st-refresh-token: + description: Set to an empty string to trigger token clearing in the client SDK + schema: + type: string + example: "" + front-token: + schema: + type: string + example: remove + Access-Control-Expose-Headers: + schema: + type: string + example: front-token, st-access-token, st-refresh-token + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/session/refresh: + post: + tags: + - Session Recipe + operationId: refresh + summary: Refresh user session + description: | + Refresh the user session + security: + - RefreshTokenBearer: [] + - RefreshTokenCookie: [] + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/rid" + - $ref: "#/components/parameters/anti-csrf" + responses: + "200": + description: Refresh users + headers: + Set-Cookie: + description: In cookie-based sessions + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax; sRefreshToken=K91cQ7ezMbu...cb61c3.V2; Path=/auth/session/refresh; Expires=Thu, 30 Sep 2021 06:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + st-refresh-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: If enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token, st-refresh-token" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/signin: + post: + tags: + - EmailPassword Recipe + operationId: signIn + summary: Sign in with email + description: | + Signin a user with email ID and password + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/rid" + requestBody: + content: + application/json: + schema: + type: object + required: + - formFields + properties: + formFields: + $ref: "#/components/schemas/formFields" + shouldTryLinkingWithSessionUser: + type: boolean + example: false + responses: + "200": + description: Sign in Response + headers: + Set-Cookie: + description: In cookie-based sessions + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax; sRefreshToken=K91cQ7ezMbu...cb61c3.V2; Path=/auth/session/refresh; Expires=Thu, 30 Sep 2021 06:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + st-refresh-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: If enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token, st-refresh-token" + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/signInResponse" + - $ref: "#/components/schemas/signInNotAllowedResponse" + - $ref: "#/components/schemas/fieldErrorResponse" + - $ref: "#/components/schemas/wrongCredentialsResponse" + - $ref: "#/components/schemas/generalErrorResponse" + + "403": + $ref: "#/components/responses/403-factor-setup" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/signup: + post: + tags: + - EmailPassword Recipe + operationId: signUp + summary: Sign up with email + description: | + Signup a user with email ID and password + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/emailPasswordRid" + requestBody: + content: + application/json: + schema: + type: object + required: + - formFields + properties: + formFields: + $ref: "#/components/schemas/formFields" + shouldTryLinkingWithSessionUser: + type: boolean + example: false + responses: + "200": + description: Sign up Response + headers: + Set-Cookie: + description: In cookie-based sessions + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax; sRefreshToken=K91cQ7ezMbu...cb61c3.V2; Path=/auth/session/refresh; Expires=Thu, 30 Sep 2021 06:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + st-refresh-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: If enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token, st-refresh-token" + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/signupResponse" + - $ref: "#/components/schemas/signUpNotAllowedResponse" + - $ref: "#/components/schemas/fieldErrorResponse" + - $ref: "#/components/schemas/generalErrorResponse" + + "403": + $ref: "#/components/responses/403-factor-setup" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/signup/email/exists: + get: + deprecated: true + tags: + - EmailPassword Recipe + operationId: emailExistsDepr + summary: Check email exists (deprecated) + description: | + Check if an email exists + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/emailPasswordRid" + - $ref: "#/components/parameters/email" + responses: + "200": + description: Checks if an email exists + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + exists: + $ref: "#/components/schemas/exists" + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/emailpassword/email/exists: + get: + tags: + - EmailPassword Recipe + operationId: emailExists + summary: Check email exists + description: | + Check if an email exists + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/emailPasswordRid" + - $ref: "#/components/parameters/email" + responses: + "200": + description: Checks if an email exists + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + exists: + $ref: "#/components/schemas/exists" + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/user/password/reset/token: + post: + tags: + - EmailPassword Recipe + operationId: passwordResetToken + summary: Generate password reset token + description: | + Generate a new reset password token for this user + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/emailPasswordRid" + requestBody: + content: + application/json: + schema: + type: object + properties: + formFields: + $ref: "#/components/schemas/formFields" + example: { formFields: [{ id: "email", value: "test@email.com" }] } + responses: + "200": + description: Generate a new reset password token for this user + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/passwordResetTokenResponse" + - $ref: "#/components/schemas/passwordResetNotAllowedResponse" + - $ref: "#/components/schemas/fieldErrorResponse" + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/user/password/reset: + post: + tags: + - EmailPassword Recipe + operationId: passwordReset + summary: Reset user password + description: | + Reset a password using password reset token + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/emailPasswordRid" + requestBody: + content: + application/json: + schema: + type: object + properties: + method: + $ref: "#/components/schemas/method" + formfields: + $ref: "#/components/schemas/formFields" + token: + $ref: "#/components/schemas/token" + example: + { + method: "token", + formFields: [{ id: "password", value: "newPass123" }], + token: "ZTRiOTBjNz...jI5MTZlODkxw", + } + responses: + "200": + description: Reset a password using password reset token + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/passwordResetResponse" + - $ref: "#/components/schemas/passwordResetErrorResponse" + - $ref: "#/components/schemas/fieldErrorResponse" + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/signinup: + post: + tags: + - ThirdParty Recipe + operationId: signInUp + summary: Sign in/up with third party + description: | + Signin/up a user + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/thirdPartyRid" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + required: + - thirdPartyId + - redirectURIInfo + properties: + thirdPartyId: + $ref: "#/components/schemas/thirdPartyId" + clientType: + $ref: "#/components/schemas/clientType" + redirectURIInfo: + type: object + required: + - redirectURIOnProviderDashboard + - redirectURIQueryParams + properties: + redirectURIOnProviderDashboard: + $ref: "#/components/schemas/redirectURI" + redirectURIQueryParams: + type: object + example: + code: "neqmpdsfuqe141m5lk437867masdf" + state: "ljayfgqewertbh13245njw0" + pkceCodeVerifier: + type: string + example: abcd1234 + shouldTryLinkingWithSessionUser: + type: boolean + example: false + - type: object + required: + - thirdPartyId + - oAuthTokens + properties: + thirdPartyId: + $ref: "#/components/schemas/thirdPartyId" + clientType: + $ref: "#/components/schemas/clientType" + oAuthTokens: + $ref: "#/components/schemas/oAuthTokens" + shouldTryLinkingWithSessionUser: + type: boolean + example: false + responses: + "200": + description: Signin/up a user + headers: + Set-Cookie: + description: In cookie-based sessions + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax; sRefreshToken=K91cQ7ezMbu...cb61c3.V2; Path=/auth/session/refresh; Expires=Thu, 30 Sep 2021 06:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + st-refresh-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: If enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token, st-refresh-token" + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/signinupResponse" + - $ref: "#/components/schemas/signinupErrorResponse" + - $ref: "#/components/schemas/generalErrorResponse" + + "403": + $ref: "#/components/responses/403-factor-setup" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/authorisationurl: + get: + tags: + - ThirdParty Recipe + operationId: authorisationUrl + summary: Get third party auth URL + description: | + Get the thirdparty provider's authorisation URL to which the user should be redirected to. + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/thirdPartyRid" + - in: query + name: thirdPartyId + required: true + schema: + $ref: "#/components/schemas/thirdPartyId" + - in: query + name: redirectURIOnProviderDashboard + required: true + schema: + $ref: "#/components/schemas/redirectURI" + - in: query + name: clientType + required: false + schema: + $ref: "#/components/schemas/clientType" + responses: + "200": + description: Get the OAuth authorisation URL + content: + application/json: + schema: + oneOf: + - type: object + required: + - status + - url + properties: + status: + $ref: "#/components/schemas/statusOK" + urlWithQueryParams: + type: string + example: https://providerdomain.com/authorize?client_id=..&scope=..&access_type=.. + pkceCodeVerifier: + type: string + example: abcd1234 + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/loginmethods: + get: + tags: + - Multitenancy Recipe + operationId: loginmethods + summary: Get enabled login methods + description: | + Get enabled login methods: Returns recipes with their enabled setting and recipe specific configuration. + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/multitenancyRid" + - in: query + name: clientType + required: false + schema: + $ref: "#/components/schemas/clientType" + responses: + "200": + description: Get enabled login methods + content: + application/json: + schema: + oneOf: + - type: object + required: + - status + - recipes + properties: + status: + $ref: "#/components/schemas/statusOK" + recipes: + type: object + required: + - emailPassword + - thirdParty + - passwordless + - firstFactors + properties: + emailPassword: + type: object + required: + - enabled + properties: + enabled: + type: boolean + example: true + thirdParty: + type: object + required: + - enabled + - providers + properties: + enabled: + type: boolean + example: true + providers: + type: array + items: + type: object + required: + - id + properties: + id: + $ref: "#/components/schemas/thirdPartyId" + name: + type: string + example: Google + passwordless: + type: object + required: + - enabled + properties: + enabled: + type: boolean + example: true + firstFactors: + type: array + items: + type: string + - $ref: "#/components/schemas/generalErrorResponse" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/callback/apple: + post: + tags: + - ThirdParty Recipe + operationId: thirdPartyCallbackApple + summary: Handle Apple sign in + description: | + Handles sign in with the apple. + parameters: + - $ref: "#/components/parameters/apiBasePath" + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + code: + type: string + description: "The Authorization code which will be exchanged for an access token" + state: + type: string + description: "A unique string used to mitigate CSRF attacks" + responses: + "303": + description: Redirects the user to the client's app. + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/user/email/verify/token: + post: + tags: + - EmailVerification Recipe + operationId: verifyEmailToken + summary: Send email verification + description: | + Send email verification email + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/emailVerificationRid" + - $ref: "#/components/parameters/anti-csrf" + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + responses: + "200": + description: Send email verification email + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + type: string + enum: ["OK", "EMAIL_ALREADY_VERIFIED_ERROR"] + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/user/email/verify: + post: + tags: + - EmailVerification Recipe + operationId: verifyEmail + summary: Verify email address + description: | + Verify an email + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/emailVerificationRid" + requestBody: + content: + application/json: + schema: + type: object + properties: + method: + $ref: "#/components/schemas/method" + token: + $ref: "#/components/schemas/token" + responses: + "200": + description: Verify an email + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + type: string + enum: ["OK", "EMAIL_VERIFICATION_INVALID_TOKEN_ERROR"] + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/user/email/verify: + get: + tags: + - EmailVerification Recipe + operationId: getVerifyEmail + summary: Check email verification status + description: | + Checks if an email is verified and adds this information into the access token payload as well + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/emailVerificationRid" + - $ref: "#/components/parameters/anti-csrf" + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + + responses: + "200": + description: Checks if an email is verified and adds this information into the access token payload as well + headers: + Set-Cookie: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: Sent in cookie-based sessions if the access token payload is updated + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: Sent if enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + description: Sent if the access token payload is updated + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token" + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + isVerified: + type: boolean + example: true + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/jwt/jwks.json: + get: + tags: + - JWT Recipe + operationId: getJWKS + summary: Get JWT keys + description: | + Get all JSON web keys for JWT verification + parameters: + - $ref: "#/components/parameters/apiBasePath" + responses: + "200": + description: Retrieve JWKs for JWT verification + content: + application/json: + schema: + oneOf: + - type: object + properties: + keys: + type: array + items: + type: object + description: A JWK that can be used to verify a JWT + properties: + alg: + type: string + description: The algorithm to use when creating the JWT. + enum: ["RS256"] + kty: + type: string + example: RSA + use: + type: string + example: sig + kid: + type: string + description: Unique identifier for the JWK + n: + type: string + description: Modulus for the key + e: + type: string + description: Exponent for the key + - $ref: "#/components/schemas/generalErrorResponse" + + "400": + $ref: "#/components/responses/400" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/.well-known/openid-configuration: + get: + tags: + - OpenId Recipe + operationId: getOpenIdDiscoveryConfiguration + summary: Get OpenID config + description: | + Get OpenID discovery configuration + parameters: + - $ref: "#/components/parameters/apiBasePath" + responses: + "200": + description: Retrieve OpenID configuration + content: + application/json: + schema: + oneOf: + - type: object + properties: + issuer: + type: string + description: URL using the https scheme with no query or fragment component that the OP asserts as its Issuer Identifier (https://openid.net/specs/openid-connect-discovery-1_0.html section 3) + example: https://api.example.com/auth + jwks_uri: + type: string + description: URL for fetching a list JsonWebKey, used for JWT signature verification. Refer to /jwt/jwks.json API in the JWT recipe for JWK details + example: https://api.example.com/auth/jwt/jwks.json + authorization_endpoint: + type: string + description: URL of the authorization endpoint + example: https://api.example.com/auth/oauth/authorize + token_endpoint: + type: string + description: URL of the token endpoint + example: https://api.example.com/auth/oauth/token + userinfo_endpoint: + type: string + description: URL of the userinfo endpoint + example: https://api.example.com/auth/oauth/userinfo + revocation_endpoint: + type: string + description: URL of the token revocation endpoint + example: https://api.example.com/auth/oauth/revoke + token_introspection_endpoint: + type: string + description: URL of the token introspection endpoint + example: https://api.example.com/auth/oauth/introspect + end_session_endpoint: + type: string + description: URL of the end session endpoint + example: https://api.example.com/auth/oauth/end_session + subject_types_supported: + type: array + items: + type: string + enum: ["public"] + id_token_signing_alg_values_supported: + type: array + items: + type: string + enum: ["RS256"] + response_types_supported: + type: array + items: + type: string + enum: ["code", "id_token", "id_token token"] + - $ref: "#/components/schemas/generalErrorResponse" + + "400": + $ref: "#/components/responses/400" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/oauth/login: + get: + tags: + - OAuth2Provider Recipe + operationId: oauthLoginGET + summary: Continue OAuth login + description: | + Continues the OAuth2 login flow after the login page + parameters: + - $ref: "#/components/parameters/apiBasePath" + - in: query + name: loginChallenge + required: true + schema: + type: string + responses: + "200": + description: The next url in the login flow + content: + application/json: + schema: + oneOf: + - type: object + properties: + frontendRedirectTo: + type: string + description: The URL to redirect the user to + example: https://client.com/callback?code=asdf1234567890&status=asdf1234 + - $ref: "#/components/schemas/generalErrorResponse" + + "400": + $ref: "#/components/responses/400-oauth-error" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/oauth/auth: + get: + tags: + - OAuth2Provider Recipe + operationId: oauthAuthGET + summary: Start OAuth login + description: | + Starts the OAuth2 login flow - for a detailed description of all input parameters please see the OAuth2 and OpenID Connect Core specs + parameters: + - $ref: "#/components/parameters/apiBasePath" + responses: + "302": + description: Redirects the user to the login page or back to the client app + headers: + Location: + schema: + type: string + example: https://auth.example.com/auth/?loginChallenge=1234567890 + + "200": + description: A general error response + content: + application/json: + schema: + $ref: "#/components/schemas/generalErrorResponse" + + "400": + $ref: "#/components/responses/400-oauth-error" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/oauth/token: + post: + tags: + - OAuth2Provider Recipe + operationId: oauthTokenPOST + summary: Exchange OAuth grant + description: | + Exchanges an OAuth2 grant (e.g.: authorization code) for an access token (and optionally a refresh/id token) - for a detailed description of all input parameters please see the OAuth2 and OpenID Connect Core specs + parameters: + - $ref: "#/components/parameters/apiBasePath" + responses: + "200": + description: Issued tokens + content: + application/json: + schema: + oneOf: + - type: object + required: + - expires_in + - token_type + - scope + properties: + access_token: + type: string + description: "The access token issued by the authorization server." + + expires_in: + type: number + description: 'The lifetime in seconds of the access token (integer). For example, the value "3600" denotes that the access token will expire in one hour from the time the response was generated.' + + id_token: + type: string + description: "To retrieve a refresh token request the id_token scope." + + refresh_token: + type: string + description: 'The refresh token, which can be used to obtain new access tokens. To retrieve it add the scope "offline" to your access token request.' + + scope: + type: string + description: "The scope of the access token" + + token_type: + type: string + description: "The type of the token issued" + - $ref: "#/components/schemas/generalErrorResponse" + + "400": + $ref: "#/components/responses/400-oauth-error" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/oauth/userinfo: + get: + tags: + - OAuth2Provider Recipe + operationId: oauthUserInfoGET + summary: Get OAuth user info + description: | + Retrieves user information based on the access token passed in the authorization header + parameters: + - $ref: "#/components/parameters/apiBasePath" + security: + - OAuth2AccessTokenBearer: [] + responses: + "200": + description: Retrieved user information + content: + application/json: + schema: + oneOf: + - type: object + required: + - sub + properties: + sub: + $ref: "#/components/schemas/userId" + email: + type: string + description: The email of the user + example: johndoe@gmail.com + email_verified: + type: boolean + description: Whether the email is verified + example: true + emails: + type: array + items: + type: string + example: johndoe@gmail.com + phoneNumber: + type: string + description: The phoneNumber of the user + example: "0036701234567" + phoneNumber_verified: + type: boolean + description: Whether the phoneNumber is verified + example: true + phoneNumbers: + type: array + items: + type: string + example: "0036701234567" + roles: + type: array + items: + type: string + example: admin + permissions: + type: array + items: + type: string + example: "user:create" + + - $ref: "#/components/schemas/generalErrorResponse" + + "401": + description: The access token is expired, revoked or malformed + headers: + WWW-Authenticate: + schema: + type: string + example: 'Bearer error="invalid_token"' + content: + application/json: + schema: + type: object + properties: + message: + type: string + example: Invalid or expired OAuth2 access token + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/oauth/revoke: + post: + tags: + - OAuth2Provider Recipe + operationId: oauthRevokePOST + summary: Revoke OAuth token + description: | + Revokes an access/refresh token - the client id and secret can also be provided in an authorization header using the Basic scheme + parameters: + - $ref: "#/components/parameters/apiBasePath" + requestBody: + content: + application/json: + schema: + type: object + required: + - token + properties: + token: + type: string + client_id: + type: string + example: st-cl-test-client + client_secret: + type: string + example: superSecret + x-www-form-urlencoded: + schema: + type: object + required: + - token + properties: + token: + type: string + client_id: + type: string + example: st-cl-test-client + client_secret: + type: string + example: superSecret + responses: + "200": + description: Revoked the access/refresh token + content: + application/json: + schema: + oneOf: + - type: object + required: + - status + properties: + status: + $ref: "#/components/schemas/statusOK" + + - $ref: "#/components/schemas/generalErrorResponse" + + "400": + $ref: "#/components/responses/400-oauth-error" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/oauth/introspect: + post: + tags: + - OAuth2Provider Recipe + operationId: oauthIntrospectPOST + summary: Introspect OAuth token + description: | + Introspects an access/refresh token + parameters: + - $ref: "#/components/parameters/apiBasePath" + requestBody: + content: + application/json: + schema: + type: object + required: + - token + properties: + token: + type: string + application/x-www-form-urlencoded: + schema: + type: object + required: + - token + properties: + token: + type: string + responses: + "200": + description: Information about the token + content: + application/json: + schema: + oneOf: + - type: object + required: + - active + properties: + active: + type: boolean + description: Whether the token is active or not + example: true + token_type: + type: string + description: The type of the token + example: Bearer + token_use: + type: string + description: The use of the token + example: access_token + sub: + $ref: "#/components/schemas/userId" + email: + type: string + description: The email of the user + example: johndoe@gmail.com + email_verified: + type: boolean + description: Whether the email is verified + example: true + emails: + type: array + items: + type: string + example: johndoe@gmail.com + phoneNumber: + type: string + description: The phoneNumber of the user + example: "0036701234567" + phoneNumber_verified: + type: boolean + description: Whether the phoneNumber is verified + example: true + phoneNumbers: + type: array + items: + type: string + example: "0036701234567" + roles: + type: array + items: + type: string + example: admin + permissions: + type: array + items: + type: string + example: "user:create" + + - $ref: "#/components/schemas/generalErrorResponse" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/oauth/end_session: + post: + tags: + - OAuth2Provider Recipe + operationId: oauthEndSessionPOST + summary: End OAuth session + description: | + Redirects the user to a page where they can log out and revoke the oauth tokens - for a detailed description of input parameters please see the user initiated logout spec + parameters: + - $ref: "#/components/parameters/apiBasePath" + requestBody: + content: + application/json: + schema: + type: object + properties: + id_token_hint: + type: string + client_id: + type: string + example: st-cl-example-client + post_logout_redirect_uri: + type: string + example: https://client.example.com/logoutCallback + application/x-www-form-urlencoded: + schema: + type: object + properties: + id_token_hint: + type: string + client_id: + type: string + example: st-cl-example-client + post_logout_redirect_uri: + type: string + example: https://client.example.com/logoutCallback + responses: + "302": + description: Redirects the user to the logout page or back to the client app + headers: + Location: + schema: + type: string + example: https://auth.example.com/auth/oauth/logout?logoutChallenge=1234567890 + + "200": + description: A general error response + content: + application/json: + schema: + $ref: "#/components/schemas/generalErrorResponse" + + "400": + $ref: "#/components/responses/400-oauth-error" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + get: + tags: + - OAuth2Provider Recipe + operationId: oauthEndSessionGET + summary: End session redirect + parameters: + - $ref: "#/components/parameters/apiBasePath" + - in: query + name: id_token_hint + schema: + type: string + - in: query + name: client_id + schema: + type: string + example: st-cl-example-client + - in: query + name: post_logout_redirect_uri + schema: + type: string + example: https://client.example.com/logoutCallback + description: | + Redirects the user to a page where they can log out and revoke the oauth tokens + responses: + "302": + description: Redirects the user to the logout page or back to the client app + headers: + Location: + schema: + type: string + example: https://auth.example.com/auth/oauth/logout?logoutChallenge=1234567890 + + "200": + description: A general error response + content: + application/json: + schema: + $ref: "#/components/schemas/generalErrorResponse" + + "400": + $ref: "#/components/responses/400-oauth-error" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/oauth/logininfo: + get: + tags: + - OAuth2Provider Recipe + operationId: oauthLoginInfoGET + summary: Get OAuth login info + description: | + Retrieves information about the OAuth2 login + parameters: + - $ref: "#/components/parameters/apiBasePath" + - in: query + name: loginChallenge + required: true + schema: + type: string + responses: + "200": + description: Information about the current login flow + content: + application/json: + schema: + oneOf: + - type: object + required: + - status + - info + properties: + status: + $ref: "#/components/schemas/statusOK" + info: + type: object + description: Information about the current login flow + required: + - clientId + properties: + clientId: + type: string + description: The ID of the client. + clientName: + type: string + description: The name of the client. + tosUri: + type: string + description: The URI of the client's terms of service. + policyUri: + type: string + description: The URI of the client's privacy policy. + logoUri: + type: string + description: The URI of the client's logo. + clientUri: + type: string + description: The URI of the client we can link to on the login page + + - $ref: "#/components/schemas/generalErrorResponse" + + "400": + $ref: "#/components/responses/400-oauth-error" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/oauth/logout: + post: + tags: + - OAuth2Provider Recipe + operationId: oauthLogoutPOST + summary: Logout OAuth user + description: | + Logs out the user and revokes the access/refresh tokens based on the id_token_hint passed to the end_session endpoint + parameters: + - $ref: "#/components/parameters/apiBasePath" + requestBody: + content: + application/json: + schema: + type: object + required: + - logoutChallenge + properties: + logoutChallenge: + type: string + x-www-form-urlencoded: + schema: + type: object + required: + - logoutChallenge + properties: + logoutChallenge: + type: string + responses: + "200": + description: Accepts the logout request specified by the challenge and gets where the user should be redirected to + content: + application/json: + schema: + oneOf: + - type: object + properties: + frontendRedirectTo: + type: string + description: The URL to redirect the user to + example: https://auth.example.com/auth/oauth/logout?logoutChallenge=1234567890 + - $ref: "#/components/schemas/generalErrorResponse" + + "400": + $ref: "#/components/responses/400-oauth-error" + + "404": + $ref: "#/components/responses/404" + + "500": + $ref: "#/components/responses/500" + + /example: + get: + tags: + - App API + operationId: exampleAppAPI + summary: Test authentication + description: | + Use this endpoint to check if your request are authenticated properly. + parameters: + - $ref: "#/components/parameters/apiBasePath" + responses: + "200": + description: The session passed verification and went through the application code + + "401": + description: The session doesn't exists or if it needs to be refreshed + content: + application/json: + schema: + type: object + properties: + message: + type: string + description: unauthorised or try refresh token + example: try refresh token + + "403": + description: The session exists, but didn't pass a claim validator + content: + application/json: + schema: + type: object + properties: + message: + type: string + example: invalid claim + claimValidationErrors: + type: array + items: + type: object + properties: + id: + type: string + example: st-ev + reason: + type: object + example: + message: "value does not exist" + expectedValue: val + actualValue: claimVal + + /{apiBasePath}/{tenantId}/webauthn/register/options: + post: + tags: + - WebAuthn Recipe + operationId: webauthnRegisterOptions + summary: Get WebAuthn registration options + description: | + Get WebAuthn registration options for a user + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + required: + - email + properties: + email: + $ref: "#/components/schemas/email" + displayName: + type: string + example: "John Doe" + - type: object + required: + - recoverAccountToken + properties: + recoverAccountToken: + type: string + example: "abc123..." + responses: + "200": + description: WebAuthn registration options + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + webauthnGeneratedOptionsId: + type: string + example: "opt_123..." + createdAt: + type: string + example: "2024-03-20T10:00:00Z" + expiresAt: + type: string + example: "2024-03-20T10:05:00Z" + rp: + type: object + properties: + id: + type: string + example: "example.com" + name: + type: string + example: "Example Site" + user: + type: object + properties: + id: + type: string + example: "user_123..." + name: + type: string + example: "john@example.com" + displayName: + type: string + example: "John Doe" + challenge: + type: string + example: "base64challenge..." + timeout: + type: number + example: 300000 + excludeCredentials: + type: array + items: + type: object + properties: + id: + type: string + type: + type: string + enum: ["public-key"] + transports: + type: array + items: + type: string + enum: ["ble", "hybrid", "internal", "nfc", "usb"] + attestation: + type: string + enum: ["none", "indirect", "direct", "enterprise"] + pubKeyCredParams: + type: array + items: + type: object + properties: + alg: + type: number + example: -7 + type: + type: string + example: "public-key" + authenticatorSelection: + type: object + properties: + requireResidentKey: + type: boolean + residentKey: + type: string + enum: ["required", "preferred", "discouraged"] + userVerification: + type: string + enum: ["required", "preferred", "discouraged"] + - $ref: "#/components/schemas/generalErrorResponse" + - type: object + properties: + status: + type: string + enum: ["INVALID_OPTIONS_ERROR", "RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"] + - type: object + properties: + status: + type: string + enum: ["INVALID_EMAIL_ERROR"] + err: + type: string + example: "Invalid email" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/webauthn/signin/options: + post: + tags: + - WebAuthn Recipe + operationId: webauthnSignInOptions + summary: Get WebAuthn sign in options + description: | + Get WebAuthn sign in options + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + responses: + "200": + description: WebAuthn sign in options + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + webauthnGeneratedOptionsId: + type: string + example: "opt_123..." + createdAt: + type: string + example: "2024-03-20T10:00:00Z" + expiresAt: + type: string + example: "2024-03-20T10:05:00Z" + rpId: + type: string + example: "example.com" + challenge: + type: string + example: "base64challenge..." + timeout: + type: number + example: 300000 + userVerification: + type: string + enum: ["required", "preferred", "discouraged"] + - $ref: "#/components/schemas/generalErrorResponse" + - type: object + properties: + status: + type: string + enum: ["INVALID_OPTIONS_ERROR"] + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/webauthn/signup: + post: + tags: + - WebAuthn Recipe + operationId: webauthnSignUp + summary: Sign up with WebAuthn + description: | + Sign up a user with WebAuthn + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + requestBody: + content: + application/json: + schema: + type: object + required: + - webauthnGeneratedOptionsId + - credential + properties: + webauthnGeneratedOptionsId: + type: string + example: "opt_123..." + credential: + $ref: "#/components/schemas/registrationPayload" + shouldTryLinkingWithSessionUser: + type: boolean + example: true + responses: + "200": + description: Sign up response + headers: + Set-Cookie: + description: In cookie-based sessions + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax; sRefreshToken=K91cQ7ezMbu...cb61c3.V2; Path=/auth/session/refresh; Expires=Thu, 30 Sep 2021 06:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + st-refresh-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: If enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token, st-refresh-token" + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/user" + - $ref: "#/components/schemas/generalErrorResponse" + - type: object + properties: + status: + type: string + enum: ["INVALID_CREDENTIALS_ERROR", "EMAIL_ALREADY_EXISTS_ERROR"] + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/webauthn/signin: + post: + tags: + - WebAuthn Recipe + operationId: webauthnSignIn + summary: Sign in with WebAuthn + description: | + Sign in a user with WebAuthn + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + requestBody: + content: + application/json: + schema: + type: object + required: + - webauthnGeneratedOptionsId + - credential + properties: + webauthnGeneratedOptionsId: + type: string + example: "opt_123..." + credential: + $ref: "#/components/schemas/authenticationPayload" + shouldTryLinkingWithSessionUser: + type: boolean + example: true + responses: + "200": + description: Sign in response + headers: + Set-Cookie: + description: In cookie-based sessions + schema: + type: string + example: "sAccessToken=eyJhb...%3D%3D; Path=/; Expires=Tue, 22 Jun 2021 07:43:07 GMT; HttpOnly; SameSite=Lax; sRefreshToken=K91cQ7ezMbu...cb61c3.V2; Path=/auth/session/refresh; Expires=Thu, 30 Sep 2021 06:43:07 GMT; HttpOnly; SameSite=Lax" + st-access-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + st-refresh-token: + description: In header-based sessions + schema: + $ref: "#/components/schemas/token" + anti-csrf: + description: If enabled by the user + schema: + $ref: "#/components/schemas/token" + front-token: + schema: + $ref: "#/components/schemas/token" + Access-Control-Expose-Headers: + schema: + type: string + example: "anti-csrf, front-token, st-access-token, st-refresh-token" + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/user" + - $ref: "#/components/schemas/generalErrorResponse" + - type: object + properties: + status: + type: string + enum: ["INVALID_CREDENTIALS_ERROR"] + - type: object + properties: + status: + type: string + enum: ["SIGN_IN_NOT_ALLOWED"] + reason: + type: string + example: "Sign in not allowed" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/webauthn/recover/account/token: + post: + tags: + - WebAuthn Recipe + operationId: webauthnGenerateRecoverAccountToken + summary: Generate WebAuthn recovery token + description: | + Generate a recovery token for a WebAuthn account + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + requestBody: + content: + application/json: + schema: + type: object + required: + - email + properties: + email: + $ref: "#/components/schemas/email" + responses: + "200": + description: Recovery token generation response + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - $ref: "#/components/schemas/generalErrorResponse" + - type: object + properties: + status: + type: string + enum: ["RECOVER_ACCOUNT_NOT_ALLOWED"] + reason: + type: string + example: "Recover account not allowed" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/webauthn/recover/account: + post: + tags: + - WebAuthn Recipe + operationId: webauthnRecoverAccount + summary: Recover WebAuthn account + description: | + Recover a WebAuthn account + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + requestBody: + content: + application/json: + schema: + type: object + required: + - token + - webauthnGeneratedOptionsId + - credential + properties: + token: + type: string + example: "abc123..." + webauthnGeneratedOptionsId: + type: string + example: "opt_123..." + credential: + $ref: "#/components/schemas/registrationPayload" + responses: + "200": + description: Account recovery response + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/user" + email: + $ref: "#/components/schemas/email" + - $ref: "#/components/schemas/generalErrorResponse" + - type: object + properties: + status: + type: string + enum: + [ + "INVALID_CREDENTIALS_ERROR", + "RECOVER_ACCOUNT_TOKEN_INVALID_ERROR", + "OPTIONS_NOT_FOUND_ERROR", + "INVALID_OPTIONS_ERROR", + ] + - type: object + properties: + status: + type: string + enum: ["INVALID_AUTHENTICATOR_ERROR"] + reason: + type: string + example: "Invalid authenticator" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/webauthn/credential: + post: + tags: + - WebAuthn Recipe + operationId: webauthnRegisterCredential + summary: Register WebAuthn credential + description: | + Register a new WebAuthn credential for an existing user + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/anti-csrf" + security: + - AccessTokenBearer: [] + - AccessTokenCookie: [] + requestBody: + content: + application/json: + schema: + type: object + required: + - webauthnGeneratedOptionsId + - credential + properties: + webauthnGeneratedOptionsId: + type: string + example: "opt_123..." + credential: + $ref: "#/components/schemas/registrationPayload" + responses: + "200": + description: Credential registration response + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + - $ref: "#/components/schemas/generalErrorResponse" + - type: object + properties: + status: + type: string + enum: + [ + "INVALID_CREDENTIALS_ERROR", + "OPTIONS_NOT_FOUND_ERROR", + "INVALID_OPTIONS_ERROR", + "INVALID_AUTHENTICATOR_ERROR", + ] + - type: object + properties: + status: + type: string + enum: ["REGISTER_CREDENTIAL_NOT_ALLOWED", "INVALID_AUTHENTICATOR_ERRORp"] + reason: + type: string + example: "Register credential not allowed" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /{apiBasePath}/{tenantId}/webauthn/email/exists: + get: + tags: + - WebAuthn Recipe + operationId: webauthnEmailExists + summary: Check WebAuthn email exists + description: | + Check if a WebAuthn email exists + parameters: + - $ref: "#/components/parameters/apiBasePath" + - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/webauthnRid" + - $ref: "#/components/parameters/email" + responses: + "200": + description: Email existence check response + content: + application/json: + schema: + oneOf: + - type: object + properties: + status: + $ref: "#/components/schemas/statusOK" + exists: + type: boolean + example: true + - $ref: "#/components/schemas/generalErrorResponse" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + +components: + parameters: + rid: + name: rid + in: header + description: The recipe ID for the request + example: session + schema: + type: string + + emailPasswordRid: + name: rid + in: header + description: The email password recipe ID + example: emailpassword + schema: + type: string + + thirdPartyRid: + name: rid + in: header + description: The third party recipe ID + example: thirdparty + schema: + type: string + + passwordlessRid: + name: rid + in: header + description: The passwordless recipe ID + example: passwordless + schema: + type: string + + emailVerificationRid: + name: rid + in: header + description: The email verification recipe ID + example: emailverification + schema: + type: string + + multitenancyRid: + name: rid + in: header + description: The multitenancy recipe ID + example: multitenancy + schema: + type: string + + multiFactorAuthRid: + name: rid + in: header + description: The multi factor auth recipe ID + example: multifactorauth + schema: + type: string + + totpRid: + name: rid + in: header + description: The TOTP recipe ID + example: totp + schema: + type: string + + anti-csrf: + name: anti-csrf + in: header + description: This will only be here if enabled by the user. + schema: + $ref: "#/components/schemas/token" + + apiBasePath: + name: apiBasePath + in: path + description: Its value depends on the apiBasePath set by the user + required: true + schema: + type: string + example: auth + + tenantId: + name: tenantId + in: path + description: The tenant against which the request is made. If left empty, the default tenant will be used. + required: false + schema: + type: string + example: public + + email: + name: email + in: query + description: The email address to check + required: true + schema: + type: string + example: johndoe@gmail.com + + phoneNumber: + name: phoneNumber + in: query + description: The phone number to check + required: true + schema: + type: string + example: "0036701234567" + + webauthnRid: + name: rid + in: header + description: The WebAuthn recipe ID + example: webauthn + schema: + type: string + + responses: + 500: + description: Internal server error + content: + text/plain: + schema: + $ref: "#/components/schemas/internalError" + + 400: + description: Bad request error + content: + text/plain: + schema: + $ref: "#/components/schemas/badRequest" + + 404: + description: Resource not found error + content: + text/plain: + schema: + $ref: "#/components/schemas/notFound" + + 400-oauth-error: + description: OAuth2 specific error response + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: The OAuth2 error code + example: invalid_request + error_description: + type: string + description: Human readable error description + example: "Unsupported grant type: password" + + 403-factor-setup: + description: A claim validation error happened during factor setup + content: + application/json: + schema: + oneOf: + - type: object + properties: + message: + type: string + description: Error message + example: invalid claim + claimValidationErrors: + type: array + description: List of claim validation errors + items: + type: object + properties: + id: + type: string + description: The claim ID + example: st-ev + reason: + type: object + description: The reason for the validation error + example: + message: "wrong value" + expectedValue: true + actualValue: false + - type: object + properties: + message: + type: string + description: Error message + example: invalid claim + claimValidationErrors: + type: array + description: List of claim validation errors + items: + type: object + properties: + id: + type: string + description: The claim ID + example: st-mfa + reason: + type: string + description: The reason for the validation error + example: "Completed factors in the session does not satisfy the MFA requirements for auth" + + schemas: + statusOK: + type: string + description: Success status indicator + enum: + - OK + + generalErrorResponse: + type: object + description: Generic error response + properties: + status: + type: string + description: Error status code + enum: + - GENERAL_ERROR + message: + type: string + description: Error message + + token: + type: string + description: A security token used for authentication + example: ZTRiOTBjNz...jI5MTZlODkxw + + cookie: + type: string + description: HTTP cookie string + example: ed3164...06c0d; Path=/; Expires=Thu, 30 Sep 2021 06:43:07 GMT; HttpOnly; SameSite=Lax + + id: + type: string + description: Field identifier + enum: ["email", "password"] + + userId: + type: string + description: Unique identifier for a user + example: fa7a0841-b533-4478-95533-0fde890c3483 + + user: + type: object + description: User information + properties: + id: + $ref: "#/components/schemas/userId" + timeJoined: + type: number + description: Timestamp when user joined + example: 1638433545183 + isPrimaryUser: + type: boolean + description: Whether this is the primary user account + example: true + tenantIds: + type: array + description: List of tenant IDs the user belongs to + items: + type: string + example: public + emails: + type: array + description: List of user's email addresses + items: + type: string + example: johndoe@gmail.com + phoneNumbers: + type: array + description: List of user's phone numbers + items: + type: string + example: +36201234123 + thirdParty: + type: array + description: List of third party accounts + items: + type: object + properties: + id: + type: string + description: Third party provider ID + example: google + userId: + type: string + description: User ID in the third party system + example: rq238mrq2389rvq123213 + loginMethods: + type: array + description: List of login methods available to the user + items: + type: object + properties: + recipeId: + type: string + description: The recipe ID for this login method + enum: ["emailpassword", "thirdparty", "passwordless"] + recipeUserId: + $ref: "#/components/schemas/userId" + verified: + type: boolean + description: Whether this login method is verified + example: true + tenantIds: + type: array + description: List of tenant IDs for this login method + items: + type: string + example: public + timeJoined: + type: number + description: Timestamp when this login method was added + example: 1638433545183 + email: + type: string + description: Email address for this login method + example: johndoe@gmail.com + phoneNumber: + type: string + description: Phone number for this login method + example: +36201234123 + thirdParty: + type: object + description: Third party information for this login method + properties: + id: + type: string + description: Third party provider ID + example: google + userId: + type: string + description: User ID in the third party system + example: rq238mrq2389rvq123213 + + email: + type: string + description: Email address + example: johndoe@gmail.com + + phoneNumber: + type: string + description: Phone number + example: "0036701234567" + + deviceId: + type: string + description: This should be saved on the starting device to enable the manual code entry flow. + example: TU/52WOcktSv99zqaAZuWJG9BSoS0aRLfCbep8rFEwk= + + preAuthSessionId: + type: string + description: An identifier that used to identify the login attempt/device. + example: kFmkPQEAJtACiT2w/K8fndEuNm+XozJXSZSlWEr+iGs= + + thirdPartyId: + type: string + description: Third party provider identifier + example: google + + exists: + type: boolean + description: Whether the resource exists + example: true + + method: + type: string + description: The method to use for the operation + example: "token" + + code: + $ref: "#/components/schemas/token" + + authCodeResponse: + description: OAuth authorization code response + type: object + required: + - access_token + properties: + access_token: + type: string + description: OAuth access token + id_token: + type: string + description: OAuth ID token + + redirectURI: + type: string + description: URL to redirect to after authentication + example: https://yourdomain.com/callback + + clientType: + type: string + description: Type of client making the request + example: web + + oAuthTokens: + type: object + description: OAuth tokens + properties: + access_token: + type: string + description: OAuth access token + example: ZTRiOTBjNz...jI5MTZlODkxw + id_token: + type: string + description: OAuth ID token + example: ZTRiOTBjNz...jI5MTZlODkxw + + formFields: + type: array + description: Form fields for authentication + items: + type: object + properties: + id: + $ref: "#/components/schemas/id" + value: + type: string + description: Field value + example: [{ id: email, value: johndoe@gmail.com }, { id: password, value: testPass123 }] + + signInResponse: + type: object + description: Sign in response + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/user" + + signInNotAllowedResponse: + type: object + description: Sign in not allowed response + properties: + status: + type: string + description: Error status + enum: ["SIGN_IN_NOT_ALLOWED"] + reason: + type: string + description: Reason why sign in is not allowed + example: "Cannot sign in due to security reasons. Please try resetting your password, use a different login method or contact support. (ERR_CODE_008)" + + signupResponse: + type: object + description: Sign up response + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/user" + + signUpNotAllowedResponse: + type: object + description: Sign up not allowed response + properties: + status: + type: string + description: Error status + enum: ["SIGN_UP_NOT_ALLOWED"] + reason: + type: string + description: Reason why sign up is not allowed + example: "Cannot sign up due to security reasons. Please try resetting your password, use a different login method or contact support. (ERR_CODE_007)" + + passwordResetTokenResponse: + type: object + description: Password reset token response + properties: + status: + $ref: "#/components/schemas/statusOK" + + passwordResetNotAllowedResponse: + type: object + description: Password reset not allowed response + properties: + status: + type: string + description: Error status + enum: ["PASSWORD_RESET_NOT_ALLOWED"] + reason: + type: string + description: Reason why password reset is not allowed + example: "Token generation was not done because of account take over risk. Please contact support. (HAS_OTHER_EMAIL_OR_PHONE)" + + signinupResponse: + type: object + description: Sign in/up response + properties: + status: + $ref: "#/components/schemas/statusOK" + user: + $ref: "#/components/schemas/user" + createdNewRecipeUser: + type: boolean + description: Whether a new recipe user was created + example: true + + passwordResetErrorResponse: + type: object + description: Password reset error response + properties: + status: + type: string + description: Error status + enum: ["RESET_PASSWORD_INVALID_TOKEN_ERROR"] + + passwordResetResponse: + type: object + description: Password reset success response + properties: + status: + type: string + description: Success status + enum: ["OK"] + + fieldErrorResponse: + type: object + description: Form field error response + properties: + status: + type: string + description: Error status + enum: ["FIELD_ERROR"] + formFields: + type: array + description: List of field errors + items: + type: object + properties: + id: + type: string + description: Field ID + example: email + error: + type: string + description: Error message + example: "Error Message" + + wrongCredentialsResponse: + type: object + description: Wrong credentials error response + properties: + status: + type: string + description: Error status + enum: ["WRONG_CREDENTIALS_ERROR"] + + signinupErrorResponse: + description: Sign in/up error response + oneOf: + - type: object + properties: + status: + type: string + description: Error status + enum: ["NO_EMAIL_GIVEN_BY_PROVIDER"] + + - type: object + properties: + status: + type: string + description: Error status + enum: ["SIGN_IN_UP_NOT_ALLOWED"] + reason: + type: string + description: Reason why sign in/up is not allowed + example: "Cannot sign in / up due to security reasons. Please contact support. (IS_SIGN_IN_ALLOWED_FALSE)" + + internalError: + type: string + description: Internal server error message + enum: + - Internal Error + + badRequest: + type: string + description: Bad request error message + enum: + - Bad request + + notFound: + type: string + description: Not found error message + enum: + - Not Found + + registrationPayload: + type: object + description: WebAuthn registration payload + required: + - id + - rawId + - response + - type + properties: + id: + type: string + description: Credential ID + example: "cred_123..." + rawId: + type: string + description: Raw credential ID + example: "base64rawid..." + authenticatorAttachment: + type: string + description: Type of authenticator + enum: ["platform", "cross-platform"] + clientExtensionResults: + type: object + description: Client extension results + additionalProperties: true + response: + type: object + description: Registration response + required: + - clientDataJSON + - attestationObject + properties: + clientDataJSON: + type: string + description: Client data JSON + example: "base64clientdata..." + attestationObject: + type: string + description: Attestation object + example: "base64attestation..." + authenticatorData: + type: string + description: Authenticator data + example: "base64authenticatordata..." + transports: + type: array + description: Supported transports + items: + type: string + enum: ["usb", "nfc", "ble", "internal", "smart-card", "cable", "hybrid"] + publicKey: + type: string + description: Public key + example: "base64publickey..." + publicKeyAlgorithm: + type: number + description: Public key algorithm + example: -7 + type: + type: string + description: Credential type + enum: ["public-key"] + + authenticationPayload: + type: object + description: WebAuthn authentication payload + required: + - id + - rawId + - response + - type + properties: + id: + type: string + description: Credential ID + example: "cred_123..." + rawId: + type: string + description: Raw credential ID + example: "base64rawid..." + authenticatorAttachment: + type: string + description: Type of authenticator + enum: ["platform", "cross-platform"] + clientExtensionResults: + type: object + description: Client extension results + additionalProperties: true + response: + type: object + description: Authentication response + required: + - clientDataJSON + - authenticatorData + - signature + properties: + clientDataJSON: + type: string + description: Client data JSON + example: "base64clientdata..." + authenticatorData: + type: string + description: Authenticator data + example: "base64authenticatordata..." + signature: + type: string + description: Authentication signature + example: "base64signature..." + userHandle: + type: string + description: User handle + example: "base64userhandle..." + type: + type: string + description: Credential type + enum: ["public-key"] + + securitySchemes: + AccessTokenCookie: + description: This is an HTTPOnly cookie, set by sign-in and refresh endpoints and present on requests that update the access token + type: apiKey + in: cookie + name: sAccessToken + + AccessTokenBearer: + description: Returned as the "st-access-token" header from sign-in and refresh endpoints and present on requests that update the access token payload + type: http + scheme: bearer + + RefreshTokenBearer: + description: Returned as the "st-refresh-token" header from sign-in and refresh endpoints + scheme: bearer + type: http + + RefreshTokenCookie: + description: This is an HTTPOnly cookie, set by the sign-in and refresh endpoints + type: apiKey + in: cookie + name: sRefreshToken + + OAuth2AccessTokenBearer: + description: An OAuth2 access token returned by the token or authorization endpoints during OAuth flows + type: http + scheme: bearer diff --git a/static/fonts/IBMPlexMono-Regular.ttf b/public/fonts/IBMPlexMono-Regular.ttf similarity index 100% rename from static/fonts/IBMPlexMono-Regular.ttf rename to public/fonts/IBMPlexMono-Regular.ttf diff --git a/static/fonts/IBMPlexMono-Thin.ttf b/public/fonts/IBMPlexMono-Thin.ttf similarity index 100% rename from static/fonts/IBMPlexMono-Thin.ttf rename to public/fonts/IBMPlexMono-Thin.ttf diff --git a/static/img/account-linking/err_001.png b/public/img/account-linking/err_001.png similarity index 100% rename from static/img/account-linking/err_001.png rename to public/img/account-linking/err_001.png diff --git a/static/img/account-linking/err_002.png b/public/img/account-linking/err_002.png similarity index 100% rename from static/img/account-linking/err_002.png rename to public/img/account-linking/err_002.png diff --git a/static/img/account-linking/err_003.png b/public/img/account-linking/err_003.png similarity index 100% rename from static/img/account-linking/err_003.png rename to public/img/account-linking/err_003.png diff --git a/static/img/account-linking/err_004.png b/public/img/account-linking/err_004.png similarity index 100% rename from static/img/account-linking/err_004.png rename to public/img/account-linking/err_004.png diff --git a/static/img/account-linking/err_005.png b/public/img/account-linking/err_005.png similarity index 100% rename from static/img/account-linking/err_005.png rename to public/img/account-linking/err_005.png diff --git a/static/img/account-linking/err_006.png b/public/img/account-linking/err_006.png similarity index 100% rename from static/img/account-linking/err_006.png rename to public/img/account-linking/err_006.png diff --git a/static/img/account-linking/err_007.png b/public/img/account-linking/err_007.png similarity index 100% rename from static/img/account-linking/err_007.png rename to public/img/account-linking/err_007.png diff --git a/static/img/account-linking/err_008.png b/public/img/account-linking/err_008.png similarity index 100% rename from static/img/account-linking/err_008.png rename to public/img/account-linking/err_008.png diff --git a/static/img/active-recipe-icon.png b/public/img/active-recipe-icon.png similarity index 100% rename from static/img/active-recipe-icon.png rename to public/img/active-recipe-icon.png diff --git a/static/img/architecture/managed_service.png b/public/img/architecture/managed_service.png similarity index 100% rename from static/img/architecture/managed_service.png rename to public/img/architecture/managed_service.png diff --git a/static/img/architecture/managed_service_generic.png b/public/img/architecture/managed_service_generic.png similarity index 100% rename from static/img/architecture/managed_service_generic.png rename to public/img/architecture/managed_service_generic.png diff --git a/static/img/architecture/managed_service_without_dashboard.png b/public/img/architecture/managed_service_without_dashboard.png similarity index 100% rename from static/img/architecture/managed_service_without_dashboard.png rename to public/img/architecture/managed_service_without_dashboard.png diff --git a/static/img/architecture/self_hosted.png b/public/img/architecture/self_hosted.png similarity index 100% rename from static/img/architecture/self_hosted.png rename to public/img/architecture/self_hosted.png diff --git a/static/img/architecture/self_hosted_generic.png b/public/img/architecture/self_hosted_generic.png similarity index 100% rename from static/img/architecture/self_hosted_generic.png rename to public/img/architecture/self_hosted_generic.png diff --git a/static/img/architecture/self_hosted_without_dashboard.png b/public/img/architecture/self_hosted_without_dashboard.png similarity index 100% rename from static/img/architecture/self_hosted_without_dashboard.png rename to public/img/architecture/self_hosted_without_dashboard.png diff --git a/static/img/arrow-down.svg b/public/img/arrow-down.svg similarity index 100% rename from static/img/arrow-down.svg rename to public/img/arrow-down.svg diff --git a/static/img/attackprotectionsuite/sequence-diagram.png b/public/img/attackprotectionsuite/sequence-diagram.png similarity index 100% rename from static/img/attackprotectionsuite/sequence-diagram.png rename to public/img/attackprotectionsuite/sequence-diagram.png diff --git a/static/img/avg-latency.png b/public/img/avg-latency.png similarity index 100% rename from static/img/avg-latency.png rename to public/img/avg-latency.png diff --git a/static/img/change-user.png b/public/img/change-user.png similarity index 100% rename from static/img/change-user.png rename to public/img/change-user.png diff --git a/static/img/dashboard/assign-role.png b/public/img/dashboard/assign-role.png similarity index 100% rename from static/img/dashboard/assign-role.png rename to public/img/dashboard/assign-role.png diff --git a/static/img/dashboard/create-role.gif b/public/img/dashboard/create-role.gif similarity index 100% rename from static/img/dashboard/create-role.gif rename to public/img/dashboard/create-role.gif diff --git a/static/img/dashboard/create-role.png b/public/img/dashboard/create-role.png similarity index 100% rename from static/img/dashboard/create-role.png rename to public/img/dashboard/create-role.png diff --git a/static/img/dashboard/csp-error.png b/public/img/dashboard/csp-error.png similarity index 100% rename from static/img/dashboard/csp-error.png rename to public/img/dashboard/csp-error.png diff --git a/static/img/dashboard/forgot-password.png b/public/img/dashboard/forgot-password.png similarity index 100% rename from static/img/dashboard/forgot-password.png rename to public/img/dashboard/forgot-password.png diff --git a/static/img/dashboard/login.png b/public/img/dashboard/login.png similarity index 100% rename from static/img/dashboard/login.png rename to public/img/dashboard/login.png diff --git a/static/img/dashboard/no-roles-created.png b/public/img/dashboard/no-roles-created.png similarity index 100% rename from static/img/dashboard/no-roles-created.png rename to public/img/dashboard/no-roles-created.png diff --git a/static/img/dashboard/no-users.png b/public/img/dashboard/no-users.png similarity index 100% rename from static/img/dashboard/no-users.png rename to public/img/dashboard/no-users.png diff --git a/static/img/dashboard/one-user.png b/public/img/dashboard/one-user.png similarity index 100% rename from static/img/dashboard/one-user.png rename to public/img/dashboard/one-user.png diff --git a/static/img/dashboard/preview-role.png b/public/img/dashboard/preview-role.png similarity index 100% rename from static/img/dashboard/preview-role.png rename to public/img/dashboard/preview-role.png diff --git a/static/img/dashboard/reset-password.png b/public/img/dashboard/reset-password.png similarity index 100% rename from static/img/dashboard/reset-password.png rename to public/img/dashboard/reset-password.png diff --git a/static/img/dashboard/roles-list.png b/public/img/dashboard/roles-list.png similarity index 100% rename from static/img/dashboard/roles-list.png rename to public/img/dashboard/roles-list.png diff --git a/static/img/dashboard/select-tenant.png b/public/img/dashboard/select-tenant.png similarity index 100% rename from static/img/dashboard/select-tenant.png rename to public/img/dashboard/select-tenant.png diff --git a/static/img/dashboard/signup.png b/public/img/dashboard/signup.png similarity index 100% rename from static/img/dashboard/signup.png rename to public/img/dashboard/signup.png diff --git a/static/img/dashboard/tenant-management/active-directory.png b/public/img/dashboard/tenant-management/active-directory.png similarity index 100% rename from static/img/dashboard/tenant-management/active-directory.png rename to public/img/dashboard/tenant-management/active-directory.png diff --git a/static/img/dashboard/tenant-management/add-provider-prompt.png b/public/img/dashboard/tenant-management/add-provider-prompt.png similarity index 100% rename from static/img/dashboard/tenant-management/add-provider-prompt.png rename to public/img/dashboard/tenant-management/add-provider-prompt.png diff --git a/static/img/dashboard/tenant-management/all-enabled.png b/public/img/dashboard/tenant-management/all-enabled.png similarity index 100% rename from static/img/dashboard/tenant-management/all-enabled.png rename to public/img/dashboard/tenant-management/all-enabled.png diff --git a/static/img/dashboard/tenant-management/core-config.png b/public/img/dashboard/tenant-management/core-config.png similarity index 100% rename from static/img/dashboard/tenant-management/core-config.png rename to public/img/dashboard/tenant-management/core-config.png diff --git a/static/img/dashboard/tenant-management/create-provider/create-active-directory.gif b/public/img/dashboard/tenant-management/create-provider/create-active-directory.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-active-directory.gif rename to public/img/dashboard/tenant-management/create-provider/create-active-directory.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-apple.gif b/public/img/dashboard/tenant-management/create-provider/create-apple.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-apple.gif rename to public/img/dashboard/tenant-management/create-provider/create-apple.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-bitbucket.gif b/public/img/dashboard/tenant-management/create-provider/create-bitbucket.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-bitbucket.gif rename to public/img/dashboard/tenant-management/create-provider/create-bitbucket.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-discord.gif b/public/img/dashboard/tenant-management/create-provider/create-discord.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-discord.gif rename to public/img/dashboard/tenant-management/create-provider/create-discord.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-facebook.gif b/public/img/dashboard/tenant-management/create-provider/create-facebook.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-facebook.gif rename to public/img/dashboard/tenant-management/create-provider/create-facebook.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-github.gif b/public/img/dashboard/tenant-management/create-provider/create-github.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-github.gif rename to public/img/dashboard/tenant-management/create-provider/create-github.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-gitlab.gif b/public/img/dashboard/tenant-management/create-provider/create-gitlab.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-gitlab.gif rename to public/img/dashboard/tenant-management/create-provider/create-gitlab.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-google-workspaces.gif b/public/img/dashboard/tenant-management/create-provider/create-google-workspaces.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-google-workspaces.gif rename to public/img/dashboard/tenant-management/create-provider/create-google-workspaces.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-google.gif b/public/img/dashboard/tenant-management/create-provider/create-google.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-google.gif rename to public/img/dashboard/tenant-management/create-provider/create-google.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-linkedin.gif b/public/img/dashboard/tenant-management/create-provider/create-linkedin.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-linkedin.gif rename to public/img/dashboard/tenant-management/create-provider/create-linkedin.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-okta.gif b/public/img/dashboard/tenant-management/create-provider/create-okta.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-okta.gif rename to public/img/dashboard/tenant-management/create-provider/create-okta.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-public-google.gif b/public/img/dashboard/tenant-management/create-provider/create-public-google.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-public-google.gif rename to public/img/dashboard/tenant-management/create-provider/create-public-google.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-saml.gif b/public/img/dashboard/tenant-management/create-provider/create-saml.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-saml.gif rename to public/img/dashboard/tenant-management/create-provider/create-saml.gif diff --git a/static/img/dashboard/tenant-management/create-provider/create-twitter.gif b/public/img/dashboard/tenant-management/create-provider/create-twitter.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-provider/create-twitter.gif rename to public/img/dashboard/tenant-management/create-provider/create-twitter.gif diff --git a/static/img/dashboard/tenant-management/create-tenant.gif b/public/img/dashboard/tenant-management/create-tenant.gif similarity index 100% rename from static/img/dashboard/tenant-management/create-tenant.gif rename to public/img/dashboard/tenant-management/create-tenant.gif diff --git a/static/img/dashboard/tenant-management/create-tenant.png b/public/img/dashboard/tenant-management/create-tenant.png similarity index 100% rename from static/img/dashboard/tenant-management/create-tenant.png rename to public/img/dashboard/tenant-management/create-tenant.png diff --git a/static/img/dashboard/tenant-management/custom-provider-basic-details.png b/public/img/dashboard/tenant-management/custom-provider-basic-details.png similarity index 100% rename from static/img/dashboard/tenant-management/custom-provider-basic-details.png rename to public/img/dashboard/tenant-management/custom-provider-basic-details.png diff --git a/static/img/dashboard/tenant-management/custom-tenant-config.png b/public/img/dashboard/tenant-management/custom-tenant-config.png similarity index 100% rename from static/img/dashboard/tenant-management/custom-tenant-config.png rename to public/img/dashboard/tenant-management/custom-tenant-config.png diff --git a/static/img/dashboard/tenant-management/details.png b/public/img/dashboard/tenant-management/details.png similarity index 100% rename from static/img/dashboard/tenant-management/details.png rename to public/img/dashboard/tenant-management/details.png diff --git a/static/img/dashboard/tenant-management/edit-core-config.png b/public/img/dashboard/tenant-management/edit-core-config.png similarity index 100% rename from static/img/dashboard/tenant-management/edit-core-config.png rename to public/img/dashboard/tenant-management/edit-core-config.png diff --git a/static/img/dashboard/tenant-management/enable-ep-tp.png b/public/img/dashboard/tenant-management/enable-ep-tp.png similarity index 100% rename from static/img/dashboard/tenant-management/enable-ep-tp.png rename to public/img/dashboard/tenant-management/enable-ep-tp.png diff --git a/static/img/dashboard/tenant-management/enable-tp-ep-emailotp.png b/public/img/dashboard/tenant-management/enable-tp-ep-emailotp.png similarity index 100% rename from static/img/dashboard/tenant-management/enable-tp-ep-emailotp.png rename to public/img/dashboard/tenant-management/enable-tp-ep-emailotp.png diff --git a/static/img/dashboard/tenant-management/ep-create-tenant.gif b/public/img/dashboard/tenant-management/ep-create-tenant.gif similarity index 100% rename from static/img/dashboard/tenant-management/ep-create-tenant.gif rename to public/img/dashboard/tenant-management/ep-create-tenant.gif diff --git a/static/img/dashboard/tenant-management/ep-enabled.png b/public/img/dashboard/tenant-management/ep-enabled.png similarity index 100% rename from static/img/dashboard/tenant-management/ep-enabled.png rename to public/img/dashboard/tenant-management/ep-enabled.png diff --git a/static/img/dashboard/tenant-management/landing.png b/public/img/dashboard/tenant-management/landing.png similarity index 100% rename from static/img/dashboard/tenant-management/landing.png rename to public/img/dashboard/tenant-management/landing.png diff --git a/static/img/dashboard/tenant-management/login-methods.png b/public/img/dashboard/tenant-management/login-methods.png similarity index 100% rename from static/img/dashboard/tenant-management/login-methods.png rename to public/img/dashboard/tenant-management/login-methods.png diff --git a/static/img/dashboard/tenant-management/new-boxy-config.gif b/public/img/dashboard/tenant-management/new-boxy-config.gif similarity index 100% rename from static/img/dashboard/tenant-management/new-boxy-config.gif rename to public/img/dashboard/tenant-management/new-boxy-config.gif diff --git a/static/img/dashboard/tenant-management/new-oauth-provider.png b/public/img/dashboard/tenant-management/new-oauth-provider.png similarity index 100% rename from static/img/dashboard/tenant-management/new-oauth-provider.png rename to public/img/dashboard/tenant-management/new-oauth-provider.png diff --git a/static/img/dashboard/tenant-management/new-oidc-provider.png b/public/img/dashboard/tenant-management/new-oidc-provider.png similarity index 100% rename from static/img/dashboard/tenant-management/new-oidc-provider.png rename to public/img/dashboard/tenant-management/new-oidc-provider.png diff --git a/static/img/dashboard/tenant-management/new-provider-details.png b/public/img/dashboard/tenant-management/new-provider-details.png similarity index 100% rename from static/img/dashboard/tenant-management/new-provider-details.png rename to public/img/dashboard/tenant-management/new-provider-details.png diff --git a/static/img/dashboard/tenant-management/new-provider.png b/public/img/dashboard/tenant-management/new-provider.png similarity index 100% rename from static/img/dashboard/tenant-management/new-provider.png rename to public/img/dashboard/tenant-management/new-provider.png diff --git a/static/img/dashboard/tenant-management/openid-config.png b/public/img/dashboard/tenant-management/openid-config.png similarity index 100% rename from static/img/dashboard/tenant-management/openid-config.png rename to public/img/dashboard/tenant-management/openid-config.png diff --git a/static/img/dashboard/tenant-management/otp-email-enabled.png b/public/img/dashboard/tenant-management/otp-email-enabled.png similarity index 100% rename from static/img/dashboard/tenant-management/otp-email-enabled.png rename to public/img/dashboard/tenant-management/otp-email-enabled.png diff --git a/static/img/dashboard/tenant-management/pl-create-tenant.gif b/public/img/dashboard/tenant-management/pl-create-tenant.gif similarity index 100% rename from static/img/dashboard/tenant-management/pl-create-tenant.gif rename to public/img/dashboard/tenant-management/pl-create-tenant.gif diff --git a/static/img/dashboard/tenant-management/saml-config-via-api.png b/public/img/dashboard/tenant-management/saml-config-via-api.png similarity index 100% rename from static/img/dashboard/tenant-management/saml-config-via-api.png rename to public/img/dashboard/tenant-management/saml-config-via-api.png diff --git a/static/img/dashboard/tenant-management/saml-config.png b/public/img/dashboard/tenant-management/saml-config.png similarity index 100% rename from static/img/dashboard/tenant-management/saml-config.png rename to public/img/dashboard/tenant-management/saml-config.png diff --git a/static/img/dashboard/tenant-management/saml-prompt.png b/public/img/dashboard/tenant-management/saml-prompt.png similarity index 100% rename from static/img/dashboard/tenant-management/saml-prompt.png rename to public/img/dashboard/tenant-management/saml-prompt.png diff --git a/static/img/dashboard/tenant-management/secondary-factors.png b/public/img/dashboard/tenant-management/secondary-factors.png similarity index 100% rename from static/img/dashboard/tenant-management/secondary-factors.png rename to public/img/dashboard/tenant-management/secondary-factors.png diff --git a/static/img/dashboard/tenant-management/tenant-users.png b/public/img/dashboard/tenant-management/tenant-users.png similarity index 100% rename from static/img/dashboard/tenant-management/tenant-users.png rename to public/img/dashboard/tenant-management/tenant-users.png diff --git a/static/img/dashboard/tenant-management/third-party-providers.png b/public/img/dashboard/tenant-management/third-party-providers.png similarity index 100% rename from static/img/dashboard/tenant-management/third-party-providers.png rename to public/img/dashboard/tenant-management/third-party-providers.png diff --git a/static/img/dashboard/tenant-management/tp-create-tenant.gif b/public/img/dashboard/tenant-management/tp-create-tenant.gif similarity index 100% rename from static/img/dashboard/tenant-management/tp-create-tenant.gif rename to public/img/dashboard/tenant-management/tp-create-tenant.gif diff --git a/static/img/dashboard/tenant-management/tpep-create-tenant.gif b/public/img/dashboard/tenant-management/tpep-create-tenant.gif similarity index 100% rename from static/img/dashboard/tenant-management/tpep-create-tenant.gif rename to public/img/dashboard/tenant-management/tpep-create-tenant.gif diff --git a/static/img/dashboard/tenant-management/tpep-create-thirdparty.gif b/public/img/dashboard/tenant-management/tpep-create-thirdparty.gif similarity index 100% rename from static/img/dashboard/tenant-management/tpep-create-thirdparty.gif rename to public/img/dashboard/tenant-management/tpep-create-thirdparty.gif diff --git a/static/img/dashboard/tenant-management/tpl-create-tenant.gif b/public/img/dashboard/tenant-management/tpl-create-tenant.gif similarity index 100% rename from static/img/dashboard/tenant-management/tpl-create-tenant.gif rename to public/img/dashboard/tenant-management/tpl-create-tenant.gif diff --git a/static/img/dashboard/user-info-continued.png b/public/img/dashboard/user-info-continued.png similarity index 100% rename from static/img/dashboard/user-info-continued.png rename to public/img/dashboard/user-info-continued.png diff --git a/static/img/dashboard/user-info.png b/public/img/dashboard/user-info.png similarity index 100% rename from static/img/dashboard/user-info.png rename to public/img/dashboard/user-info.png diff --git a/static/img/dashboard/view-assigned-roles.png b/public/img/dashboard/view-assigned-roles.png similarity index 100% rename from static/img/dashboard/view-assigned-roles.png rename to public/img/dashboard/view-assigned-roles.png diff --git a/static/img/discord-yellow.png b/public/img/discord-yellow.png similarity index 100% rename from static/img/discord-yellow.png rename to public/img/discord-yellow.png diff --git a/static/img/discord.png b/public/img/discord.png similarity index 100% rename from static/img/discord.png rename to public/img/discord.png diff --git a/static/img/docs-left-menu-chevron.png b/public/img/docs-left-menu-chevron.png similarity index 100% rename from static/img/docs-left-menu-chevron.png rename to public/img/docs-left-menu-chevron.png diff --git a/static/img/email-verification-clicked-no-session.png b/public/img/email-verification-clicked-no-session.png similarity index 100% rename from static/img/email-verification-clicked-no-session.png rename to public/img/email-verification-clicked-no-session.png diff --git a/static/img/email-verification-link-expired.png b/public/img/email-verification-link-expired.png similarity index 100% rename from static/img/email-verification-link-expired.png rename to public/img/email-verification-link-expired.png diff --git a/static/img/email-verification-link-generic-error.png b/public/img/email-verification-link-generic-error.png similarity index 100% rename from static/img/email-verification-link-generic-error.png rename to public/img/email-verification-link-generic-error.png diff --git a/static/img/email-verification-send-email-generic-error.png b/public/img/email-verification-send-email-generic-error.png similarity index 100% rename from static/img/email-verification-send-email-generic-error.png rename to public/img/email-verification-send-email-generic-error.png diff --git a/static/img/email-verification-send-email.png b/public/img/email-verification-send-email.png similarity index 100% rename from static/img/email-verification-send-email.png rename to public/img/email-verification-send-email.png diff --git a/static/img/email-verification-success.png b/public/img/email-verification-success.png similarity index 100% rename from static/img/email-verification-success.png rename to public/img/email-verification-success.png diff --git a/static/img/emailpassword-field-validation-error.png b/public/img/emailpassword-field-validation-error.png similarity index 100% rename from static/img/emailpassword-field-validation-error.png rename to public/img/emailpassword-field-validation-error.png diff --git a/static/img/emailpassword-general-error.png b/public/img/emailpassword-general-error.png similarity index 100% rename from static/img/emailpassword-general-error.png rename to public/img/emailpassword-general-error.png diff --git a/static/img/emailpassword-sign-in.png b/public/img/emailpassword-sign-in.png similarity index 100% rename from static/img/emailpassword-sign-in.png rename to public/img/emailpassword-sign-in.png diff --git a/static/img/emailpassword-sign-up.png b/public/img/emailpassword-sign-up.png similarity index 100% rename from static/img/emailpassword-sign-up.png rename to public/img/emailpassword-sign-up.png diff --git a/static/img/emailpassword-wrong-cred.png b/public/img/emailpassword-wrong-cred.png similarity index 100% rename from static/img/emailpassword-wrong-cred.png rename to public/img/emailpassword-wrong-cred.png diff --git a/static/img/emailpassword/buttonText.png b/public/img/emailpassword/buttonText.png similarity index 100% rename from static/img/emailpassword/buttonText.png rename to public/img/emailpassword/buttonText.png diff --git a/static/img/emailpassword/change-user.png b/public/img/emailpassword/change-user.png similarity index 100% rename from static/img/emailpassword/change-user.png rename to public/img/emailpassword/change-user.png diff --git a/static/img/emailpassword/custom-field-name-signup-ep.png b/public/img/emailpassword/custom-field-name-signup-ep.png similarity index 100% rename from static/img/emailpassword/custom-field-name-signup-ep.png rename to public/img/emailpassword/custom-field-name-signup-ep.png diff --git a/static/img/emailpassword/email-verification-successful.png b/public/img/emailpassword/email-verification-successful.png similarity index 100% rename from static/img/emailpassword/email-verification-successful.png rename to public/img/emailpassword/email-verification-successful.png diff --git a/static/img/emailpassword/email-verify-email.png b/public/img/emailpassword/email-verify-email.png similarity index 100% rename from static/img/emailpassword/email-verify-email.png rename to public/img/emailpassword/email-verify-email.png diff --git a/static/img/emailpassword/error.png b/public/img/emailpassword/error.png similarity index 100% rename from static/img/emailpassword/error.png rename to public/img/emailpassword/error.png diff --git a/static/img/emailpassword/input-background.png b/public/img/emailpassword/input-background.png similarity index 100% rename from static/img/emailpassword/input-background.png rename to public/img/emailpassword/input-background.png diff --git a/static/img/emailpassword/inspect-button-2.png b/public/img/emailpassword/inspect-button-2.png similarity index 100% rename from static/img/emailpassword/inspect-button-2.png rename to public/img/emailpassword/inspect-button-2.png diff --git a/static/img/emailpassword/inspect-button.png b/public/img/emailpassword/inspect-button.png similarity index 100% rename from static/img/emailpassword/inspect-button.png rename to public/img/emailpassword/inspect-button.png diff --git a/static/img/emailpassword/modified-formfields.png b/public/img/emailpassword/modified-formfields.png similarity index 100% rename from static/img/emailpassword/modified-formfields.png rename to public/img/emailpassword/modified-formfields.png diff --git a/static/img/emailpassword/override/find-component.png b/public/img/emailpassword/override/find-component.png similarity index 100% rename from static/img/emailpassword/override/find-component.png rename to public/img/emailpassword/override/find-component.png diff --git a/static/img/emailpassword/pass-reset-email.png b/public/img/emailpassword/pass-reset-email.png similarity index 100% rename from static/img/emailpassword/pass-reset-email.png rename to public/img/emailpassword/pass-reset-email.png diff --git a/static/img/emailpassword/password-manager.png b/public/img/emailpassword/password-manager.png similarity index 100% rename from static/img/emailpassword/password-manager.png rename to public/img/emailpassword/password-manager.png diff --git a/static/img/emailpassword/primary.png b/public/img/emailpassword/primary.png similarity index 100% rename from static/img/emailpassword/primary.png rename to public/img/emailpassword/primary.png diff --git a/static/img/emailpassword/react-override-octocat.png b/public/img/emailpassword/react-override-octocat.png similarity index 100% rename from static/img/emailpassword/react-override-octocat.png rename to public/img/emailpassword/react-override-octocat.png diff --git a/static/img/emailpassword/reset-password-enter-email.png b/public/img/emailpassword/reset-password-enter-email.png similarity index 100% rename from static/img/emailpassword/reset-password-enter-email.png rename to public/img/emailpassword/reset-password-enter-email.png diff --git a/static/img/emailpassword/reset-password-submit-new-password.png b/public/img/emailpassword/reset-password-submit-new-password.png similarity index 100% rename from static/img/emailpassword/reset-password-submit-new-password.png rename to public/img/emailpassword/reset-password-submit-new-password.png diff --git a/static/img/emailpassword/saas-connect-popup.png b/public/img/emailpassword/saas-connect-popup.png similarity index 100% rename from static/img/emailpassword/saas-connect-popup.png rename to public/img/emailpassword/saas-connect-popup.png diff --git a/static/img/emailpassword/signin-dark.png b/public/img/emailpassword/signin-dark.png similarity index 100% rename from static/img/emailpassword/signin-dark.png rename to public/img/emailpassword/signin-dark.png diff --git a/static/img/emailpassword/signin-with-custom-error-msg.png b/public/img/emailpassword/signin-with-custom-error-msg.png similarity index 100% rename from static/img/emailpassword/signin-with-custom-error-msg.png rename to public/img/emailpassword/signin-with-custom-error-msg.png diff --git a/static/img/emailpassword/signin-with-default-values.png b/public/img/emailpassword/signin-with-default-values.png similarity index 100% rename from static/img/emailpassword/signin-with-default-values.png rename to public/img/emailpassword/signin-with-default-values.png diff --git a/static/img/emailpassword/signup-centered-blue-button.png b/public/img/emailpassword/signup-centered-blue-button.png similarity index 100% rename from static/img/emailpassword/signup-centered-blue-button.png rename to public/img/emailpassword/signup-centered-blue-button.png diff --git a/static/img/emailpassword/signup-light.png b/public/img/emailpassword/signup-light.png similarity index 100% rename from static/img/emailpassword/signup-light.png rename to public/img/emailpassword/signup-light.png diff --git a/static/img/emailpassword/signup-with-custom-components.png b/public/img/emailpassword/signup-with-custom-components.png similarity index 100% rename from static/img/emailpassword/signup-with-custom-components.png rename to public/img/emailpassword/signup-with-custom-components.png diff --git a/static/img/emailpassword/signup-with-custom-error-msg.png b/public/img/emailpassword/signup-with-custom-error-msg.png similarity index 100% rename from static/img/emailpassword/signup-with-custom-error-msg.png rename to public/img/emailpassword/signup-with-custom-error-msg.png diff --git a/static/img/emailpassword/signup-with-custom-field-order.png b/public/img/emailpassword/signup-with-custom-field-order.png similarity index 100% rename from static/img/emailpassword/signup-with-custom-field-order.png rename to public/img/emailpassword/signup-with-custom-field-order.png diff --git a/static/img/emailpassword/signup-with-default-values.png b/public/img/emailpassword/signup-with-default-values.png similarity index 100% rename from static/img/emailpassword/signup-with-default-values.png rename to public/img/emailpassword/signup-with-default-values.png diff --git a/static/img/emailpassword/signup-with-name-and-age-failure.png b/public/img/emailpassword/signup-with-name-and-age-failure.png similarity index 100% rename from static/img/emailpassword/signup-with-name-and-age-failure.png rename to public/img/emailpassword/signup-with-name-and-age-failure.png diff --git a/static/img/emailpassword/signup-with-name-and-age.png b/public/img/emailpassword/signup-with-name-and-age.png similarity index 100% rename from static/img/emailpassword/signup-with-name-and-age.png rename to public/img/emailpassword/signup-with-name-and-age.png diff --git a/static/img/emailpassword/sp-test-signup.png b/public/img/emailpassword/sp-test-signup.png similarity index 100% rename from static/img/emailpassword/sp-test-signup.png rename to public/img/emailpassword/sp-test-signup.png diff --git a/static/img/emailpassword/st-ep-refresh-cookies.png b/public/img/emailpassword/st-ep-refresh-cookies.png similarity index 100% rename from static/img/emailpassword/st-ep-refresh-cookies.png rename to public/img/emailpassword/st-ep-refresh-cookies.png diff --git a/static/img/emailpassword/st-ep-refresh.png b/public/img/emailpassword/st-ep-refresh.png similarity index 100% rename from static/img/emailpassword/st-ep-refresh.png rename to public/img/emailpassword/st-ep-refresh.png diff --git a/static/img/emailpassword/st-ep-signout.png b/public/img/emailpassword/st-ep-signout.png similarity index 100% rename from static/img/emailpassword/st-ep-signout.png rename to public/img/emailpassword/st-ep-signout.png diff --git a/static/img/emailpassword/st-test-signin-cookies.png b/public/img/emailpassword/st-test-signin-cookies.png similarity index 100% rename from static/img/emailpassword/st-test-signin-cookies.png rename to public/img/emailpassword/st-test-signin-cookies.png diff --git a/static/img/emailpassword/st-user-unauthorized.png b/public/img/emailpassword/st-user-unauthorized.png similarity index 100% rename from static/img/emailpassword/st-user-unauthorized.png rename to public/img/emailpassword/st-user-unauthorized.png diff --git a/static/img/emailpassword/success.png b/public/img/emailpassword/success.png similarity index 100% rename from static/img/emailpassword/success.png rename to public/img/emailpassword/success.png diff --git a/static/img/emailpassword/textInput.png b/public/img/emailpassword/textInput.png similarity index 100% rename from static/img/emailpassword/textInput.png rename to public/img/emailpassword/textInput.png diff --git a/static/img/emailpassword/textLabel.png b/public/img/emailpassword/textLabel.png similarity index 100% rename from static/img/emailpassword/textLabel.png rename to public/img/emailpassword/textLabel.png diff --git a/static/img/emailpassword/textPrimary.png b/public/img/emailpassword/textPrimary.png similarity index 100% rename from static/img/emailpassword/textPrimary.png rename to public/img/emailpassword/textPrimary.png diff --git a/static/img/emailpassword/textTitle.png b/public/img/emailpassword/textTitle.png similarity index 100% rename from static/img/emailpassword/textTitle.png rename to public/img/emailpassword/textTitle.png diff --git a/static/img/emailpassword/verify-email-screen.png b/public/img/emailpassword/verify-email-screen.png similarity index 100% rename from static/img/emailpassword/verify-email-screen.png rename to public/img/emailpassword/verify-email-screen.png diff --git a/static/img/emailverification/resend-with-border.png b/public/img/emailverification/resend-with-border.png similarity index 100% rename from static/img/emailverification/resend-with-border.png rename to public/img/emailverification/resend-with-border.png diff --git a/static/img/enter-otp-error.png b/public/img/enter-otp-error.png similarity index 100% rename from static/img/enter-otp-error.png rename to public/img/enter-otp-error.png diff --git a/static/img/enter-otp-invalid.png b/public/img/enter-otp-invalid.png similarity index 100% rename from static/img/enter-otp-invalid.png rename to public/img/enter-otp-invalid.png diff --git a/static/img/enter-otp-screen.png b/public/img/enter-otp-screen.png similarity index 100% rename from static/img/enter-otp-screen.png rename to public/img/enter-otp-screen.png diff --git a/public/img/favicon.ico b/public/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d6c03af6c56acb822f313745b9448b120bdd9857 GIT binary patch literal 4432 zcmY*dcUTk7vIUGZX+}V*h86{sgiwQ_6FMTD04kl(OG1fAm1^j{E4_(;bVPbbKzi?8 zK&l8*y!gBK-S^&p-|WuJo;hb`|J=}LPZcQ1naBwU2q={lk015F4@+}+*z+y(d?U92Gda5x+Sg+XAj$JdC*7@Pyv z#N)98hU4EP|HC6^fiZKjcEVaaI)MK2nwUDeV#V3n{|fzg{ku=BwdMaRIbi-X*7bmp zzc&zmJ}BhB+}EXuzgaPL7i)`a<-hzA{D^;$|1b9+9R%dB`2T6<-;@56y&hG990B?7 zvq_Mvwmv`+5Ku=c$w_OYZ|+sfbu z!bmCPtnsYnXp0}cUVr3DquV`{78hPoM4yk}>=-sSb199!H&@AU_x#mBHV&-wJFE zfKw5_>Ggh)V_Ht=xG})RR~9U5mA`0cHx(o#rQ zuvkWU?D^Ganu-lIvR^FOW zDS3H=uUA)HM{D&fUX8X;7`zGuUheT6D2KSw4e(Pu;u?a}IN->`-@+?{w)jcL=^<*Am z+SYrO;x+dXjsgADpM%cACtiM^X)LV(QkV!?QJjHs*@@v9|YlMz93ZE0v3Q zk#f$SykblCjIM}iQV=JyMul%B=%@Z@I6LUP{c^4`*KsHdnR#_}wF0YKxl!T$B~Z=# zc}eQPa&FQQ~mkm47ZagV!8|% z_1@Y5=Y=#2i*>-9l?Lhhkl0hxqi@_4(LFMv3}v0eF)&{(b=0lt+Jsug$=r2@v52~y z#@A$+l2 zm-6n(hr%4tFLaz#pBq&?(}sMQWd(sj1fC*DG=S)iQKC@TpWbGb72cX;jf~q#>WS>h zuV`8@hUp1{cTHmIytQ{FGw zuvQA$e~BtKTlZe?tFE2!7gy%eZOw34VJB$6SdDRaKHYkYMkwr1gvgs!I>j6}eRh1| z*VaLh7q@Vnf_s**&wRm9>ZA$lokDQjg_(pdjPkU;2GK;NgHLwmZV}(6RK^H)i2C!h z_%mjg1m18+oTf-&nt1aiX`DNsWMqe#5La51=!M&4aU%tkOc34*<0}Y@sSUU z{m}95&jm}{NqMoqvY3pnU`7`3M&3-&oPOraFQ+T(-ecp8#~Ps@=$ye)EtooeXiq5!gEVbL9+o`w4pftgGoyK_pt4y0;{}})WVjAWfjw3K{u6v;)doN z_}Id=Hi?~>eBlAn73}Y?HT%DsPWW$$oi2yJ8<`XvaHW1*ET?k68p+a+xS0+?!xz`(C53psbQfGjrF zxnFb9!77Z|-LE+m*a>-kp4QnHS=skPIhmPXL#uTfX!v6^x>JHaT})4#2cmi&FY}U6 z-)o%>?1P?;ORzBB8)t&c^R{{+qXz?a1}`j_x@xVIDh@2n$AYHG3n=sCj4l}-&klJf zX&_+PNB}dk!GVVuGCnfHJDyR zX;DH^d8$9%(wWBBwlhnXBQmhUEix;vyr?vYYTZl~Yf6A_iIJcAWg;|1nT-kmy)hPk zV9i<*&mt^O6UbhYY&6Lxf1BjKNo3QojE#YZ4iwlS`b|eNw+((8Cd_MTk^FQ)R5`7u z<`Q8327J5N2rHL8*!^NHrMPr>NG*p$LJ+6KA!r^C%B4`Qt-@i%JD$I%FPd!S`p#!( zuH8ra5;$kBY5^w>LkCJO>9C*Q3|aQ#3HLW)do(3!7g|6XwC7?j=qb(dVzyk*G2Y8b z0%xMw*tWD^YfTo_D{;u@XX@nijQS9*M-_=swFPxX*Dt=pXbX$~5)F)^6Dm&6%y z6Z2uvZgsY`i}=gyTBQPkv5-m1fpEEy?Xalj0PtZQLTuexAZa?>J!z_A3(3388*gX^ zZ-^@XG|vVlOzB%ITkEh#TfZbPjGgNAp#3(`Rvgu#WuT|aoc59mM`6_UBrKBS`Leo1 zS04asz*`enITuzO-E0$|Tf@LZl;MN-H86z>KAa5@6!o8_8ErA%_?-W6ctf?H5=9D^e?ReIm%n%=X z&lU1<_>S;MBsiYT+4{zrz`$y^C(fT5A*b*BW&_A+S_g>TcollYk*>UaAYzZj)Odn) zn#pd_FGnvR-e&2=nJJaf4f&tSoW*data0a|(VP1wJM$GJ>WDMiM%?ypfur3>bGu+J zg*oMG*D(hAL8jGJVHv`~9EZ2^0coQ8WlO+WtJeun0x3xyb{^m4iQtX=Rnk*R1N{X9 zcxMc0N4&@y?&D5jFb@gkkNNrIduNBFP4k&8elnS8xtitv)a1!BW{0Z5XO83`BapQ~ zWwc!4y_))RFn|mm4acHs29Gb(H%R_S*>-vId+LhAjQVaW7ZU|pTx`Adz9ΠX$7Q zL}agIQblIt6uZdCPwNkE&UQ-C#QVN~u(ta!i3EP4DPQKvW?NVKhstPEkhbmap$!#`_8~9MF*? z<7Ez1DmxvhqV9NnZ-L0J?kaXl-O(eWbS0lTaWfwC!Z6I!@}+DqK|QH8a_HO2S)3*- zyUbu-q4a+^r7|p&OcWzwgCfq!X_Y#;MC_a2+XVE14jYwn&i+ClcXm~qBDRVWp z+EhcAnn7f9lbDRysD#!PO%Hl?k7OYe=Q`4`I+zh62PsNeZ?QnILYtpU-aQr5{+QNu z*XJDIv=Uq5;UUoT=){RfTD}CKopBBb(oV-K6Uf;BrLb{p3NhwPt>BXl)r*pM_XQI^ zL+-cbkMCbR+HB@d0<>ov0ehSrD1#)_U{oD;L-BlClI>=r1CY8AAPbVLrcw8Y^j(cT zbFR8f9wimo)pqM~iZK3(s6@bsyxHig@gO}gI4E^r+lSZtr!qxk!@yhVleaO-VQF~5 zvqF4`N^AIQ0U5u%!V<6OU`MwNXN_M_-Tt{-_$ORCf`y1doM&7G^x_-q?s&jOx@-g| zHTio|+}C9xZ!cfpc}+!c^AzgIRPMb6_e&HC9tXtTQu3CJ=A=|_vW^l+rv!G{KZ z$>cnB3g;@ReA<4vWlJUEO6Scp|D&G6Q0Hur3iG}9#H*5zhm}VtV^)93NvJPTP(Qo* z2`y?+P`$0V-xp_`7_rRA$BK{}Neh-Z5{Ba{_}X>6DDX*d9(@arGc%{?i+#^sNt%ud z&1^d$5)>*Sw=Y4Eb&z7l(N71a-ukU4ZI5$-P_SkV!g8fSA-rW0Q$BwkV*|2(-|k+? zPZK#)K&K@0r_~4M?NhQ1XV7Y=aeQI&jbr8@ntsA9+q!+X#21gcEjKNH4^AOd+A{fP z`F9q_6G$lx{GQ+MFgnDsZCsE`3l(Z;`QO}aKDrT<$3vIfmyLpM9P(-}em4xb!-Zjk zFK0{5`m-6{njkF@UHW-v_Ge{y`e#P09kuiCer`$)J5}K&fIO;5d81j4)}z#!m8$4x zSbJ*a!KdilohMg`J{zCTyGAdnjQNG-Iq>9V?UIJV65f?q# z9`56I(p4Q9gJ1@;YU(d;i{0Ez@JwunfK0VJUEnxqy16XRhaJWgl#mPCGtIur6Oa29pzm+pzs`hChHKihnE;Axbz{8OV{t^<{(kXD%Wo zqDAQjIS-Jao;-(ugJ=WJSjiQPOyj&=uX8j{3 zKZFJtbfJ65Px#g20YA-@wK8z+45l?I(|N4dw|h9+ocImV_kJ&vjNz0hRYK0bI=1Ya zckqPl>(5&3R12;q=e4NB?OyeA8k`l0+Y!D#ypu&5@60hDRo=>MFMXBFw5RpM@CY>= z=KxWM)nP2|TgQf}s=30Fu*G|_R0N&)V>+?csK(XQ2@jG+v?VVu_>1}v$wJ)s!L5)! zbic7u)>uJ*!E@ix(fo%aRqAjL@_L { - let output = ""; - - const completionChunks = await openai.chat.completions.create({ - model: "gpt-4o", - temperature: 0.1, - messages: [ - { - role: "user", - content: ` - You are working on a documentation project that uses Docusaurus and vale.sh for linting. - You are tasked with fixing the linting errors in the provided markdown content. -`, - }, - { - role: "user", - content: ` - You will receive a document and the linting errors associated with it. - The document represents an MDX page from the documentation project - Return an updated document that has the linting errors fixed. - Read the document and return and a string that will act as a SEO description for the document - - Keep the description short. At most 15 words - - Be concise - - Do not use redundant phrasing like "This page does X". Just explain what it does - - Only explain the main idea of the page - - Use an active writing style. Explain what the user will be able to do by reading this page. - - Do not use adjectives like seamless, easy, fast or any kind of marketing speak. - You will return only the string. No other details besides that. - `, - }, - { - role: "user", - content: markdownContent, - }, - ], - stream: true, - }); - const spinner = ora("Receiving GPT message").start(); - let chunkIndex = 0; - for await (const chunk of completionChunks) { - chunkIndex++; - spinner.text = `Received chunk ${chunkIndex}`; - const stringChunk = chunk.choices[0]?.delta?.content || ""; - output += stringChunk; - } - spinner.succeed("Received GPT message"); - - return output; -}; - -const correctLinting = async (lintingIssues: ValeLintingIssue[]) => { - let output = ""; - - const completionChunks = await openai.chat.completions.create({ - model: "gpt-4o", - temperature: 0.2, - messages: [ - { - role: "developer", - content: ` - You are working on a documentation project that uses Docusaurus and vale.sh for linting. - You are tasked with fixing the linting issues from an MDX document. -`, - }, - { - role: "developer", - content: ` - You will receive a json encoded string with linting issues associated with it. - The JSON has the following format: - [{ - // the error message from vale.sh - ErrorMessage: string, - // the line of the MDX document that contains the issue - Value: string, - // the line number - Line: number - }] - Return the corrected lines in the same format as the input but with the Value property updated with the corrected line. - Only return the response array. Do not change the order of the array. It should be the same as the original array. - Respect the following rules when formulating the response: - - Only correct the vale errors. Do not include any additional information. - - Do not wrap the response in "\`\`\`markdown" backticks - - Do not wrap the response in "\`\`\`json" backticks - - Return the same amount of array elements as the input. Match the array elements by their index. - - If you do not know how to correct a line, return the original line. - - Do not change import statements - - Update lines that report "pasive voice" errors to use active voice - - Do not change values inside inline code expressions (single backticks: \`appInfo\`). Ignore errors for this type of expressions. - - Values that look like variable names should be wrapped in backticks (\`appInfo\`) - - If you encounter "signup" or "signin" errors, replace the words with "sign up" or "sign in" - - If you encounter "supertokens" errors, replace the words with "SuperTokens" - - If you encounter "Github" errors, replace the words with "GitHub" - - If you encounter "env var(s)" expressions, replace the words with "environment variable(s)" - - If you encounter "uri", "url", "api" expressions, replace the words with "URL", "URI", "API" - - If you encounter the following expression, "env vars", replace it with "environment variables" - - If you encounter errors for the following words: appId, env, just wrap the words in backticks (\`appId\`) - `, - }, - { - role: "user", - content: `${JSON.stringify(lintingIssues.map((lintingIssue) => ({ ErrorMessage: lintingIssue.Message, Value: lintingIssue.IncorrectValue, Line: lintingIssue.Line })))}`, - }, - ], - stream: true, - }); - let chunkIndex = 0; - const spinner = ora("Receiving GPT message").start(); - for await (const chunk of completionChunks) { - chunkIndex++; - spinner.text = `Received chunk ${chunkIndex}`; - const stringChunk = chunk.choices[0]?.delta?.content || ""; - output += stringChunk; - } - spinner.succeed("Received GPT message"); - - const parsedResult = JSON.parse(output) as { ErrorMessage: string; Value: string; Line: number }[]; - return lintingIssues.map((lintingIssue, index) => { - if (parsedResult[index].Line !== lintingIssue.Line) { - throw new Error( - `Line mismatch for ${lintingIssue.Line}. Expected ${parsedResult[index].Line} but got ${lintingIssue.Line}`, - ); - } - const correctedLine = parsedResult[index].Value; - lintingIssue.CorrectValue = correctedLine; - }); -}; - -async function createRedirectMap(oldUrls: string, newUrls: string) { - let output = ""; - - const completionChunks = await openai.chat.completions.create({ - model: "gpt-4o", - temperature: 0.1, - messages: [ - { - role: "user", - content: ` -You will receive two list of urls. The first one represents old links from a previous version of a website. The second one represents the new urls. -Processe the two lists and then create a mapping list that will be used to redirect the old urls to the new ones. -The format of the new list should be: -Array<{ from: string, to: string }> -The result final result should include mappings for ALL the links mentioned in the old list. -Make sure that all the links from the old list have a mapping. -`, - }, - { - role: "user", - content: ` -The old links: -${oldUrls} - `, - }, - { - role: "user", - content: ` -The new links: -${newUrls} - `, - }, - ], - stream: true, - }); - console.log(`Parsing gpt completion`); - let chunkIndex = 0; - for await (const chunk of completionChunks) { - chunkIndex++; - const stringChunk = chunk.choices[0]?.delta?.content || ""; - printStatus(`Received chunk ${chunkIndex}`); - output += stringChunk; - } - console.log(output); - - return output; -} - -const printStatus = (status: string) => { - process.stdout.write("\x1b[1A\x1b[2K"); // clear previous line - console.log(status); -}; - -(async () => { - const startPath = "./docs/references"; - const valeReport = await runVale(startPath); - - for (const file in valeReport) { - console.log(`Processing ${file}`); - const lintingIssues = valeReport[file].slice(0, 50); - await readLinesWithLintingIssues(file, lintingIssues); - await correctLinting(lintingIssues); - await writeLintingCorrectionsToFile(file, lintingIssues); - } -})(); - -async function listFiles(startPath: string) { - const files: string[] = []; - const glob = new Glob("**/*.mdx"); - - for await (const file of glob.scan(startPath)) { - files.push(file); - } - return files; -} - -async function readLinesWithLintingIssues(filePath: string, lintingIssues: ValeLintingIssue[]) { - const fileContent = await file(filePath).text(); - const fileLines = fileContent.split("\n"); - for (const lintingIssue of lintingIssues) { - const lineContent = fileLines[lintingIssue.Line - 1]; - if (!lineContent) { - throw new Error(`Line ${lintingIssue.Line} not found in file ${filePath}`); - } - lintingIssue.IncorrectValue = lineContent; - } -} - -async function writeLintingCorrectionsToFile(filePath: string, lintingIssues: ValeLintingIssue[]) { - const fileContent = await file(filePath).text(); - const fileLines = fileContent.split("\n"); - for (const lintingIssue of lintingIssues) { - const lineContent = fileLines[lintingIssue.Line - 1]; - if (!lineContent) { - throw new Error(`Line ${lintingIssue.Line} not found in file ${filePath}`); - } - fileLines[lintingIssue.Line - 1] = lintingIssue.CorrectValue; - } - await write(filePath, fileLines.join("\n")); -} - -async function runVale(itemPath: string): Promise { - const { stdout } = await $`vale ${itemPath} --output=JSON --no-exit`.nothrow(); - // const { stdout } = await $`vale ${itemPath} --minAlertLevel=error --output=JSON --no-exit`.nothrow(); - const parsedReport = JSON.parse(stdout.toString()); - return parsedReport as ValeReport; -} - -interface ValeLintingIssue { - Span: [number, number]; - Check: string; - Description: string; - Severity: "error" | "warning" | "suggestion"; - Line: number; - Message: string; - Match: string; - // Custom props used for persisting differnt values - IncorrectValue: string; - CorrectValue: string; -} - -interface ValeReport { - [key: string]: Array; -} diff --git a/scripts/blume/convert-categories.mjs b/scripts/blume/convert-categories.mjs new file mode 100644 index 0000000000..4160aa94e9 --- /dev/null +++ b/scripts/blume/convert-categories.mjs @@ -0,0 +1,100 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; + +const root = path.resolve(import.meta.dirname, "../.."); +const docsRoot = path.join(root, "docs"); + +const icons = { + References: "book-open", + Quickstart: "zap", + Authentication: "key-round", + "Additional Verification": "shield-check", + "Post Authentication": "users", + Migration: "arrow-right", + "Platform Configuration": "settings", + Deployment: "server", + "Email Password": "rectangle-ellipsis", + Passwordless: "wand-sparkles", + "Social Login": "circle-user-round", + "Enterprise Login": "building-2", + "Unified Login": "share-2", + "Machine to Machine": "bot", + Passkeys: "fingerprint", + Integrations: "puzzle", + "Frontend SDKs": "monitor", + "Backend SDKs": "server", + "User Interface": "palette", + "Frontend Driver Interface": "file-code-2", + "Core Driver Interface": "file-terminal", + "Testing and Debugging": "bug", + "SuperTokens Core": "cpu", + Plugins: "plug", + "Email/Password": "rectangle-ellipsis", + ThirdParty: "share-2", + WebAuthn: "fingerprint", + "Passkeys/WebAuthn": "fingerprint", + OAuth: "key-round", + MFA: "shield-check", + Session: "clock-3", + TOTP: "hash", + OTP: "smartphone", + SAML: "key-round", + "Email Verification": "mail-check", + "Account Linking": "file-user", + "Bulk Import": "user-plus", + Core: "cpu", + Dashboard: "layout-dashboard", + "User Metadata": "braces", + "User Roles": "shield-user", + Multitenancy: "house-plus", + "Quickstart Guides": "zap", + "Advanced Workflows": "workflow", + "Legacy Method": "history", + "Legacy method": "history", + "Using prebuilt UI": "palette", + "Step 1: Account Creation": "user-check", + "5. Checking Sessions in API Routes": "shield-check", + "Checking Sessions in API Routes": "shield-check", + "Session Verification": "badge-check", + "Attack Protection Suite": "shield-plus", + "Multi Factor Authentication": "monitor-smartphone", + "User Management": "user-search", + "Session Management": "id-card", + "React SDK Reference": "/img/logos/react.svg", + "Javascript SDK Reference": "/img/logos/js.svg", + "Node.js SDK Reference": "/img/logos/nodejs-small.svg", +}; + +const walk = async (directory) => { + const entries = await fs.readdir(directory, { withFileTypes: true }); + const files = []; + + for (const entry of entries) { + const entryPath = path.join(directory, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(entryPath))); + } else if (entry.name === "_category_.json") { + files.push(entryPath); + } + } + + return files; +}; + +const files = await walk(docsRoot); + +for (const file of files) { + const category = JSON.parse(await fs.readFile(file, "utf8")); + const meta = { + title: category.label, + ...(icons[category.label] ? { icon: icons[category.label] } : {}), + ...(typeof category.position === "number" ? { order: category.position } : {}), + ...(typeof category.collapsed === "boolean" ? { collapsed: category.collapsed } : {}), + }; + const source = `import { defineMeta } from "blume";\n\nexport default defineMeta(${JSON.stringify(meta, null, 2)});\n`; + + await fs.writeFile(path.join(path.dirname(file), "meta.ts"), source); + await fs.unlink(file); +} + +console.log(`Converted ${files.length} Docusaurus category files to meta.ts`); diff --git a/scripts/blume/convert-content.mjs b/scripts/blume/convert-content.mjs new file mode 100644 index 0000000000..fb9df5a065 --- /dev/null +++ b/scripts/blume/convert-content.mjs @@ -0,0 +1,483 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; + +import yaml from "js-yaml"; + +const root = path.resolve(import.meta.dirname, "../.."); +const docsRoot = path.join(root, "docs"); +const manifest = JSON.parse(await fs.readFile(path.join(root, "scripts/blume/route-manifest.json"), "utf8")); + +const placeholders = { + "appInfo.appName": "", + "appInfo.apiDomain": "", + "appInfo.apiBasePath": "/auth", + "appInfo.websiteDomain": "", + "appInfo.websiteBasePath": "/auth", + "appInfo.websiteBasePath_withoutForwardSlash": "auth", + "coreInfo.uri": "", + "coreInfo.key": "", + "derived.appIdPathname": "", + "derived.goPasswordlessContactMethodMethod": "ContactMethodEmailConfig", + "derived.pythonContactMethodImport": "from supertokens_python.recipe.passwordless import ContactEmailOnlyConfig", + "derived.pythonContactMethodMethod": "ContactEmailOnlyConfig", + docker_version_postgresql: "", + form_websiteBasePath: "", + jsdeliver_prebuiltui: "https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js", + prebuiltUIVersion: "https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js", + recipeNameCapitalLetters: "", + "recipes.passwordless.contactMethod": "EMAIL", + "recipes.passwordless.flowType": "MAGIC_LINK", + rid: "", + "webJsVersions.emailpassword": + "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/emailpassword.test.js", + "webJsVersions.emailverification": + "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/emailverification.test.js", + "webJsVersions.passwordless": + "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/passwordless.test.js", + "webJsVersions.session": "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/session.test.js", + "webJsVersions.supertokens": + "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/supertokens.test.js", + "webJsVersions.thirdparty": + "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/thirdparty.test.js", + "webJsVersions.webauthn": "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/webauthn.test.js", + "webJsVersions.website": "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/website.test.js", +}; + +const tabLabels = { + node: "Node.js", + nodejs: "Node.js", + go: "Go", + "go-http": "Go", + golang: "Go", + python: "Python", + java: "Java", + kotlin: "Kotlin", + swift: "Swift", + dart: "Dart", + csharp: "C#", + php: "PHP", + react: "React", + angular: "Angular", + vue: "Vue", + next: "Next.js", + nextjs: "Next.js", + express: "Express", + fastify: "Fastify", + hapi: "Hapi", + koa: "Koa", + loopback: "LoopBack", + flask: "Flask", + django: "Django", + fastapi: "FastAPI", + npm: "npm", + yarn: "Yarn", + pnpm: "pnpm", + script: "Script tag", + scripts: "Script tag", + prebuilt: "Prebuilt UI", + custom: "Custom UI", + "prebuilt-ui": "Prebuilt UI", + "custom-ui": "Custom UI", + "app-router": "App Router", + "pages-router": "Pages Router", + single: "Single tenant", + multi: "Multi-tenant", + ms: "Managed service", + ss: "Self-hosted", + curl: "cURL", + dashboard: "Dashboard", +}; + +const tabFamilies = [ + "BackendTabs", + "FrontendPrebuiltUITabs", + "FrontendCustomUITabs", + "FrontendTabs", + "SelfHostingTabs", + "RowndFrontendTabs", + "ReactRouterVersionTabs", + "ReactRouterVersionsTabs", + "OSTabs", + "DatabaseTabs", + "NodeFrameworksCard", + "NpmOrScriptsCard", + "PythonSyncAsyncCard", + "MobileFrameworksCard", + "PythonFrameworksCard", + "GoFrameworksCard", + "NodePackageManagerCard", + "JavascriptHttpLibraryCard", + "PythonPackageManagerCard", + "AccountTypeCard", + "PasswordlessConfigCard", + "ThirdPartyBuiltinProvidersCard", + "HTTPRequestCard", +]; + +const newBadges = new Set([ + "/quickstart/build-with-ai-tools", + "/additional-verification/captcha", + "/post-authentication/user-management/user-banning", + "/authentication/enterprise/tenant-discovery", + "/authentication/enterprise/tenant-management-plugin", + "/deployment/telemetry", + "/authentication/enterprise/saml", + "/post-authentication/user-management/progressive-profiling", +]); + +const betaBadges = new Set(["/authentication/ai-authentication"]); + +const escapeAttribute = (value) => String(value).replaceAll("&", "&").replaceAll('"', """); +const humanize = (value) => + String(value) + .replace(/([a-z])([A-Z])/g, "$1 $2") + .replace(/[-_]/g, " ") + .replace(/\b\w/g, (character) => character.toUpperCase()); +const tabLabel = (value) => tabLabels[value] || humanize(value); + +const walk = async (directory) => { + const entries = await fs.readdir(directory, { withFileTypes: true }); + const files = []; + for (const entry of entries) { + const entryPath = path.join(directory, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(entryPath))); + } else if (/\.mdx?$/.test(entry.name) && !entry.name.startsWith("_")) { + files.push(entryPath); + } + } + return files; +}; + +const splitFrontmatter = (source) => { + if (!source.startsWith("---\n")) { + return { data: {}, body: source }; + } + const end = source.indexOf("\n---", 4); + if (end === -1) { + throw new Error("Unclosed frontmatter"); + } + return { + data: yaml.load(source.slice(4, end)) || {}, + body: source.slice(end + 4).replace(/^\n/, ""), + }; +}; + +const stripFrontmatter = (source) => splitFrontmatter(source).body; + +const expandPartials = async (source, sourceFile, stack = []) => { + const imports = []; + const lines = source.split("\n"); + let inFence = false; + + for (let index = 0; index < lines.length; index += 1) { + const line = lines[index]; + if (/^\s*```/.test(line)) { + inFence = !inFence; + continue; + } + if (inFence) continue; + + const match = line.match(/^import\s+([A-Za-z][A-Za-z0-9_]*)\s+from\s+["']([^"']+\.mdx)["'];?\s*$/); + if (match) { + imports.push({ line: index, name: match[1], specifier: match[2] }); + } + } + + for (const imported of imports.reverse()) { + let partialPath; + if (imported.specifier.startsWith("/docs/")) { + partialPath = path.resolve(docsRoot, imported.specifier.slice("/docs/".length)); + } else if (path.isAbsolute(imported.specifier)) { + throw new Error(`Unsupported absolute MDX import "${imported.specifier}" in ${sourceFile}; expected /docs/...`); + } else { + partialPath = path.resolve(path.dirname(sourceFile), imported.specifier); + } + if (stack.includes(partialPath)) { + throw new Error(`Circular MDX partial import: ${[...stack, partialPath].join(" -> ")}`); + } + let partial = stripFrontmatter(await fs.readFile(partialPath, "utf8")); + partial = await expandPartials(partial, partialPath, [...stack, partialPath]); + const usage = new RegExp(`<${imported.name}(?:\\s[^>]*)?\\s*/>`, "g"); + source = source.replace(usage, partial.trim()); + source = source.replace(new RegExp(`^import\\s+${imported.name}\\s+from\\s+["'][^"']+["'];?\\s*$`, "m"), ""); + } + + return source; +}; + +const transformCodeBlocks = (source) => { + const lines = source.split("\n"); + const output = []; + for (let index = 0; index < lines.length; index += 1) { + const opener = lines[index].match(/^(\s*)```([^`]*)$/); + if (!opener) { + output.push(lines[index]); + continue; + } + + const indent = opener[1]; + let info = opener[2] + .replace(/\s+showAppTypeSelect\b/g, "") + .replace(/\s+preview=(?:"[^"]*"|'[^']*')/g, "") + .replace(/\s+previewAlt=(?:"[^"]*"|'[^']*')/g, "") + .replace(/\bshowLineNumbers\b/g, "lineNumbers") + .trimEnd(); + const code = []; + const highlights = new Set(); + let inHighlight = false; + let highlightNext = false; + + index += 1; + while ( + index < lines.length && + !new RegExp(`^${indent.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\`\`\`\\s*$`).test(lines[index]) + ) { + const line = lines[index]; + if (line.includes("highlight-start")) { + inHighlight = true; + } else if (line.includes("highlight-end")) { + inHighlight = false; + } else if (line.includes("highlight-next-line")) { + highlightNext = true; + } else if ( + !line.includes("REMOVE_FROM_OUTPUT") && + !line.includes("@ts-expect-error") && + !line.includes("@ts-nocheck") && + !line.includes("@ts-ignore") && + !line.includes("// typecheck-only") && + !line.includes("supertokens-web-js-script") && + !line.includes("supertokens-auth-react-script") + ) { + code.push(line.replaceAll("# type: ignore", "")); + if (inHighlight || highlightNext) highlights.add(code.length); + highlightNext = false; + } + index += 1; + } + + if (highlights.size > 0 && !/\{[^}]+\}/.test(info)) { + info = `${info} {${[...highlights].join(",")}}`; + } + output.push(`${indent}\`\`\`${info}`, ...code, lines[index] || `${indent}\`\`\``); + } + return output.join("\n"); +}; + +const transformHeadingContainer = (source, component, item, headingPattern) => + source.replace(new RegExp(`<${component}(?:\\s[^>]*)?>([\\s\\S]*?)`, "g"), (full, content) => { + const heading = new RegExp(`^${headingPattern}\\s+(.+)$`, "gm"); + const matches = [...content.matchAll(heading)]; + if (matches.length === 0) return full.replace(new RegExp(`<${component}(?:\\s[^>]*)?>`), `<${component}>`); + + const sections = matches.map((match, index) => { + const start = match.index + match[0].length; + const end = matches[index + 1]?.index ?? content.length; + return `<${item} title="${escapeAttribute(match[1].replace(/[*_`\[\]]/g, ""))}">\n${content + .slice(start, end) + .trim()}\n`; + }); + return `<${component}>\n${sections.join("\n")}\n`; + }); + +const transformReferenceCards = (source) => { + source = source + .replace(/]*)?>/g, "") + .replace(/<\/ReferenceCard\.Grid>/g, "") + .replace(/\s*/g, "") + .replace(/]*?)\s*\/>/g, (full, attributes) => { + const href = attributes.match(/href=["']([^"']+)["']/)?.[1]; + const label = attributes.match(/label=["']([^"']+)["']/)?.[1]; + return href && label ? `` : full; + }); + + return source.replace(/]*?)>([\s\S]*?)<\/ReferenceCard>/g, (full, attributes, content) => { + const href = attributes.match(/href=["']([^"']+)["']/)?.[1]; + if (!href) return full; + const title = content.match(/([\s\S]*?)<\/ReferenceCard\.Title>/)?.[1]?.trim(); + const description = content + .match(/([\s\S]*?)<\/ReferenceCard\.Description>/)?.[1] + ?.trim(); + const avatar = content.match(/]*icon=["']([^"']+)["'][^>]*\/>/)?.[1]; + const icon = content.match(/]*icon=["']([^"']+)["'][^>]*\/>/)?.[1]; + const titleText = title?.replace(/<[^>]+>/g, "").replace(/\s+/g, " ") || humanize(path.basename(href)); + const iconValue = avatar + ? `/img/icons/${avatar}.svg` + : icon + ? icon.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase() + : null; + return `\n${ + description || "" + }\n`; + }); +}; + +const transformTabs = (source) => { + for (const family of tabFamilies) { + source = source + .replace(new RegExp(`<${family}(?:\\s[^>]*)?>`, "g"), ``) + .replace(new RegExp(``, "g"), "") + .replace(new RegExp(`<${family}\\.(?:TabItem|Tab|Content)\\s+([^>]*?)>`, "g"), (full, attributes) => { + const value = attributes.match(/value=["']([^"']+)["']/)?.[1]; + const label = attributes.match(/label=["']([^"']+)["']/)?.[1]; + return ``; + }) + .replace(new RegExp(``, "g"), ""); + } + + source = source + .replace(/]*)?>/g, "") + .replace(/]*?)>/g, (full, attributes) => { + const value = attributes.match(/value=["']([^"']+)["']/)?.[1]; + const label = attributes.match(/label=["']([^"']+)["']/)?.[1]; + return ``; + }) + .replace(/<\/TabItem>/g, ""); + return source; +}; + +const transformVariants = (source) => + source + .replace(//g, "") + .replace(//g, '') + .replace(/<\/UIType\.PrebuiltUIContent>/g, "") + .replace(//g, '') + .replace(/<\/UIType\.CustomUIContent>/g, "") + .replace(//g, "") + .replace(//g, '') + .replace(/<\/TenantType\.SingleTenantContent>/g, "") + .replace(//g, '') + .replace(/<\/TenantType\.MultiTenantContent>/g, "") + .replace(/]*)?>/g, "") + .replace(/<\/Question>/g, "") + .replace(/]*title=["']([^"']+)["'][^>]*>/g, '') + .replace(/<\/Answer>/g, ""); + +const removeBodyH1s = (source) => { + const lines = source.split("\n"); + let inFence = false; + return lines + .filter((line) => { + if (/^\s*```/.test(line)) inFence = !inFence; + return inFence || !/^#\s+/.test(line); + }) + .join("\n"); +}; + +const routeForFile = (file) => { + const relative = path + .relative(docsRoot, file) + .replace(/\.mdx?$/, "") + .split(path.sep); + if (relative.at(-1) === "index") relative.pop(); + return `/${relative.join("/")}`.replace(/\/$/, "") || "/"; +}; + +const mapFrontmatter = (data, body, route, file) => { + const bodyTitle = body.match(/^#\s+(.+)$/m)?.[1]?.replace(/[*_`]/g, ""); + const filenameTitle = humanize( + path.basename(file, path.extname(file)) === "index" + ? path.basename(path.dirname(file)) + : path.basename(file, path.extname(file)), + ); + const title = data.title || data.page_title || bodyTitle || filenameTitle; + const mapped = { + title, + ...(data.description ? { description: data.description } : {}), + ...(data.draft === true ? { draft: true } : {}), + ...(data.last_update?.date ? { lastModified: data.last_update.date } : {}), + }; + + const sidebar = {}; + if (data.sidebar_label) sidebar.label = data.sidebar_label; + if (typeof data.sidebar_position === "number") sidebar.order = data.sidebar_position; + if (data.unlisted === true || route === "/legacy/core/v10/self-host-supertokens") sidebar.hidden = true; + if (newBadges.has(route)) sidebar.badge = "New"; + if (betaBadges.has(route)) sidebar.badge = "Beta"; + if (Object.keys(sidebar).length > 0) mapped.sidebar = sidebar; + + const seo = {}; + if (data.image) seo.image = data.image; + if (data.unlisted === true) seo.noindex = true; + if (Object.keys(seo).length > 0) mapped.seo = seo; + if (Array.isArray(data.tags) && data.tags.length > 0) mapped.search = { tags: data.tags }; + return mapped; +}; + +const rewriteLinks = (source) => { + for (const redirect of manifest.openapi) { + source = source.replaceAll(`/docs${redirect.from}`, redirect.to); + source = source.replaceAll(redirect.from, redirect.to); + } + return source + .replace( + /\/docs\/authentication\/social\/built-in-providers(?=[#?/"')\s]|$)/g, + "/authentication/social/built-in-providers-config", + ) + .replaceAll( + "/docs/additional-verification/mfa/webauthn-secondary-factor-setup", + "/additional-verification/mfa/webauthn-setup", + ) + .replace(/(["'(])\/docs(?=\/|["')#])/g, "$1") + .replace(/(\bsrc\s*=\s*["'])\/img\//g, "$1/docs/img/") + .replace(/(!\[[^\]]*\]\()\/img\//g, "$1/docs/img/") + .replace(/\.mdx(?=([#?][^\s"')>]*)?["')>\s])/g, "") + .replace(/\.md(?=([#?][^\s"')>]*)?["')>\s])/g, ""); +}; + +const files = await walk(docsRoot); +let inlinedPartials = 0; + +for (const file of files) { + let source = await fs.readFile(file, "utf8"); + const importsBefore = (source.match(/^import\s+\w+\s+from\s+["'][.][^"']+\.mdx["'];?\s*$/gm) || []).length; + source = await expandPartials(source, file); + inlinedPartials += importsBefore; + + const { data, body: originalBody } = splitFrontmatter(source); + const route = routeForFile(file); + let body = originalBody; + + body = body + .replace(/^import\s+.*(?:@theme|@site\/src\/components|\/src\/components|@radix-ui\/themes).*$/gm, "") + .replace( + /\^\{([^}]+)\}/g, + (full, key) => placeholders[key] ?? `<${humanize(key).toUpperCase().replaceAll(" ", "_")}>`, + ) + .replace(/\{\{optional\}\}|\{optional\}/g, "(optional)") + .replace(/:::important\b/g, ":::note") + .replace(/:::caution\b/g, ":::warning") + .replace(/^(\s*):::(note|tip|info|warning|danger|success)\s+([^\n\[]+)$/gm, (full, indent, type, title) => + title.trim() === "no-title" ? `${indent}:::${type}` : `${indent}:::${type}[${title.trim()}]`, + ) + .replace(/]*)?\s*\/?>/g, "") + .replace(/<\/AppInfoForm>/g, "") + .replace( + /]*)?\s*\/>/g, + ":::info[Managed service feature]\nThis feature is available for managed SuperTokens deployments.\n:::", + ) + .replace(//g, '') + .replace(/<\/RemoveForLLMs>/g, "") + .replace(//g, "") + .replace(/<\/DescriptionText>/g, "") + .replace(/\s*/g, "\n\n---\n") + .replace(//g, "
"); + + body = transformCodeBlocks(body); + body = transformReferenceCards(body); + body = transformTabs(body); + body = transformVariants(body); + body = transformHeadingContainer(body, "Steps", "Step", "#{2,6}"); + body = transformHeadingContainer(body, "Accordion", "AccordionItem", "##"); + body = rewriteLinks(body); + body = removeBodyH1s(body) + .replace(/\n{4,}/g, "\n\n\n") + .trim(); + + const legacyData = readLegacyFrontmatter(file); + const mapped = mapFrontmatter({ ...legacyData, ...data }, originalBody, route, file); + const frontmatter = yaml.dump(mapped, { lineWidth: 120, noRefs: true, sortKeys: false }).trim(); + await fs.writeFile(file, `---\n${frontmatter}\n---\n\n${body}\n`); +} + +console.log(`Converted ${files.length} pages and inlined ${inlinedPartials} partial imports`); diff --git a/scripts/blume/create-route-manifest.mjs b/scripts/blume/create-route-manifest.mjs new file mode 100644 index 0000000000..fe03bde1fd --- /dev/null +++ b/scripts/blume/create-route-manifest.mjs @@ -0,0 +1,140 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; + +import yaml from "js-yaml"; + +const root = path.resolve(import.meta.dirname, "../.."); +const contentRoot = path.join(root, "docs"); +const outputPath = path.join(root, "scripts/blume/route-manifest.json"); +const redirectsPath = path.join(root, "scripts/blume/openapi-redirects.ts"); + +const slugify = (value) => + value + .normalize("NFKD") + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-|-$/g, ""); + +const routeFromFile = (file, id) => { + const parsed = path.parse(path.relative(contentRoot, file)); + const segments = parsed.dir ? parsed.dir.split(path.sep) : []; + const finalSegment = id || parsed.name; + + if (finalSegment !== "index") { + segments.push(finalSegment); + } + + return `/${segments.join("/")}`.replace(/\/$/, "") || "/"; +}; + +const readFrontmatter = (source) => { + if (!source.startsWith("---\n")) { + return {}; + } + + const end = source.indexOf("\n---", 4); + if (end === -1) { + return {}; + } + + return yaml.load(source.slice(4, end)) || {}; +}; + +const walk = async (directory) => { + const entries = await fs.readdir(directory, { withFileTypes: true }); + const files = []; + + for (const entry of entries) { + if (entry.name.startsWith("_")) { + continue; + } + + const entryPath = path.join(directory, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(entryPath))); + } else if (/\.mdx?$/.test(entry.name)) { + files.push(entryPath); + } + } + + return files; +}; + +const buildOpenApiRedirects = async (apiName) => { + const spec = yaml.load(await fs.readFile(path.join(root, `openapi/${apiName}.yml`), "utf8")); + const mapping = JSON.parse(await fs.readFile(path.join(root, `public/${apiName}-mapping.json`), "utf8")); + const operations = []; + + for (const pathItem of Object.values(spec.paths || {})) { + for (const operation of Object.values(pathItem || {})) { + if (!(operation && typeof operation === "object" && operation.operationId)) { + continue; + } + + const legacy = mapping[operation.operationId]; + if (!legacy?.filePath) { + throw new Error(`Missing ${apiName.toUpperCase()} file mapping for ${operation.operationId}`); + } + + const tag = operation.tags?.[0] || "default"; + operations.push({ + operationId: operation.operationId, + from: `/references/${legacy.filePath.replace(/^\/+/, "").replace(/\.mdx?$/, "")}`, + to: `/references/${apiName}/${slugify(tag)}/${slugify(operation.operationId)}`, + }); + } + } + + return operations.sort((a, b) => a.from.localeCompare(b.from)); +}; + +const files = await walk(contentRoot); +const pages = []; + +for (const file of files) { + const source = await fs.readFile(file, "utf8"); + const frontmatter = readFrontmatter(source); + const route = routeFromFile(file, frontmatter.id); + + pages.push({ + file: path.relative(root, file), + route, + publicRoute: route === "/" ? "/docs" : `/docs${route}`, + }); +} + +const openapi = [...(await buildOpenApiRedirects("cdi")), ...(await buildOpenApiRedirects("fdi"))]; + +for (const operation of openapi) { + if (!pages.some((page) => page.route === operation.from)) { + pages.push({ + file: `docs${operation.from}.mdx`, + route: operation.from, + publicRoute: `/docs${operation.from}`, + }); + } +} + +pages.sort((a, b) => a.route.localeCompare(b.route)); + +const manifest = { + counts: { + pages: pages.length, + openapiOperations: openapi.length, + }, + pages, + openapi, +}; + +await fs.writeFile(outputPath, `${JSON.stringify(manifest, null, 2)}\n`); +await fs.writeFile( + redirectsPath, + `// Generated by scripts/blume/create-route-manifest.mjs.\nexport const openApiRedirects = ${JSON.stringify( + openapi.map(({ from, to }) => ({ from, to })), + null, + 2, + )} as const;\n`, +); +console.log( + `Wrote ${pages.length} pages and ${openapi.length} OpenAPI operations to ${path.relative(root, outputPath)}`, +); diff --git a/scripts/blume/fix-legacy-components.mjs b/scripts/blume/fix-legacy-components.mjs new file mode 100644 index 0000000000..9c204cd4a4 --- /dev/null +++ b/scripts/blume/fix-legacy-components.mjs @@ -0,0 +1,210 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; + +const root = path.resolve(import.meta.dirname, "../.."); +const docsRoot = path.join(root, "docs"); + +const families = [ + "AccountTypeCard", + "GoFrameworksCard", + "JavascriptHttpLibraryCard", + "MobileFrameworksCard", + "NodeFrameworksCard", + "NpmOrScriptsCard", + "PasswordlessConfigCard", + "PythonFrameworksCard", +]; + +const labels = { + node: "Node.js", + nodejs: "Node.js", + go: "Go", + python: "Python", + react: "React", + angular: "Angular", + vue: "Vue", + express: "Express", + fastify: "Fastify", + hapi: "Hapi", + koa: "Koa", + loopback: "LoopBack", + flask: "Flask", + django: "Django", + fastapi: "FastAPI", + npm: "npm", + script: "Script tag", + scripts: "Script tag", + axios: "Axios", + fetch: "Fetch", + single: "Single tenant", + multi: "Multi-tenant", + "with-docker": "Self-hosted with Docker", + "without-docker": "Self-hosted without Docker", +}; + +const labelFor = (value) => + labels[value] || + String(value || "Option") + .replace(/([a-z])([A-Z])/g, "$1 $2") + .replace(/[-_]/g, " ") + .replace(/\b\w/g, (character) => character.toUpperCase()); + +const replaceOpening = (source, name, replacement) => { + let cursor = 0; + let output = ""; + const needle = `<${name}`; + while (cursor < source.length) { + const start = source.indexOf(needle, cursor); + if (start === -1) { + output += source.slice(cursor); + break; + } + const next = source[start + needle.length]; + if (!(next === ">" || /\s/.test(next || ""))) { + output += source.slice(cursor, start + needle.length); + cursor = start + needle.length; + continue; + } + let quote = null; + let escaped = false; + let braces = 0; + let end = start + needle.length; + for (; end < source.length; end += 1) { + const character = source[end]; + if (escaped) escaped = false; + else if (quote && character === "\\") escaped = true; + else if (quote && character === quote) quote = null; + else if (!quote && (character === '"' || character === "'")) quote = character; + else if (!quote && character === "{") braces += 1; + else if (!quote && character === "}") braces = Math.max(0, braces - 1); + else if (!quote && braces === 0 && character === ">") { + end += 1; + break; + } + } + const opening = source.slice(start, end); + output += source.slice(cursor, start) + replacement(opening); + cursor = end; + } + return output; +}; + +const walk = async (directory) => { + const files = []; + for (const entry of await fs.readdir(directory, { withFileTypes: true })) { + if (entry.name.startsWith("_")) continue; + const entryPath = path.join(directory, entry.name); + if (entry.isDirectory()) files.push(...(await walk(entryPath))); + else if (/\.mdx?$/.test(entry.name)) files.push(entryPath); + } + return files; +}; + +const transformOutsideFences = (source, transform) => { + const lines = source.split("\n"); + let inFence = false; + return lines + .map((line) => { + if (/^\s*```/.test(line)) { + inFence = !inFence; + return line; + } + return inFence ? line : transform(line); + }) + .join("\n"); +}; + +const transformOutsideInlineCode = (line, transform) => { + let cursor = 0; + let output = ""; + while (cursor < line.length) { + const start = line.indexOf("`", cursor); + if (start === -1) return output + transform(line.slice(cursor)); + let length = 1; + while (line[start + length] === "`") length += 1; + const delimiter = "`".repeat(length); + const end = line.indexOf(delimiter, start + length); + if (end === -1) return output + transform(line.slice(cursor)); + output += transform(line.slice(cursor, start)) + line.slice(start, end + length); + cursor = end + length; + } + return output; +}; + +for (const file of await walk(docsRoot)) { + let source = await fs.readFile(file, "utf8"); + + for (const family of families) { + source = replaceOpening(source, family, () => ``) + .replace(new RegExp(``, "g"), "") + .replace(new RegExp(`<${family}\\.(?:Section|Content)(?:\\s+([^>]*?))?\\s*>`, "g"), (full, attributes) => { + const value = + attributes?.match(/value=["']([^"']+)["']/)?.[1] || attributes?.match(/name=["']([^"']+)["']/)?.[1]; + return ``; + }) + .replace(new RegExp(``, "g"), ""); + } + + source = source + .replace(/]*)?>/g, '') + .replace(/<\/AccountTypeCard\.ManagedContent>/g, "") + .replace(/]*?)>/g, (full, attributes) => { + const value = attributes.match(/value=["']([^"']+)["']/)?.[1]; + return ``; + }) + .replace(/<\/AccountTypeCard\.SelfHostedContent>/g, "") + .replace(//g, "") + .replace(/<\/NodeFrameworksCard\.HeaderCustomActions>/g, "") + .replace( + /]*?)?\s*>/g, + (full, kind) => { + const titles = { ShellExample: "cURL", NodeJSExample: "Node.js", GoExample: "Go", PythonExample: "Python" }; + return ``; + }, + ) + .replace(/<\/HTTPRequestCard\.(ShellExample|NodeJSExample|GoExample|PythonExample)>/g, "") + .replace(//g, '') + .replace(/<\/HTTPRequestCard\.DetailsModal>/g, "") + .replace(/<\/?HTTPRequestCard\.DetailsModal(?:Header|Description|Body)>/g, "") + .replace(//g, "") + .replace(/<\/CodeSampleCard>/g, "") + .replace(/]*)?>/g, "") + .replace(/<\/AppInfoForm>/g, "") + .replace(/]*)?>/g, '') + .replace(/<\/UIType\.CustomUIContent>/g, "") + .replace(/]*)?>/g, '') + .replace(/<\/UIType\.PrebuiltUIContent>/g, "") + .replace(/]*)?>/g, ":::info[Access token guidance]") + .replace(/<\/TokensCallout>/g, ":::") + .replace( + /]*)?\s*\/>/g, + ":::warning[OAuth2 token verification]\nVerify OAuth2 access tokens with your OAuth2/OIDC library instead of the SuperTokens Session SDK.\n:::", + ) + .replace( + /]*)?\s*\/>/g, + ":::warning[OAuth2 token verification]\nCheck authentication with your OAuth2/OIDC library when using Unified Login.\n:::", + ) + .replace(/]*)?>/g, "
") + .replace(/<\/Box>/g, "
") + .replace(/]*)?>/g, "
") + .replace(/<\/Flex>/g, "
") + .replace(/

(.*?)<\/H2>/g, "## $1") + .replace(/

(.*?)<\/H3>/g, "### $1") + .replace(/

(.*?)<\/H4>/g, "#### $1"); + + source = transformOutsideFences(source, (line) => { + const repaired = line + .replace(/``(<[A-Z][A-Z0-9_]+>)`/g, "`$1") + .replace(/`(<[A-Z][A-Z0-9_]+>)``/g, "$1`") + .replace(/'`(<[A-Z][A-Z0-9_]+>)`'/g, "`'$1'`"); + return transformOutsideInlineCode(repaired, (text) => + text + .replace(/<([A-Z][A-Z0-9_]{1,})>/g, "<$1>") + .replace(/<(T|P|Action|ValueType|PreloadInfoType|NormalisedConfig|RecipeContext)>/g, "<$1>"), + ); + }); + + await fs.writeFile(file, source); +} + +console.log("Converted remaining legacy MDX components"); diff --git a/scripts/blume/fix-stale-links.mjs b/scripts/blume/fix-stale-links.mjs new file mode 100644 index 0000000000..a2faab1160 --- /dev/null +++ b/scripts/blume/fix-stale-links.mjs @@ -0,0 +1,116 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; + +const docsRoot = path.resolve(import.meta.dirname, "../../docs"); + +const replacements = [ + { + from: "../frontend-setup#step-2-checking-the---custv-boolean-value-in-the-mfa-claim--cust", + to: "/additional-verification/mfa/initial-setup#12-add-the-mfa-flow", + expected: 2, + }, + { + from: "../frontend-setup#mfa-info-endpoint", + to: "/additional-verification/mfa/initial-setup#the-mfa-info-endpoint", + expected: 7, + }, + { + from: "./frontend-setup#mfa-info-endpoint", + to: "/additional-verification/mfa/initial-setup#the-mfa-info-endpoint", + expected: 1, + }, + { + from: "/passwordless/custom-ui/login-otp#step-3-verifying-the-input-otp", + to: "/authentication/passwordless/initial-setup#23-verifying-the-otp", + expected: 2, + }, + { + from: "/passwordless/custom-ui/login-otp", + to: "/authentication/passwordless/initial-setup#21-creating-and-sending-the-otp", + expected: 2, + }, + { + from: "./backend-setup#multi-tenant-setup-1", + to: "/additional-verification/mfa/initial-setup#13-configure-the-second-factor", + expected: 2, + }, + { + from: "./backend-setup#multi-tenant-setup", + to: "/additional-verification/mfa/initial-setup#12-configure-the-first-factors", + expected: 1, + }, + { + from: "/multi-tenancy/new-tenant", + to: "/authentication/enterprise/manage-tenants#create-a-new-tenant", + expected: 1, + }, + { + from: "../../custom-ui/thirdparty-login", + to: "/authentication/social/initial-setup#2-add-the-login-ui", + expected: 3, + }, + { + from: "../sessions/protecting-frontend-routes#verifying-the-claims-of-a-session--cust", + to: "/additional-verification/session-verification/protect-frontend-routes#check-the-claims-of-a-session", + expected: 2, + }, + { + from: "../sessions/protecting-frontend-routes", + to: "/additional-verification/session-verification/protect-frontend-routes", + expected: 2, + }, + { + from: "/microservice_auth/legacy/implementation-guide", + to: "/authentication/m2m/legacy-flow", + expected: 1, + }, + { + from: "/authentication/unified-login/reuse-website-login", + to: "/authentication/unified-login/quickstart-guides/reuse-website-login", + expected: 9, + }, + { + from: "../../custom-ui/init/frontend", + to: "/quickstart/frontend-setup", + expected: 1, + }, + { + from: "../custom-ui/init/frontend", + to: "/quickstart/frontend-setup", + expected: 1, + }, +]; + +const walk = async (directory) => { + const files = []; + for (const entry of await fs.readdir(directory, { withFileTypes: true })) { + const entryPath = path.join(directory, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(entryPath))); + } else if (/\.mdx?$/.test(entry.name)) { + files.push(entryPath); + } + } + return files; +}; + +const files = await walk(docsRoot); +const sources = new Map(await Promise.all(files.map(async (file) => [file, await fs.readFile(file, "utf8")]))); +let rewritten = 0; + +for (const replacement of replacements) { + const count = [...sources.values()].reduce((total, source) => total + source.split(replacement.from).length - 1, 0); + if (count === 0) { + continue; + } + if (count !== replacement.expected) { + throw new Error(`Expected ${replacement.expected} occurrence(s) of ${replacement.from}, found ${count}`); + } + rewritten += count; + for (const [file, source] of sources) { + sources.set(file, source.replaceAll(replacement.from, replacement.to)); + } +} + +await Promise.all([...sources].map(([file, source]) => fs.writeFile(file, source))); +console.log(`Rewrote ${rewritten} stale links.`); diff --git a/scripts/blume/openapi-redirects.ts b/scripts/blume/openapi-redirects.ts new file mode 100644 index 0000000000..8f4bf8af7c --- /dev/null +++ b/scripts/blume/openapi-redirects.ts @@ -0,0 +1,823 @@ +// Generated by scripts/blume/create-route-manifest.mjs. +export const openApiRedirects = [ + { + "from": "/references/cdi/account-linking/get-accountlinking-user-link-check", + "to": "/references/cdi/account-linking-recipe/canlinkaccounts" + }, + { + "from": "/references/cdi/account-linking/get-accountlinking-user-primary-check", + "to": "/references/cdi/account-linking-recipe/cancreateprimaryuser" + }, + { + "from": "/references/cdi/account-linking/post-accountlinking-user-link", + "to": "/references/cdi/account-linking-recipe/linkaccounts" + }, + { + "from": "/references/cdi/account-linking/post-accountlinking-user-primary", + "to": "/references/cdi/account-linking-recipe/createprimaryuser" + }, + { + "from": "/references/cdi/account-linking/post-accountlinking-user-unlink", + "to": "/references/cdi/account-linking-recipe/unlinkaccounts" + }, + { + "from": "/references/cdi/core/delete-ee-license", + "to": "/references/cdi/core/deletelicense" + }, + { + "from": "/references/cdi/core/delete-hello", + "to": "/references/cdi/core/deletehello" + }, + { + "from": "/references/cdi/core/get-apiversion", + "to": "/references/cdi/core/getapiversion" + }, + { + "from": "/references/cdi/core/get-config", + "to": "/references/cdi/core/getconfig" + }, + { + "from": "/references/cdi/core/get-ee-featureflag", + "to": "/references/cdi/core/getfeatureflag" + }, + { + "from": "/references/cdi/core/get-ee-license", + "to": "/references/cdi/core/getlicense" + }, + { + "from": "/references/cdi/core/get-hello", + "to": "/references/cdi/core/gethello" + }, + { + "from": "/references/cdi/core/get-requests-stats", + "to": "/references/cdi/core/getrequestsstats" + }, + { + "from": "/references/cdi/core/get-root", + "to": "/references/cdi/core/gethelloonrootpath" + }, + { + "from": "/references/cdi/core/get-telemetry", + "to": "/references/cdi/core/gettelemetry" + }, + { + "from": "/references/cdi/core/get-user-id", + "to": "/references/cdi/core/getuserid" + }, + { + "from": "/references/cdi/core/get-user-search-tags", + "to": "/references/cdi/core/getsearchtags" + }, + { + "from": "/references/cdi/core/get-userid-map", + "to": "/references/cdi/useridmapping-recipe/useridmappinggetmapping" + }, + { + "from": "/references/cdi/core/get-users", + "to": "/references/cdi/core/getusers" + }, + { + "from": "/references/cdi/core/get-users-by-accountinfo", + "to": "/references/cdi/core/getusersbyaccountinfo" + }, + { + "from": "/references/cdi/core/get-users-count", + "to": "/references/cdi/core/getuserscount" + }, + { + "from": "/references/cdi/core/get-users-count-active", + "to": "/references/cdi/core/getactiveuserscount" + }, + { + "from": "/references/cdi/core/post-hello", + "to": "/references/cdi/core/posthello" + }, + { + "from": "/references/cdi/core/post-user-remove", + "to": "/references/cdi/core/deleteuser" + }, + { + "from": "/references/cdi/core/post-userid-map", + "to": "/references/cdi/useridmapping-recipe/useridmappingcreatemapping" + }, + { + "from": "/references/cdi/core/post-userid-map-remove", + "to": "/references/cdi/useridmapping-recipe/useridmappingremovemapping" + }, + { + "from": "/references/cdi/core/put-ee-license", + "to": "/references/cdi/core/setlicense" + }, + { + "from": "/references/cdi/core/put-hello", + "to": "/references/cdi/core/puthello" + }, + { + "from": "/references/cdi/core/put-userid-external-user-id-info", + "to": "/references/cdi/useridmapping-recipe/useridmappingupateexternaluseridinfo" + }, + { + "from": "/references/cdi/dashboard/delete-dashboard-session", + "to": "/references/cdi/dashboard-recipe/revokedashboarduserssession" + }, + { + "from": "/references/cdi/dashboard/delete-dashboard-user", + "to": "/references/cdi/dashboard-recipe/deletedashboarduser" + }, + { + "from": "/references/cdi/dashboard/get-dashboard-tenant-core-config", + "to": "/references/cdi/dashboard-recipe/tenantcoreconfigfordashboardget" + }, + { + "from": "/references/cdi/dashboard/get-dashboard-user-sessions", + "to": "/references/cdi/dashboard-recipe/getallsessionsfordashboarduser" + }, + { + "from": "/references/cdi/dashboard/get-dashboard-users", + "to": "/references/cdi/dashboard-recipe/getalldashboardusers" + }, + { + "from": "/references/cdi/dashboard/post-dashboard-session-verify", + "to": "/references/cdi/dashboard-recipe/verifydashboardusersession" + }, + { + "from": "/references/cdi/dashboard/post-dashboard-signin", + "to": "/references/cdi/dashboard-recipe/signindashboarduser" + }, + { + "from": "/references/cdi/dashboard/post-dashboard-user", + "to": "/references/cdi/dashboard-recipe/createdashboarduser" + }, + { + "from": "/references/cdi/dashboard/put-dashboard-user", + "to": "/references/cdi/dashboard-recipe/updatedashboarduser" + }, + { + "from": "/references/cdi/email-password/get-user", + "to": "/references/cdi/emailpassword-recipe/emailpasswordgetuser" + }, + { + "from": "/references/cdi/email-password/post-signin", + "to": "/references/cdi/emailpassword-recipe/emailpasswordsignin" + }, + { + "from": "/references/cdi/email-password/post-signup", + "to": "/references/cdi/emailpassword-recipe/emailpasswordsignup" + }, + { + "from": "/references/cdi/email-password/post-user-password-reset", + "to": "/references/cdi/emailpassword-recipe/emailpasswordgetpasswordreset" + }, + { + "from": "/references/cdi/email-password/post-user-password-reset-token", + "to": "/references/cdi/emailpassword-recipe/emailpasswordgetpasswordresettoken" + }, + { + "from": "/references/cdi/email-password/post-user-password-reset-token-consume", + "to": "/references/cdi/emailpassword-recipe/emailpasswordresetpasswordconsumetoken" + }, + { + "from": "/references/cdi/email-password/post-user-passwordhash-import", + "to": "/references/cdi/emailpassword-recipe/userimport" + }, + { + "from": "/references/cdi/email-password/put-user", + "to": "/references/cdi/emailpassword-recipe/emailpasswordputuser" + }, + { + "from": "/references/cdi/email-verification/get-user-email-verify", + "to": "/references/cdi/emailverification-recipe/emailverificationverifyget" + }, + { + "from": "/references/cdi/email-verification/post-user-email-verify", + "to": "/references/cdi/emailverification-recipe/emailverificationverify" + }, + { + "from": "/references/cdi/email-verification/post-user-email-verify-remove", + "to": "/references/cdi/emailverification-recipe/emailverificationverifyremove" + }, + { + "from": "/references/cdi/email-verification/post-user-email-verify-token", + "to": "/references/cdi/emailverification-recipe/emailverificationverifytoken" + }, + { + "from": "/references/cdi/email-verification/post-user-email-verify-token-remove", + "to": "/references/cdi/emailverification-recipe/emailverificationverifytokenremove" + }, + { + "from": "/references/cdi/import/delete-bulk-import-users", + "to": "/references/cdi/bulk-import/deletebulkimportusers" + }, + { + "from": "/references/cdi/import/get-bulk-import-users", + "to": "/references/cdi/bulk-import/getbulkimportusers" + }, + { + "from": "/references/cdi/import/get-bulk-import-users-count", + "to": "/references/cdi/bulk-import/importoneuserwithbulkimport" + }, + { + "from": "/references/cdi/import/post-bulk-import-import", + "to": "/references/cdi/bulk-import/countbulkimportusers" + }, + { + "from": "/references/cdi/import/post-bulk-import-users", + "to": "/references/cdi/bulk-import/addbulkimportusers" + }, + { + "from": "/references/cdi/mfa/get-totp-device-list", + "to": "/references/cdi/totp-recipe/gettotpdevices" + }, + { + "from": "/references/cdi/mfa/post-totp-device", + "to": "/references/cdi/totp-recipe/createtotpdevice" + }, + { + "from": "/references/cdi/mfa/post-totp-device-import", + "to": "/references/cdi/totp-recipe/importtotpdevice" + }, + { + "from": "/references/cdi/mfa/post-totp-device-remove", + "to": "/references/cdi/totp-recipe/removetotpdevice" + }, + { + "from": "/references/cdi/mfa/post-totp-device-verify", + "to": "/references/cdi/totp-recipe/verifytotpdevice" + }, + { + "from": "/references/cdi/mfa/post-totp-verify", + "to": "/references/cdi/totp-recipe/verifytotpcode" + }, + { + "from": "/references/cdi/mfa/put-totp-device", + "to": "/references/cdi/totp-recipe/updatetotpdevicename" + }, + { + "from": "/references/cdi/multitenancy/get-multitenancy-app-list", + "to": "/references/cdi/multitenancy-recipe/applistget" + }, + { + "from": "/references/cdi/multitenancy/get-multitenancy-app-list-v2", + "to": "/references/cdi/multitenancy-recipe/applistv2get" + }, + { + "from": "/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list", + "to": "/references/cdi/multitenancy-recipe/connectionuridomainlistget" + }, + { + "from": "/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list-v2", + "to": "/references/cdi/multitenancy-recipe/connectionuridomainlistv2get" + }, + { + "from": "/references/cdi/multitenancy/get-multitenancy-tenant", + "to": "/references/cdi/multitenancy-recipe/tenantconfigget" + }, + { + "from": "/references/cdi/multitenancy/get-multitenancy-tenant-list", + "to": "/references/cdi/multitenancy-recipe/tenantlistget" + }, + { + "from": "/references/cdi/multitenancy/get-multitenancy-tenant-list-v2", + "to": "/references/cdi/multitenancy-recipe/tenantlistv2get" + }, + { + "from": "/references/cdi/multitenancy/get-multitenancy-tenant-v2", + "to": "/references/cdi/multitenancy-recipe/tenantconfigv2get" + }, + { + "from": "/references/cdi/multitenancy/post-multitenancy-app-remove", + "to": "/references/cdi/multitenancy-recipe/deleteapppost" + }, + { + "from": "/references/cdi/multitenancy/post-multitenancy-config-thirdparty-remove", + "to": "/references/cdi/multitenancy-recipe/deletetenantconfigpost" + }, + { + "from": "/references/cdi/multitenancy/post-multitenancy-connectionuridomain-remove", + "to": "/references/cdi/multitenancy-recipe/deleteconnectionuridomainpost" + }, + { + "from": "/references/cdi/multitenancy/post-multitenancy-tenant-remove", + "to": "/references/cdi/multitenancy-recipe/deletetenantpost" + }, + { + "from": "/references/cdi/multitenancy/post-multitenancy-tenant-user", + "to": "/references/cdi/multitenancy-recipe/addusertotenant" + }, + { + "from": "/references/cdi/multitenancy/post-multitenancy-tenant-user-remove", + "to": "/references/cdi/multitenancy-recipe/removeuserfromtenant" + }, + { + "from": "/references/cdi/multitenancy/put-multitenancy-app", + "to": "/references/cdi/multitenancy-recipe/createorupdateappput" + }, + { + "from": "/references/cdi/multitenancy/put-multitenancy-app-v2", + "to": "/references/cdi/multitenancy-recipe/createorupdateappv2put" + }, + { + "from": "/references/cdi/multitenancy/put-multitenancy-config-thirdparty", + "to": "/references/cdi/multitenancy-recipe/createorupdatetenantconfigput" + }, + { + "from": "/references/cdi/multitenancy/put-multitenancy-connectionuridomain", + "to": "/references/cdi/multitenancy-recipe/createorupdateconnectionuridomainput" + }, + { + "from": "/references/cdi/multitenancy/put-multitenancy-connectionuridomain-v2", + "to": "/references/cdi/multitenancy-recipe/createorupdateconnectionuridomainv2put" + }, + { + "from": "/references/cdi/multitenancy/put-multitenancy-tenant", + "to": "/references/cdi/multitenancy-recipe/createorupdatetenantput" + }, + { + "from": "/references/cdi/multitenancy/put-multitenancy-tenant-v2", + "to": "/references/cdi/multitenancy-recipe/createorupdatetenantv2put" + }, + { + "from": "/references/cdi/oauth/get-jwks", + "to": "/references/cdi/jwt-recipe/getjwks" + }, + { + "from": "/references/cdi/oauth/get-oauth2-auth", + "to": "/references/cdi/oauth2provider-recipe/getoauth2auth" + }, + { + "from": "/references/cdi/oauth/get-oauth2-client", + "to": "/references/cdi/oauth2provider-recipe/getoauth2client" + }, + { + "from": "/references/cdi/oauth/get-oauth2-clients", + "to": "/references/cdi/oauth2provider-recipe/listoauth2clients" + }, + { + "from": "/references/cdi/oauth/get-oauth2-consent-request", + "to": "/references/cdi/oauth2provider-recipe/getoauth2consentrequest" + }, + { + "from": "/references/cdi/oauth/get-oauth2-login-request", + "to": "/references/cdi/oauth2provider-recipe/getoauth2loginrequest" + }, + { + "from": "/references/cdi/oauth/get-oauth2-sessions-logout", + "to": "/references/cdi/oauth2provider-recipe/getoauth2sessionslogout" + }, + { + "from": "/references/cdi/oauth/get-oauth2-token", + "to": "/references/cdi/oauth2provider-recipe/getoauth2token" + }, + { + "from": "/references/cdi/oauth/get-well-known-jwks", + "to": "/references/cdi/core/getwellknownjwks" + }, + { + "from": "/references/cdi/oauth/post-oauth2-client", + "to": "/references/cdi/oauth2provider-recipe/createoauth2client" + }, + { + "from": "/references/cdi/oauth/post-oauth2-client-remove", + "to": "/references/cdi/oauth2provider-recipe/removeoauth2client" + }, + { + "from": "/references/cdi/oauth/post-oauth2-consent-request-accept", + "to": "/references/cdi/oauth2provider-recipe/acceptoauth2consentrequest" + }, + { + "from": "/references/cdi/oauth/post-oauth2-consent-request-reject", + "to": "/references/cdi/oauth2provider-recipe/rejectoauth2consentrequest" + }, + { + "from": "/references/cdi/oauth/post-oauth2-login-request-accept", + "to": "/references/cdi/oauth2provider-recipe/acceptoauth2loginrequest" + }, + { + "from": "/references/cdi/oauth/post-oauth2-login-request-reject", + "to": "/references/cdi/oauth2provider-recipe/rejectoauth2loginrequest" + }, + { + "from": "/references/cdi/oauth/post-oauth2-logout-request-accept", + "to": "/references/cdi/oauth2provider-recipe/acceptoauth2logoutrequest" + }, + { + "from": "/references/cdi/oauth/post-oauth2-logout-request-reject", + "to": "/references/cdi/oauth2provider-recipe/rejectoauth2logoutrequest" + }, + { + "from": "/references/cdi/oauth/post-oauth2-session-revoke", + "to": "/references/cdi/oauth2provider-recipe/revokeoauth2session" + }, + { + "from": "/references/cdi/oauth/post-oauth2-token-introspect", + "to": "/references/cdi/oauth2provider-recipe/introspectoauth2token" + }, + { + "from": "/references/cdi/oauth/post-oauth2-token-revoke", + "to": "/references/cdi/oauth2provider-recipe/revokeoauth2token" + }, + { + "from": "/references/cdi/oauth/post-oauth2-tokens-revoke", + "to": "/references/cdi/oauth2provider-recipe/revokeoauth2tokens" + }, + { + "from": "/references/cdi/oauth/put-oauth2-client", + "to": "/references/cdi/oauth2provider-recipe/updateoauth2client" + }, + { + "from": "/references/cdi/passwordless/get-signinup-codes", + "to": "/references/cdi/passwordless-recipe/passwordlesslistcodes" + }, + { + "from": "/references/cdi/passwordless/get-user", + "to": "/references/cdi/passwordless-recipe/passwordlessgetuser" + }, + { + "from": "/references/cdi/passwordless/post-signinup-code", + "to": "/references/cdi/passwordless-recipe/passwordlessstartsignin" + }, + { + "from": "/references/cdi/passwordless/post-signinup-code-check", + "to": "/references/cdi/passwordless-recipe/passwordlesscheckcode" + }, + { + "from": "/references/cdi/passwordless/post-signinup-code-consume", + "to": "/references/cdi/passwordless-recipe/passwordlesstryusecode" + }, + { + "from": "/references/cdi/passwordless/post-signinup-code-remove", + "to": "/references/cdi/passwordless-recipe/passwordlessrevokecode" + }, + { + "from": "/references/cdi/passwordless/post-signinup-codes-remove", + "to": "/references/cdi/passwordless-recipe/passwordlessrevokeallcodesofuser" + }, + { + "from": "/references/cdi/passwordless/put-user", + "to": "/references/cdi/passwordless-recipe/passwordlessputuser" + }, + { + "from": "/references/cdi/session/get-jwt-data", + "to": "/references/cdi/session-recipe/getjwtdata" + }, + { + "from": "/references/cdi/session/get-session", + "to": "/references/cdi/session-recipe/getsessioninfo" + }, + { + "from": "/references/cdi/session/get-session-data", + "to": "/references/cdi/session-recipe/getsessiondata" + }, + { + "from": "/references/cdi/session/get-session-user", + "to": "/references/cdi/session-recipe/getusersessionhandles" + }, + { + "from": "/references/cdi/session/post-jwt", + "to": "/references/cdi/jwt-recipe/createsignedjwt" + }, + { + "from": "/references/cdi/session/post-session", + "to": "/references/cdi/session-recipe/createnewsession" + }, + { + "from": "/references/cdi/session/post-session-refresh", + "to": "/references/cdi/session-recipe/refreshsession" + }, + { + "from": "/references/cdi/session/post-session-regenerate", + "to": "/references/cdi/session-recipe/regeneratesession" + }, + { + "from": "/references/cdi/session/post-session-remove", + "to": "/references/cdi/session-recipe/deletesession" + }, + { + "from": "/references/cdi/session/post-session-verify", + "to": "/references/cdi/session-recipe/verifysession" + }, + { + "from": "/references/cdi/session/put-jwt-data", + "to": "/references/cdi/session-recipe/putjwtdata" + }, + { + "from": "/references/cdi/session/put-session-data", + "to": "/references/cdi/session-recipe/putsessiondata" + }, + { + "from": "/references/cdi/thirdparty/get-user", + "to": "/references/cdi/thirdparty-recipe/thirdpartygetuser" + }, + { + "from": "/references/cdi/thirdparty/get-users-by-email", + "to": "/references/cdi/thirdparty-recipe/thirdpartygetusersbyemail" + }, + { + "from": "/references/cdi/thirdparty/post-signinup", + "to": "/references/cdi/thirdparty-recipe/thirdpartysigninup" + }, + { + "from": "/references/cdi/user-metadata/get-user-metadata", + "to": "/references/cdi/user-metadata-recipe/usermetadataread" + }, + { + "from": "/references/cdi/user-metadata/post-user-metadata-remove", + "to": "/references/cdi/user-metadata-recipe/usermetadatadelete" + }, + { + "from": "/references/cdi/user-metadata/put-user-metadata", + "to": "/references/cdi/user-metadata-recipe/usermetadataupdate" + }, + { + "from": "/references/cdi/user-roles/get-permission-roles", + "to": "/references/cdi/user-roles-recipe/getpermissionroles" + }, + { + "from": "/references/cdi/user-roles/get-role-permissions", + "to": "/references/cdi/user-roles-recipe/getrolepermissions" + }, + { + "from": "/references/cdi/user-roles/get-role-users", + "to": "/references/cdi/user-roles-recipe/getroleusers" + }, + { + "from": "/references/cdi/user-roles/get-roles", + "to": "/references/cdi/user-roles-recipe/getroles" + }, + { + "from": "/references/cdi/user-roles/get-user-roles", + "to": "/references/cdi/user-roles-recipe/getuserroles" + }, + { + "from": "/references/cdi/user-roles/post-role-permissions-remove", + "to": "/references/cdi/user-roles-recipe/removerolepermissions" + }, + { + "from": "/references/cdi/user-roles/post-role-remove", + "to": "/references/cdi/user-roles-recipe/removerole" + }, + { + "from": "/references/cdi/user-roles/post-user-role-remove", + "to": "/references/cdi/user-roles-recipe/removeuserrole" + }, + { + "from": "/references/cdi/user-roles/put-role", + "to": "/references/cdi/user-roles-recipe/putrole" + }, + { + "from": "/references/cdi/user-roles/put-user-role", + "to": "/references/cdi/user-roles-recipe/adduserrole" + }, + { + "from": "/references/cdi/webauthn/delete-webauthn-credential", + "to": "/references/cdi/webauthn-recipe/removewebauthncredential" + }, + { + "from": "/references/cdi/webauthn/delete-webauthn-options", + "to": "/references/cdi/webauthn-recipe/removewebauthnoptions" + }, + { + "from": "/references/cdi/webauthn/get-webauthn-credential", + "to": "/references/cdi/webauthn-recipe/getwebauthncredential" + }, + { + "from": "/references/cdi/webauthn/get-webauthn-credentials", + "to": "/references/cdi/webauthn-recipe/listwebauthncredentials" + }, + { + "from": "/references/cdi/webauthn/get-webauthn-options", + "to": "/references/cdi/webauthn-recipe/getwebauthnoptions" + }, + { + "from": "/references/cdi/webauthn/post-webauthn-recover", + "to": "/references/cdi/webauthn-recipe/recoverwebauthnuser" + }, + { + "from": "/references/cdi/webauthn/post-webauthn-register", + "to": "/references/cdi/webauthn-recipe/registerwebauthncredential" + }, + { + "from": "/references/cdi/webauthn/post-webauthn-registration-options", + "to": "/references/cdi/webauthn-recipe/generateregistrationoptions" + }, + { + "from": "/references/cdi/webauthn/post-webauthn-signin", + "to": "/references/cdi/webauthn-recipe/signinwebauthnuser" + }, + { + "from": "/references/cdi/webauthn/post-webauthn-signin-options", + "to": "/references/cdi/webauthn-recipe/generatesigninoptions" + }, + { + "from": "/references/cdi/webauthn/post-webauthn-signup", + "to": "/references/cdi/webauthn-recipe/signupwebauthnuser" + }, + { + "from": "/references/cdi/webauthn/post-webauthn-token-consume", + "to": "/references/cdi/webauthn-recipe/consumewebauthntoken" + }, + { + "from": "/references/cdi/webauthn/post-webauthn-token-recovery", + "to": "/references/cdi/webauthn-recipe/generatetokenforrecovery" + }, + { + "from": "/references/cdi/webauthn/put-webauthn-email", + "to": "/references/cdi/webauthn-recipe/updateemail" + }, + { + "from": "/references/fdi/email-password/get-emailpassword-email-exists", + "to": "/references/fdi/emailpassword-recipe/emailexists" + }, + { + "from": "/references/fdi/email-password/get-signup-email-exists", + "to": "/references/fdi/emailpassword-recipe/emailexistsdepr" + }, + { + "from": "/references/fdi/email-password/post-signin", + "to": "/references/fdi/emailpassword-recipe/signin" + }, + { + "from": "/references/fdi/email-password/post-signup", + "to": "/references/fdi/emailpassword-recipe/signup" + }, + { + "from": "/references/fdi/email-password/post-user-password-reset", + "to": "/references/fdi/emailpassword-recipe/passwordreset" + }, + { + "from": "/references/fdi/email-password/post-user-password-reset-token", + "to": "/references/fdi/emailpassword-recipe/passwordresettoken" + }, + { + "from": "/references/fdi/email-verification/get-user-email-verify", + "to": "/references/fdi/emailverification-recipe/getverifyemail" + }, + { + "from": "/references/fdi/email-verification/post-user-email-verify", + "to": "/references/fdi/emailverification-recipe/verifyemail" + }, + { + "from": "/references/fdi/email-verification/post-user-email-verify-token", + "to": "/references/fdi/emailverification-recipe/verifyemailtoken" + }, + { + "from": "/references/fdi/get-example", + "to": "/references/fdi/app-api/exampleappapi" + }, + { + "from": "/references/fdi/get-jwt-jwks-json", + "to": "/references/fdi/jwt-recipe/getjwks" + }, + { + "from": "/references/fdi/get-loginmethods", + "to": "/references/fdi/multitenancy-recipe/loginmethods" + }, + { + "from": "/references/fdi/get-well-known-openid-configuration", + "to": "/references/fdi/openid-recipe/getopeniddiscoveryconfiguration" + }, + { + "from": "/references/fdi/mfa/get-totp-device-list", + "to": "/references/fdi/totp-recipe/listtotpdevices" + }, + { + "from": "/references/fdi/mfa/post-totp-device", + "to": "/references/fdi/totp-recipe/createtotpdevice" + }, + { + "from": "/references/fdi/mfa/post-totp-device-remove", + "to": "/references/fdi/totp-recipe/removetotpdevice" + }, + { + "from": "/references/fdi/mfa/post-totp-device-verify", + "to": "/references/fdi/totp-recipe/verifytotpdevice" + }, + { + "from": "/references/fdi/mfa/post-totp-verify", + "to": "/references/fdi/totp-recipe/verifytotp" + }, + { + "from": "/references/fdi/mfa/put-mfa-info", + "to": "/references/fdi/multifactorauth-recipe/getmfainfo" + }, + { + "from": "/references/fdi/oauth/get-oauth-auth", + "to": "/references/fdi/oauth2provider-recipe/oauthauthget" + }, + { + "from": "/references/fdi/oauth/get-oauth-end_session", + "to": "/references/fdi/oauth2provider-recipe/oauthendsessionget" + }, + { + "from": "/references/fdi/oauth/get-oauth-login", + "to": "/references/fdi/oauth2provider-recipe/oauthloginget" + }, + { + "from": "/references/fdi/oauth/get-oauth-logininfo", + "to": "/references/fdi/oauth2provider-recipe/oauthlogininfoget" + }, + { + "from": "/references/fdi/oauth/get-oauth-userinfo", + "to": "/references/fdi/oauth2provider-recipe/oauthuserinfoget" + }, + { + "from": "/references/fdi/oauth/post-oauth-end_session", + "to": "/references/fdi/oauth2provider-recipe/oauthendsessionpost" + }, + { + "from": "/references/fdi/oauth/post-oauth-introspect", + "to": "/references/fdi/oauth2provider-recipe/oauthintrospectpost" + }, + { + "from": "/references/fdi/oauth/post-oauth-logout", + "to": "/references/fdi/oauth2provider-recipe/oauthlogoutpost" + }, + { + "from": "/references/fdi/oauth/post-oauth-revoke", + "to": "/references/fdi/oauth2provider-recipe/oauthrevokepost" + }, + { + "from": "/references/fdi/oauth/post-oauth-token", + "to": "/references/fdi/oauth2provider-recipe/oauthtokenpost" + }, + { + "from": "/references/fdi/passwordless/get-passwordless-email-exists", + "to": "/references/fdi/passwordless-recipe/passwordlessemailexists" + }, + { + "from": "/references/fdi/passwordless/get-passwordless-phoneNumber-exists", + "to": "/references/fdi/passwordless-recipe/passwordlessphonenumberexists" + }, + { + "from": "/references/fdi/passwordless/get-signup-email-exists", + "to": "/references/fdi/passwordless-recipe/passwordlessemailexistsdepr" + }, + { + "from": "/references/fdi/passwordless/get-signup-phoneNumber-exists", + "to": "/references/fdi/passwordless-recipe/passwordlessphonenumberexistsdepr" + }, + { + "from": "/references/fdi/passwordless/post-signinup-code", + "to": "/references/fdi/passwordless-recipe/passwordlesssigninupstart" + }, + { + "from": "/references/fdi/passwordless/post-signinup-code-consume", + "to": "/references/fdi/passwordless-recipe/passwordlesssigninupconsume" + }, + { + "from": "/references/fdi/passwordless/post-signinup-code-resend", + "to": "/references/fdi/passwordless-recipe/passwordlesssigninupresend" + }, + { + "from": "/references/fdi/session/post-session-refresh", + "to": "/references/fdi/session-recipe/refresh" + }, + { + "from": "/references/fdi/session/post-signout", + "to": "/references/fdi/session-recipe/signout" + }, + { + "from": "/references/fdi/thirdparty/get-authorisationurl", + "to": "/references/fdi/thirdparty-recipe/authorisationurl" + }, + { + "from": "/references/fdi/thirdparty/post-callback-apple", + "to": "/references/fdi/thirdparty-recipe/thirdpartycallbackapple" + }, + { + "from": "/references/fdi/thirdparty/post-signinup", + "to": "/references/fdi/thirdparty-recipe/signinup" + }, + { + "from": "/references/fdi/webauthn/get-webauthn-email-exists", + "to": "/references/fdi/webauthn-recipe/webauthnemailexists" + }, + { + "from": "/references/fdi/webauthn/post-webauthn-credential", + "to": "/references/fdi/webauthn-recipe/webauthnregistercredential" + }, + { + "from": "/references/fdi/webauthn/post-webauthn-recover-account", + "to": "/references/fdi/webauthn-recipe/webauthnrecoveraccount" + }, + { + "from": "/references/fdi/webauthn/post-webauthn-recover-account-token", + "to": "/references/fdi/webauthn-recipe/webauthngeneraterecoveraccounttoken" + }, + { + "from": "/references/fdi/webauthn/post-webauthn-register-options", + "to": "/references/fdi/webauthn-recipe/webauthnregisteroptions" + }, + { + "from": "/references/fdi/webauthn/post-webauthn-signin", + "to": "/references/fdi/webauthn-recipe/webauthnsignin" + }, + { + "from": "/references/fdi/webauthn/post-webauthn-signin-options", + "to": "/references/fdi/webauthn-recipe/webauthnsigninoptions" + }, + { + "from": "/references/fdi/webauthn/post-webauthn-signup", + "to": "/references/fdi/webauthn-recipe/webauthnsignup" + } +] as const; diff --git a/scripts/blume/prefix-content-assets.mjs b/scripts/blume/prefix-content-assets.mjs new file mode 100644 index 0000000000..752361fd96 --- /dev/null +++ b/scripts/blume/prefix-content-assets.mjs @@ -0,0 +1,46 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; + +const docsRoot = path.resolve(import.meta.dirname, "../../docs"); + +const walk = async (directory) => { + const files = []; + for (const entry of await fs.readdir(directory, { withFileTypes: true })) { + const entryPath = path.join(directory, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(entryPath))); + } else if (/\.mdx?$/.test(entry.name)) { + files.push(entryPath); + } + } + return files; +}; + +let rewritten = 0; + +for (const file of await walk(docsRoot)) { + const source = await fs.readFile(file, "utf8"); + const output = source + .replace(/(\bsrc\s*=\s*["'])\/img\//g, (match, prefix) => { + rewritten += 1; + return `${prefix}/docs/img/`; + }) + .replace(/(!\[[^\]]*\]\()\/img\//g, (match, prefix) => { + rewritten += 1; + return `${prefix}/docs/img/`; + }) + .replaceAll( + "/docs/img/dashboard/tenant-management/custom-tenant-configuration.png", + "/docs/img/dashboard/tenant-management/custom-tenant-config.png", + ) + .replaceAll( + "/docs/img/dashboard/tenant-management/openid-configuration.png", + "/docs/img/dashboard/tenant-management/openid-config.png", + ); + + if (output !== source) { + await fs.writeFile(file, output); + } +} + +console.log(`Prefixed ${rewritten} content asset reference(s).`); diff --git a/scripts/blume/remove-openapi-stubs.mjs b/scripts/blume/remove-openapi-stubs.mjs new file mode 100644 index 0000000000..dfad351bfc --- /dev/null +++ b/scripts/blume/remove-openapi-stubs.mjs @@ -0,0 +1,22 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; + +const root = path.resolve(import.meta.dirname, "../.."); +const manifest = JSON.parse(await fs.readFile(path.join(root, "scripts/blume/route-manifest.json"), "utf8")); +let removed = 0; + +for (const operation of manifest.openapi) { + const file = path.join(root, "docs", `${operation.from}.mdx`); + try { + const source = await fs.readFile(file, "utf8"); + if (!source.includes(" { + if (!source.startsWith("---\n")) return { data: {}, body: source }; + const end = source.indexOf("\n---", 4); + return { + data: yaml.load(source.slice(4, end)) || {}, + body: source.slice(end + 4).replace(/^\n/, ""), + }; +}; + +const walk = async (directory) => { + const files = []; + for (const entry of await fs.readdir(directory, { withFileTypes: true })) { + if (entry.name.startsWith("_")) continue; + const entryPath = path.join(directory, entry.name); + if (entry.isDirectory()) files.push(...(await walk(entryPath))); + else if (/\.mdx?$/.test(entry.name)) files.push(entryPath); + } + return files; +}; + +const routeForFile = (file) => { + const segments = path + .relative(docsRoot, file) + .replace(/\.mdx?$/, "") + .split(path.sep); + if (segments.at(-1) === "index") segments.pop(); + return `/${segments.join("/")}`.replace(/\/$/, "") || "/"; +}; + +const legacyDataFor = (file) => { + let relative = path.relative(root, file); + if (relative.endsWith("authentication/social/built-in-providers-config.mdx")) { + relative = relative.replace("built-in-providers-config.mdx", "built-in-providers.mdx"); + } else if (relative.endsWith("additional-verification/mfa/webauthn-setup.mdx")) { + relative = relative.replace("webauthn-setup.mdx", "webauthn-secondary-factor-setup.mdx"); + } + try { + return split(execFileSync("git", ["show", `HEAD:${relative}`], { cwd: root, encoding: "utf8" })).data; + } catch { + return {}; + } +}; + +for (const file of await walk(docsRoot)) { + const source = await fs.readFile(file, "utf8"); + const { data, body } = split(source); + const legacy = legacyDataFor(file); + const route = routeForFile(file); + const sidebar = { ...(data.sidebar || {}) }; + + if (!sidebar.label && legacy.sidebar_label) sidebar.label = legacy.sidebar_label; + if (sidebar.order === undefined && typeof legacy.sidebar_position === "number") + sidebar.order = legacy.sidebar_position; + if (legacy.unlisted === true || route === "/legacy/core/v10/self-host-supertokens") sidebar.hidden = true; + + const next = { + ...data, + ...(Object.keys(sidebar).length > 0 ? { sidebar } : {}), + }; + const frontmatter = yaml.dump(next, { lineWidth: 120, noRefs: true, sortKeys: false }).trim(); + await fs.writeFile(file, `---\n${frontmatter}\n---\n\n${body.trim()}\n`); +} + +console.log("Restored legacy sidebar metadata on migrated pages"); diff --git a/scripts/blume/route-manifest.json b/scripts/blume/route-manifest.json new file mode 100644 index 0000000000..f54e882b0c --- /dev/null +++ b/scripts/blume/route-manifest.json @@ -0,0 +1,3605 @@ +{ + "counts": { + "pages": 514, + "openapiOperations": 205 + }, + "pages": [ + { + "file": "docs/index.mdx", + "route": "/", + "publicRoute": "/docs" + }, + { + "file": "docs/additional-verification/attack-protection-suite/initial-setup.mdx", + "route": "/additional-verification/attack-protection-suite/initial-setup", + "publicRoute": "/docs/additional-verification/attack-protection-suite/initial-setup" + }, + { + "file": "docs/additional-verification/attack-protection-suite/introduction.mdx", + "route": "/additional-verification/attack-protection-suite/introduction", + "publicRoute": "/docs/additional-verification/attack-protection-suite/introduction" + }, + { + "file": "docs/additional-verification/captcha.mdx", + "route": "/additional-verification/captcha", + "publicRoute": "/docs/additional-verification/captcha" + }, + { + "file": "docs/additional-verification/email-verification/changing-style.mdx", + "route": "/additional-verification/email-verification/changing-style", + "publicRoute": "/docs/additional-verification/email-verification/changing-style" + }, + { + "file": "docs/additional-verification/email-verification/embed-in-page.mdx", + "route": "/additional-verification/email-verification/embed-in-page", + "publicRoute": "/docs/additional-verification/email-verification/embed-in-page" + }, + { + "file": "docs/additional-verification/email-verification/hooks-and-overrides.mdx", + "route": "/additional-verification/email-verification/hooks-and-overrides", + "publicRoute": "/docs/additional-verification/email-verification/hooks-and-overrides" + }, + { + "file": "docs/additional-verification/email-verification/initial-setup.mdx", + "route": "/additional-verification/email-verification/initial-setup", + "publicRoute": "/docs/additional-verification/email-verification/initial-setup" + }, + { + "file": "docs/additional-verification/email-verification/introduction.mdx", + "route": "/additional-verification/email-verification/introduction", + "publicRoute": "/docs/additional-verification/email-verification/introduction" + }, + { + "file": "docs/additional-verification/email-verification/manual-actions.mdx", + "route": "/additional-verification/email-verification/manual-actions", + "publicRoute": "/docs/additional-verification/email-verification/manual-actions" + }, + { + "file": "docs/additional-verification/email-verification/protecting-routes.mdx", + "route": "/additional-verification/email-verification/protecting-routes", + "publicRoute": "/docs/additional-verification/email-verification/protecting-routes" + }, + { + "file": "docs/additional-verification/mfa/backup-codes.mdx", + "route": "/additional-verification/mfa/backup-codes", + "publicRoute": "/docs/additional-verification/mfa/backup-codes" + }, + { + "file": "docs/additional-verification/mfa/email-sms-otp/otp-for-all-users.mdx", + "route": "/additional-verification/mfa/email-sms-otp/otp-for-all-users", + "publicRoute": "/docs/additional-verification/mfa/email-sms-otp/otp-for-all-users" + }, + { + "file": "docs/additional-verification/mfa/email-sms-otp/otp-for-opt-in-users.mdx", + "route": "/additional-verification/mfa/email-sms-otp/otp-for-opt-in-users", + "publicRoute": "/docs/additional-verification/mfa/email-sms-otp/otp-for-opt-in-users" + }, + { + "file": "docs/additional-verification/mfa/embed-the-prebuilt-ui.mdx", + "route": "/additional-verification/mfa/embed-the-prebuilt-ui", + "publicRoute": "/docs/additional-verification/mfa/embed-the-prebuilt-ui" + }, + { + "file": "docs/additional-verification/mfa/hooks-and-overrides.mdx", + "route": "/additional-verification/mfa/hooks-and-overrides", + "publicRoute": "/docs/additional-verification/mfa/hooks-and-overrides" + }, + { + "file": "docs/additional-verification/mfa/important-concepts.mdx", + "route": "/additional-verification/mfa/important-concepts", + "publicRoute": "/docs/additional-verification/mfa/important-concepts" + }, + { + "file": "docs/additional-verification/mfa/initial-setup.mdx", + "route": "/additional-verification/mfa/initial-setup", + "publicRoute": "/docs/additional-verification/mfa/initial-setup" + }, + { + "file": "docs/additional-verification/mfa/introduction.mdx", + "route": "/additional-verification/mfa/introduction", + "publicRoute": "/docs/additional-verification/mfa/introduction" + }, + { + "file": "docs/additional-verification/mfa/legacy-mfa/backend-setup/first-factor.mdx", + "route": "/additional-verification/mfa/legacy-mfa/backend-setup/first-factor", + "publicRoute": "/docs/additional-verification/mfa/legacy-mfa/backend-setup/first-factor" + }, + { + "file": "docs/additional-verification/mfa/legacy-mfa/backend-setup/protecting-api.mdx", + "route": "/additional-verification/mfa/legacy-mfa/backend-setup/protecting-api", + "publicRoute": "/docs/additional-verification/mfa/legacy-mfa/backend-setup/protecting-api" + }, + { + "file": "docs/additional-verification/mfa/legacy-mfa/backend-setup/second-factor.mdx", + "route": "/additional-verification/mfa/legacy-mfa/backend-setup/second-factor", + "publicRoute": "/docs/additional-verification/mfa/legacy-mfa/backend-setup/second-factor" + }, + { + "file": "docs/additional-verification/mfa/legacy-mfa/frontend-custom.mdx", + "route": "/additional-verification/mfa/legacy-mfa/frontend-custom", + "publicRoute": "/docs/additional-verification/mfa/legacy-mfa/frontend-custom" + }, + { + "file": "docs/additional-verification/mfa/legacy-mfa/how-it-works.mdx", + "route": "/additional-verification/mfa/legacy-mfa/how-it-works", + "publicRoute": "/docs/additional-verification/mfa/legacy-mfa/how-it-works" + }, + { + "file": "docs/additional-verification/mfa/legacy-mfa/legacy-vs-new.mdx", + "route": "/additional-verification/mfa/legacy-mfa/legacy-vs-new", + "publicRoute": "/docs/additional-verification/mfa/legacy-mfa/legacy-vs-new" + }, + { + "file": "docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/init.mdx", + "route": "/additional-verification/mfa/legacy-mfa/prebuilt-ui/init", + "publicRoute": "/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/init" + }, + { + "file": "docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/protecting-routes.mdx", + "route": "/additional-verification/mfa/legacy-mfa/prebuilt-ui/protecting-routes", + "publicRoute": "/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/protecting-routes" + }, + { + "file": "docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/showing-login-ui.mdx", + "route": "/additional-verification/mfa/legacy-mfa/prebuilt-ui/showing-login-ui", + "publicRoute": "/docs/additional-verification/mfa/legacy-mfa/prebuilt-ui/showing-login-ui" + }, + { + "file": "docs/additional-verification/mfa/migration/legacy-to-new.mdx", + "route": "/additional-verification/mfa/migration/legacy-to-new", + "publicRoute": "/docs/additional-verification/mfa/migration/legacy-to-new" + }, + { + "file": "docs/additional-verification/mfa/migration/old-sdk-to-new.mdx", + "route": "/additional-verification/mfa/migration/old-sdk-to-new", + "publicRoute": "/docs/additional-verification/mfa/migration/old-sdk-to-new" + }, + { + "file": "docs/additional-verification/mfa/protect-routes.mdx", + "route": "/additional-verification/mfa/protect-routes", + "publicRoute": "/docs/additional-verification/mfa/protect-routes" + }, + { + "file": "docs/additional-verification/mfa/step-up-auth.mdx", + "route": "/additional-verification/mfa/step-up-auth", + "publicRoute": "/docs/additional-verification/mfa/step-up-auth" + }, + { + "file": "docs/additional-verification/mfa/totp/totp-for-all-users.mdx", + "route": "/additional-verification/mfa/totp/totp-for-all-users", + "publicRoute": "/docs/additional-verification/mfa/totp/totp-for-all-users" + }, + { + "file": "docs/additional-verification/mfa/totp/totp-for-opt-in-users.mdx", + "route": "/additional-verification/mfa/totp/totp-for-opt-in-users", + "publicRoute": "/docs/additional-verification/mfa/totp/totp-for-opt-in-users" + }, + { + "file": "docs/additional-verification/mfa/webauthn-setup.mdx", + "route": "/additional-verification/mfa/webauthn-setup", + "publicRoute": "/docs/additional-verification/mfa/webauthn-setup" + }, + { + "file": "docs/additional-verification/session-verification/claim-validation.mdx", + "route": "/additional-verification/session-verification/claim-validation", + "publicRoute": "/docs/additional-verification/session-verification/claim-validation" + }, + { + "file": "docs/additional-verification/session-verification/protect-api-routes.mdx", + "route": "/additional-verification/session-verification/protect-api-routes", + "publicRoute": "/docs/additional-verification/session-verification/protect-api-routes" + }, + { + "file": "docs/additional-verification/session-verification/protect-frontend-routes.mdx", + "route": "/additional-verification/session-verification/protect-frontend-routes", + "publicRoute": "/docs/additional-verification/session-verification/protect-frontend-routes" + }, + { + "file": "docs/additional-verification/session-verification/ssr.mdx", + "route": "/additional-verification/session-verification/ssr", + "publicRoute": "/docs/additional-verification/session-verification/ssr" + }, + { + "file": "docs/additional-verification/session-verification/with-websocket.mdx", + "route": "/additional-verification/session-verification/with-websocket", + "publicRoute": "/docs/additional-verification/session-verification/with-websocket" + }, + { + "file": "docs/additional-verification/user-roles/initial-setup.mdx", + "route": "/additional-verification/user-roles/initial-setup", + "publicRoute": "/docs/additional-verification/user-roles/initial-setup" + }, + { + "file": "docs/additional-verification/user-roles/introduction.mdx", + "route": "/additional-verification/user-roles/introduction", + "publicRoute": "/docs/additional-verification/user-roles/introduction" + }, + { + "file": "docs/additional-verification/user-roles/protecting-routes.mdx", + "route": "/additional-verification/user-roles/protecting-routes", + "publicRoute": "/docs/additional-verification/user-roles/protecting-routes" + }, + { + "file": "docs/additional-verification/user-roles/role-management-actions.mdx", + "route": "/additional-verification/user-roles/role-management-actions", + "publicRoute": "/docs/additional-verification/user-roles/role-management-actions" + }, + { + "file": "docs/authentication/ai-authentication.mdx", + "route": "/authentication/ai-authentication", + "publicRoute": "/docs/authentication/ai-authentication" + }, + { + "file": "docs/authentication/email-password/customize-the-sign-in-form.mdx", + "route": "/authentication/email-password/customize-the-sign-in-form", + "publicRoute": "/docs/authentication/email-password/customize-the-sign-in-form" + }, + { + "file": "docs/authentication/email-password/customize-the-sign-up-form.mdx", + "route": "/authentication/email-password/customize-the-sign-up-form", + "publicRoute": "/docs/authentication/email-password/customize-the-sign-up-form" + }, + { + "file": "docs/authentication/email-password/disable-signup.mdx", + "route": "/authentication/email-password/disable-signup", + "publicRoute": "/docs/authentication/email-password/disable-signup" + }, + { + "file": "docs/authentication/email-password/hooks-and-overrides.mdx", + "route": "/authentication/email-password/hooks-and-overrides", + "publicRoute": "/docs/authentication/email-password/hooks-and-overrides" + }, + { + "file": "docs/authentication/email-password/implement-username-login.mdx", + "route": "/authentication/email-password/implement-username-login", + "publicRoute": "/docs/authentication/email-password/implement-username-login" + }, + { + "file": "docs/authentication/email-password/introduction.mdx", + "route": "/authentication/email-password/introduction", + "publicRoute": "/docs/authentication/email-password/introduction" + }, + { + "file": "docs/authentication/email-password/password-hashing.mdx", + "route": "/authentication/email-password/password-hashing", + "publicRoute": "/docs/authentication/email-password/password-hashing" + }, + { + "file": "docs/authentication/email-password/password-managers.mdx", + "route": "/authentication/email-password/password-managers", + "publicRoute": "/docs/authentication/email-password/password-managers" + }, + { + "file": "docs/authentication/email-password/password-reset.mdx", + "route": "/authentication/email-password/password-reset", + "publicRoute": "/docs/authentication/email-password/password-reset" + }, + { + "file": "docs/authentication/enterprise/common-domain-login.mdx", + "route": "/authentication/enterprise/common-domain-login", + "publicRoute": "/docs/authentication/enterprise/common-domain-login" + }, + { + "file": "docs/authentication/enterprise/important-concepts.mdx", + "route": "/authentication/enterprise/important-concepts", + "publicRoute": "/docs/authentication/enterprise/important-concepts" + }, + { + "file": "docs/authentication/enterprise/initial-setup.mdx", + "route": "/authentication/enterprise/initial-setup", + "publicRoute": "/docs/authentication/enterprise/initial-setup" + }, + { + "file": "docs/authentication/enterprise/introduction.mdx", + "route": "/authentication/enterprise/introduction", + "publicRoute": "/docs/authentication/enterprise/introduction" + }, + { + "file": "docs/authentication/enterprise/legacy-saml.mdx", + "route": "/authentication/enterprise/legacy-saml", + "publicRoute": "/docs/authentication/enterprise/legacy-saml" + }, + { + "file": "docs/authentication/enterprise/manage-apps.mdx", + "route": "/authentication/enterprise/manage-apps", + "publicRoute": "/docs/authentication/enterprise/manage-apps" + }, + { + "file": "docs/authentication/enterprise/manage-tenants.mdx", + "route": "/authentication/enterprise/manage-tenants", + "publicRoute": "/docs/authentication/enterprise/manage-tenants" + }, + { + "file": "docs/authentication/enterprise/saml.mdx", + "route": "/authentication/enterprise/saml", + "publicRoute": "/docs/authentication/enterprise/saml" + }, + { + "file": "docs/authentication/enterprise/subdomain-login.mdx", + "route": "/authentication/enterprise/subdomain-login", + "publicRoute": "/docs/authentication/enterprise/subdomain-login" + }, + { + "file": "docs/authentication/enterprise/tenant-discovery.mdx", + "route": "/authentication/enterprise/tenant-discovery", + "publicRoute": "/docs/authentication/enterprise/tenant-discovery" + }, + { + "file": "docs/authentication/enterprise/tenant-management-plugin.mdx", + "route": "/authentication/enterprise/tenant-management-plugin", + "publicRoute": "/docs/authentication/enterprise/tenant-management-plugin" + }, + { + "file": "docs/authentication/m2m/client-credentials.mdx", + "route": "/authentication/m2m/client-credentials", + "publicRoute": "/docs/authentication/m2m/client-credentials" + }, + { + "file": "docs/authentication/m2m/introduction.mdx", + "route": "/authentication/m2m/introduction", + "publicRoute": "/docs/authentication/m2m/introduction" + }, + { + "file": "docs/authentication/m2m/legacy-flow.mdx", + "route": "/authentication/m2m/legacy-flow", + "publicRoute": "/docs/authentication/m2m/legacy-flow" + }, + { + "file": "docs/authentication/overview.mdx", + "route": "/authentication/overview", + "publicRoute": "/docs/authentication/overview" + }, + { + "file": "docs/authentication/passkeys/customization.mdx", + "route": "/authentication/passkeys/customization", + "publicRoute": "/docs/authentication/passkeys/customization" + }, + { + "file": "docs/authentication/passkeys/important-concepts.mdx", + "route": "/authentication/passkeys/important-concepts", + "publicRoute": "/docs/authentication/passkeys/important-concepts" + }, + { + "file": "docs/authentication/passkeys/initial-setup.mdx", + "route": "/authentication/passkeys/initial-setup", + "publicRoute": "/docs/authentication/passkeys/initial-setup" + }, + { + "file": "docs/authentication/passkeys/introduction.mdx", + "route": "/authentication/passkeys/introduction", + "publicRoute": "/docs/authentication/passkeys/introduction" + }, + { + "file": "docs/authentication/passwordless/allow-list-flow.mdx", + "route": "/authentication/passwordless/allow-list-flow", + "publicRoute": "/docs/authentication/passwordless/allow-list-flow" + }, + { + "file": "docs/authentication/passwordless/configure-email-and-sms-behavior.mdx", + "route": "/authentication/passwordless/configure-email-and-sms-behavior", + "publicRoute": "/docs/authentication/passwordless/configure-email-and-sms-behavior" + }, + { + "file": "docs/authentication/passwordless/customize-the-magic-link.mdx", + "route": "/authentication/passwordless/customize-the-magic-link", + "publicRoute": "/docs/authentication/passwordless/customize-the-magic-link" + }, + { + "file": "docs/authentication/passwordless/customize-the-otp.mdx", + "route": "/authentication/passwordless/customize-the-otp", + "publicRoute": "/docs/authentication/passwordless/customize-the-otp" + }, + { + "file": "docs/authentication/passwordless/hooks-and-overrides.mdx", + "route": "/authentication/passwordless/hooks-and-overrides", + "publicRoute": "/docs/authentication/passwordless/hooks-and-overrides" + }, + { + "file": "docs/authentication/passwordless/initial-setup.mdx", + "route": "/authentication/passwordless/initial-setup", + "publicRoute": "/docs/authentication/passwordless/initial-setup" + }, + { + "file": "docs/authentication/passwordless/introduction.mdx", + "route": "/authentication/passwordless/introduction", + "publicRoute": "/docs/authentication/passwordless/introduction" + }, + { + "file": "docs/authentication/passwordless/invite-link-flow.mdx", + "route": "/authentication/passwordless/invite-link-flow", + "publicRoute": "/docs/authentication/passwordless/invite-link-flow" + }, + { + "file": "docs/authentication/social/add-multiple-clients-for-the-same-provider.mdx", + "route": "/authentication/social/add-multiple-clients-for-the-same-provider", + "publicRoute": "/docs/authentication/social/add-multiple-clients-for-the-same-provider" + }, + { + "file": "docs/authentication/social/built-in-providers-config.mdx", + "route": "/authentication/social/built-in-providers-config", + "publicRoute": "/docs/authentication/social/built-in-providers-config" + }, + { + "file": "docs/authentication/social/custom-invite-flow.mdx", + "route": "/authentication/social/custom-invite-flow", + "publicRoute": "/docs/authentication/social/custom-invite-flow" + }, + { + "file": "docs/authentication/social/custom-providers.mdx", + "route": "/authentication/social/custom-providers", + "publicRoute": "/docs/authentication/social/custom-providers" + }, + { + "file": "docs/authentication/social/hooks-and-overrides.mdx", + "route": "/authentication/social/hooks-and-overrides", + "publicRoute": "/docs/authentication/social/hooks-and-overrides" + }, + { + "file": "docs/authentication/social/initial-setup.mdx", + "route": "/authentication/social/initial-setup", + "publicRoute": "/docs/authentication/social/initial-setup" + }, + { + "file": "docs/authentication/social/introduction.mdx", + "route": "/authentication/social/introduction", + "publicRoute": "/docs/authentication/social/introduction" + }, + { + "file": "docs/authentication/unified-login/add-custom-claims-in-tokens.mdx", + "route": "/authentication/unified-login/add-custom-claims-in-tokens", + "publicRoute": "/docs/authentication/unified-login/add-custom-claims-in-tokens" + }, + { + "file": "docs/authentication/unified-login/introduction.mdx", + "route": "/authentication/unified-login/introduction", + "publicRoute": "/docs/authentication/unified-login/introduction" + }, + { + "file": "docs/authentication/unified-login/oauth2-basics.mdx", + "route": "/authentication/unified-login/oauth2-basics", + "publicRoute": "/docs/authentication/unified-login/oauth2-basics" + }, + { + "file": "docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend.mdx", + "route": "/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend", + "publicRoute": "/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-a-single-backend" + }, + { + "file": "docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-separate-backends.mdx", + "route": "/authentication/unified-login/quickstart-guides/multiple-frontends-with-separate-backends", + "publicRoute": "/docs/authentication/unified-login/quickstart-guides/multiple-frontends-with-separate-backends" + }, + { + "file": "docs/authentication/unified-login/quickstart-guides/reuse-website-login.mdx", + "route": "/authentication/unified-login/quickstart-guides/reuse-website-login", + "publicRoute": "/docs/authentication/unified-login/quickstart-guides/reuse-website-login" + }, + { + "file": "docs/authentication/unified-login/verify-tokens.mdx", + "route": "/authentication/unified-login/verify-tokens", + "publicRoute": "/docs/authentication/unified-login/verify-tokens" + }, + { + "file": "docs/authentication/unified-login/work-with-scopes.mdx", + "route": "/authentication/unified-login/work-with-scopes", + "publicRoute": "/docs/authentication/unified-login/work-with-scopes" + }, + { + "file": "docs/deployment/migrate-from-mysql.mdx", + "route": "/deployment/migrate-from-mysql", + "publicRoute": "/docs/deployment/migrate-from-mysql" + }, + { + "file": "docs/deployment/rate-limits.mdx", + "route": "/deployment/rate-limits", + "publicRoute": "/docs/deployment/rate-limits" + }, + { + "file": "docs/deployment/scalability.mdx", + "route": "/deployment/scalability", + "publicRoute": "/docs/deployment/scalability" + }, + { + "file": "docs/deployment/self-host-supertokens.mdx", + "route": "/deployment/self-host-supertokens", + "publicRoute": "/docs/deployment/self-host-supertokens" + }, + { + "file": "docs/deployment/telemetry.mdx", + "route": "/deployment/telemetry", + "publicRoute": "/docs/deployment/telemetry" + }, + { + "file": "docs/legacy/core/v10/self-host-supertokens.mdx", + "route": "/legacy/core/v10/self-host-supertokens", + "publicRoute": "/docs/legacy/core/v10/self-host-supertokens" + }, + { + "file": "docs/migration/account-migration.mdx", + "route": "/migration/account-migration", + "publicRoute": "/docs/migration/account-migration" + }, + { + "file": "docs/migration/legacy/about.mdx", + "route": "/migration/legacy/about", + "publicRoute": "/docs/migration/legacy/about" + }, + { + "file": "docs/migration/legacy/account-creation/email-verification.mdx", + "route": "/migration/legacy/account-creation/email-verification", + "publicRoute": "/docs/migration/legacy/account-creation/email-verification" + }, + { + "file": "docs/migration/legacy/account-creation/ep-migration-without-password-hash.mdx", + "route": "/migration/legacy/account-creation/ep-migration-without-password-hash", + "publicRoute": "/docs/migration/legacy/account-creation/ep-migration-without-password-hash" + }, + { + "file": "docs/migration/legacy/account-creation/user-creation.mdx", + "route": "/migration/legacy/account-creation/user-creation", + "publicRoute": "/docs/migration/legacy/account-creation/user-creation" + }, + { + "file": "docs/migration/legacy/account-creation/user-id-mapping.mdx", + "route": "/migration/legacy/account-creation/user-id-mapping", + "publicRoute": "/docs/migration/legacy/account-creation/user-id-mapping" + }, + { + "file": "docs/migration/legacy/data-migration.mdx", + "route": "/migration/legacy/data-migration", + "publicRoute": "/docs/migration/legacy/data-migration" + }, + { + "file": "docs/migration/legacy/mfa-migration.mdx", + "route": "/migration/legacy/mfa-migration", + "publicRoute": "/docs/migration/legacy/mfa-migration" + }, + { + "file": "docs/migration/legacy/session-migration.mdx", + "route": "/migration/legacy/session-migration", + "publicRoute": "/docs/migration/legacy/session-migration" + }, + { + "file": "docs/migration/overview.mdx", + "route": "/migration/overview", + "publicRoute": "/docs/migration/overview" + }, + { + "file": "docs/migration/rownd/migration-steps.mdx", + "route": "/migration/rownd/migration-steps", + "publicRoute": "/docs/migration/rownd/migration-steps" + }, + { + "file": "docs/migration/rownd/sdk-integration-guide.mdx", + "route": "/migration/rownd/sdk-integration-guide", + "publicRoute": "/docs/migration/rownd/sdk-integration-guide" + }, + { + "file": "docs/migration/session-migration.mdx", + "route": "/migration/session-migration", + "publicRoute": "/docs/migration/session-migration" + }, + { + "file": "docs/platform-configuration/email-delivery.mdx", + "route": "/platform-configuration/email-delivery", + "publicRoute": "/docs/platform-configuration/email-delivery" + }, + { + "file": "docs/platform-configuration/sms-delivery.mdx", + "route": "/platform-configuration/sms-delivery", + "publicRoute": "/docs/platform-configuration/sms-delivery" + }, + { + "file": "docs/platform-configuration/supertokens-core/add-ssl-via-nginx.mdx", + "route": "/platform-configuration/supertokens-core/add-ssl-via-nginx", + "publicRoute": "/docs/platform-configuration/supertokens-core/add-ssl-via-nginx" + }, + { + "file": "docs/platform-configuration/supertokens-core/api-keys.mdx", + "route": "/platform-configuration/supertokens-core/api-keys", + "publicRoute": "/docs/platform-configuration/supertokens-core/api-keys" + }, + { + "file": "docs/platform-configuration/supertokens-core/base-path.mdx", + "route": "/platform-configuration/supertokens-core/base-path", + "publicRoute": "/docs/platform-configuration/supertokens-core/base-path" + }, + { + "file": "docs/platform-configuration/supertokens-core/cli.mdx", + "route": "/platform-configuration/supertokens-core/cli", + "publicRoute": "/docs/platform-configuration/supertokens-core/cli" + }, + { + "file": "docs/platform-configuration/supertokens-core/ip-allow-deny.mdx", + "route": "/platform-configuration/supertokens-core/ip-allow-deny", + "publicRoute": "/docs/platform-configuration/supertokens-core/ip-allow-deny" + }, + { + "file": "docs/post-authentication/account-linking/add-passwords-to-an-existing-account.mdx", + "route": "/post-authentication/account-linking/add-passwords-to-an-existing-account", + "publicRoute": "/docs/post-authentication/account-linking/add-passwords-to-an-existing-account" + }, + { + "file": "docs/post-authentication/account-linking/automatic-account-linking.mdx", + "route": "/post-authentication/account-linking/automatic-account-linking", + "publicRoute": "/docs/post-authentication/account-linking/automatic-account-linking" + }, + { + "file": "docs/post-authentication/account-linking/important-concepts.mdx", + "route": "/post-authentication/account-linking/important-concepts", + "publicRoute": "/docs/post-authentication/account-linking/important-concepts" + }, + { + "file": "docs/post-authentication/account-linking/introduction.mdx", + "route": "/post-authentication/account-linking/introduction", + "publicRoute": "/docs/post-authentication/account-linking/introduction" + }, + { + "file": "docs/post-authentication/account-linking/link-social-accounts.mdx", + "route": "/post-authentication/account-linking/link-social-accounts", + "publicRoute": "/docs/post-authentication/account-linking/link-social-accounts" + }, + { + "file": "docs/post-authentication/account-linking/manual-account-linking.mdx", + "route": "/post-authentication/account-linking/manual-account-linking", + "publicRoute": "/docs/post-authentication/account-linking/manual-account-linking" + }, + { + "file": "docs/post-authentication/dashboard/initial-setup.mdx", + "route": "/post-authentication/dashboard/initial-setup", + "publicRoute": "/docs/post-authentication/dashboard/initial-setup" + }, + { + "file": "docs/post-authentication/dashboard/introduction.mdx", + "route": "/post-authentication/dashboard/introduction", + "publicRoute": "/docs/post-authentication/dashboard/introduction" + }, + { + "file": "docs/post-authentication/dashboard/tenant-management.mdx", + "route": "/post-authentication/dashboard/tenant-management", + "publicRoute": "/docs/post-authentication/dashboard/tenant-management" + }, + { + "file": "docs/post-authentication/dashboard/user-management.mdx", + "route": "/post-authentication/dashboard/user-management", + "publicRoute": "/docs/post-authentication/dashboard/user-management" + }, + { + "file": "docs/post-authentication/post-login-redirect.mdx", + "route": "/post-authentication/post-login-redirect", + "publicRoute": "/docs/post-authentication/post-login-redirect" + }, + { + "file": "docs/post-authentication/session-management/access-session-data.mdx", + "route": "/post-authentication/session-management/access-session-data", + "publicRoute": "/docs/post-authentication/session-management/access-session-data" + }, + { + "file": "docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting.mdx", + "route": "/post-authentication/session-management/advanced-workflows/access-token-blacklisting", + "publicRoute": "/docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting" + }, + { + "file": "docs/post-authentication/session-management/advanced-workflows/anonymous-session.mdx", + "route": "/post-authentication/session-management/advanced-workflows/anonymous-session", + "publicRoute": "/docs/post-authentication/session-management/advanced-workflows/anonymous-session" + }, + { + "file": "docs/post-authentication/session-management/advanced-workflows/customize-error-handling.mdx", + "route": "/post-authentication/session-management/advanced-workflows/customize-error-handling", + "publicRoute": "/docs/post-authentication/session-management/advanced-workflows/customize-error-handling" + }, + { + "file": "docs/post-authentication/session-management/advanced-workflows/disable-frontend-interceptors.mdx", + "route": "/post-authentication/session-management/advanced-workflows/disable-frontend-interceptors", + "publicRoute": "/docs/post-authentication/session-management/advanced-workflows/disable-frontend-interceptors" + }, + { + "file": "docs/post-authentication/session-management/advanced-workflows/in-iframe.mdx", + "route": "/post-authentication/session-management/advanced-workflows/in-iframe", + "publicRoute": "/docs/post-authentication/session-management/advanced-workflows/in-iframe" + }, + { + "file": "docs/post-authentication/session-management/advanced-workflows/multiple-api-endpoints.mdx", + "route": "/post-authentication/session-management/advanced-workflows/multiple-api-endpoints", + "publicRoute": "/docs/post-authentication/session-management/advanced-workflows/multiple-api-endpoints" + }, + { + "file": "docs/post-authentication/session-management/advanced-workflows/user-impersonation.mdx", + "route": "/post-authentication/session-management/advanced-workflows/user-impersonation", + "publicRoute": "/docs/post-authentication/session-management/advanced-workflows/user-impersonation" + }, + { + "file": "docs/post-authentication/session-management/introduction.mdx", + "route": "/post-authentication/session-management/introduction", + "publicRoute": "/docs/post-authentication/session-management/introduction" + }, + { + "file": "docs/post-authentication/session-management/security.mdx", + "route": "/post-authentication/session-management/security", + "publicRoute": "/docs/post-authentication/session-management/security" + }, + { + "file": "docs/post-authentication/session-management/session-invalidation.mdx", + "route": "/post-authentication/session-management/session-invalidation", + "publicRoute": "/docs/post-authentication/session-management/session-invalidation" + }, + { + "file": "docs/post-authentication/session-management/share-session-across-sub-domains.mdx", + "route": "/post-authentication/session-management/share-session-across-sub-domains", + "publicRoute": "/docs/post-authentication/session-management/share-session-across-sub-domains" + }, + { + "file": "docs/post-authentication/session-management/switch-between-cookies-and-header-authentication.mdx", + "route": "/post-authentication/session-management/switch-between-cookies-and-header-authentication", + "publicRoute": "/docs/post-authentication/session-management/switch-between-cookies-and-header-authentication" + }, + { + "file": "docs/post-authentication/user-management/account-deduplication.mdx", + "route": "/post-authentication/user-management/account-deduplication", + "publicRoute": "/docs/post-authentication/user-management/account-deduplication" + }, + { + "file": "docs/post-authentication/user-management/allow-users-to-update-their-data.mdx", + "route": "/post-authentication/user-management/allow-users-to-update-their-data", + "publicRoute": "/docs/post-authentication/user-management/allow-users-to-update-their-data" + }, + { + "file": "docs/post-authentication/user-management/common-actions.mdx", + "route": "/post-authentication/user-management/common-actions", + "publicRoute": "/docs/post-authentication/user-management/common-actions" + }, + { + "file": "docs/post-authentication/user-management/introduction.mdx", + "route": "/post-authentication/user-management/introduction", + "publicRoute": "/docs/post-authentication/user-management/introduction" + }, + { + "file": "docs/post-authentication/user-management/progressive-profiling.mdx", + "route": "/post-authentication/user-management/progressive-profiling", + "publicRoute": "/docs/post-authentication/user-management/progressive-profiling" + }, + { + "file": "docs/post-authentication/user-management/user-banning.mdx", + "route": "/post-authentication/user-management/user-banning", + "publicRoute": "/docs/post-authentication/user-management/user-banning" + }, + { + "file": "docs/post-authentication/user-management/user-metadata.mdx", + "route": "/post-authentication/user-management/user-metadata", + "publicRoute": "/docs/post-authentication/user-management/user-metadata" + }, + { + "file": "docs/post-authentication/user-management/user-profile.mdx", + "route": "/post-authentication/user-management/user-profile", + "publicRoute": "/docs/post-authentication/user-management/user-profile" + }, + { + "file": "docs/quickstart/backend-setup.mdx", + "route": "/quickstart/backend-setup", + "publicRoute": "/docs/quickstart/backend-setup" + }, + { + "file": "docs/quickstart/build-with-ai-tools.mdx", + "route": "/quickstart/build-with-ai-tools", + "publicRoute": "/docs/quickstart/build-with-ai-tools" + }, + { + "file": "docs/quickstart/example-applications.mdx", + "route": "/quickstart/example-applications", + "publicRoute": "/docs/quickstart/example-applications" + }, + { + "file": "docs/quickstart/frontend-setup.mdx", + "route": "/quickstart/frontend-setup", + "publicRoute": "/docs/quickstart/frontend-setup" + }, + { + "file": "docs/quickstart/integrations/aws-lambda/appsync-integration.mdx", + "route": "/quickstart/integrations/aws-lambda/appsync-integration", + "publicRoute": "/docs/quickstart/integrations/aws-lambda/appsync-integration" + }, + { + "file": "docs/quickstart/integrations/aws-lambda/quickstart-guide.mdx", + "route": "/quickstart/integrations/aws-lambda/quickstart-guide", + "publicRoute": "/docs/quickstart/integrations/aws-lambda/quickstart-guide" + }, + { + "file": "docs/quickstart/integrations/aws-lambda/session-verification.mdx", + "route": "/quickstart/integrations/aws-lambda/session-verification", + "publicRoute": "/docs/quickstart/integrations/aws-lambda/session-verification" + }, + { + "file": "docs/quickstart/integrations/graphql.mdx", + "route": "/quickstart/integrations/graphql", + "publicRoute": "/docs/quickstart/integrations/graphql" + }, + { + "file": "docs/quickstart/integrations/hasura.mdx", + "route": "/quickstart/integrations/hasura", + "publicRoute": "/docs/quickstart/integrations/hasura" + }, + { + "file": "docs/quickstart/integrations/nestjs.mdx", + "route": "/quickstart/integrations/nestjs", + "publicRoute": "/docs/quickstart/integrations/nestjs" + }, + { + "file": "docs/quickstart/integrations/netlify.mdx", + "route": "/quickstart/integrations/netlify", + "publicRoute": "/docs/quickstart/integrations/netlify" + }, + { + "file": "docs/quickstart/integrations/nextjs/app-directory/about.mdx", + "route": "/quickstart/integrations/nextjs/app-directory/about", + "publicRoute": "/docs/quickstart/integrations/nextjs/app-directory/about" + }, + { + "file": "docs/quickstart/integrations/nextjs/app-directory/init.mdx", + "route": "/quickstart/integrations/nextjs/app-directory/init", + "publicRoute": "/docs/quickstart/integrations/nextjs/app-directory/init" + }, + { + "file": "docs/quickstart/integrations/nextjs/app-directory/next-steps.mdx", + "route": "/quickstart/integrations/nextjs/app-directory/next-steps", + "publicRoute": "/docs/quickstart/integrations/nextjs/app-directory/next-steps" + }, + { + "file": "docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-middleware.mdx", + "route": "/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-middleware", + "publicRoute": "/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-middleware" + }, + { + "file": "docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-session-guard.mdx", + "route": "/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-session-guard", + "publicRoute": "/docs/quickstart/integrations/nextjs/app-directory/protecting-backend/session-verification-session-guard" + }, + { + "file": "docs/quickstart/integrations/nextjs/app-directory/protecting-route.mdx", + "route": "/quickstart/integrations/nextjs/app-directory/protecting-route", + "publicRoute": "/docs/quickstart/integrations/nextjs/app-directory/protecting-route" + }, + { + "file": "docs/quickstart/integrations/nextjs/app-directory/server-components-requests.mdx", + "route": "/quickstart/integrations/nextjs/app-directory/server-components-requests", + "publicRoute": "/docs/quickstart/integrations/nextjs/app-directory/server-components-requests" + }, + { + "file": "docs/quickstart/integrations/nextjs/app-directory/setting-up-backend.mdx", + "route": "/quickstart/integrations/nextjs/app-directory/setting-up-backend", + "publicRoute": "/docs/quickstart/integrations/nextjs/app-directory/setting-up-backend" + }, + { + "file": "docs/quickstart/integrations/nextjs/app-directory/setting-up-frontend.mdx", + "route": "/quickstart/integrations/nextjs/app-directory/setting-up-frontend", + "publicRoute": "/docs/quickstart/integrations/nextjs/app-directory/setting-up-frontend" + }, + { + "file": "docs/quickstart/integrations/nextjs/pages-directory/about.mdx", + "route": "/quickstart/integrations/nextjs/pages-directory/about", + "publicRoute": "/docs/quickstart/integrations/nextjs/pages-directory/about" + }, + { + "file": "docs/quickstart/integrations/nextjs/pages-directory/init.mdx", + "route": "/quickstart/integrations/nextjs/pages-directory/init", + "publicRoute": "/docs/quickstart/integrations/nextjs/pages-directory/init" + }, + { + "file": "docs/quickstart/integrations/nextjs/pages-directory/next-steps.mdx", + "route": "/quickstart/integrations/nextjs/pages-directory/next-steps", + "publicRoute": "/docs/quickstart/integrations/nextjs/pages-directory/next-steps" + }, + { + "file": "docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-api.mdx", + "route": "/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-api", + "publicRoute": "/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-api" + }, + { + "file": "docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-ssr.mdx", + "route": "/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-ssr", + "publicRoute": "/docs/quickstart/integrations/nextjs/pages-directory/protecting-backend/in-ssr" + }, + { + "file": "docs/quickstart/integrations/nextjs/pages-directory/protecting-route.mdx", + "route": "/quickstart/integrations/nextjs/pages-directory/protecting-route", + "publicRoute": "/docs/quickstart/integrations/nextjs/pages-directory/protecting-route" + }, + { + "file": "docs/quickstart/integrations/nextjs/pages-directory/setting-up-backend.mdx", + "route": "/quickstart/integrations/nextjs/pages-directory/setting-up-backend", + "publicRoute": "/docs/quickstart/integrations/nextjs/pages-directory/setting-up-backend" + }, + { + "file": "docs/quickstart/integrations/nextjs/pages-directory/setting-up-frontend.mdx", + "route": "/quickstart/integrations/nextjs/pages-directory/setting-up-frontend", + "publicRoute": "/docs/quickstart/integrations/nextjs/pages-directory/setting-up-frontend" + }, + { + "file": "docs/quickstart/integrations/overview.mdx", + "route": "/quickstart/integrations/overview", + "publicRoute": "/docs/quickstart/integrations/overview" + }, + { + "file": "docs/quickstart/integrations/supabase.mdx", + "route": "/quickstart/integrations/supabase", + "publicRoute": "/docs/quickstart/integrations/supabase" + }, + { + "file": "docs/quickstart/integrations/vercel.mdx", + "route": "/quickstart/integrations/vercel", + "publicRoute": "/docs/quickstart/integrations/vercel" + }, + { + "file": "docs/quickstart/introduction.mdx", + "route": "/quickstart/introduction", + "publicRoute": "/docs/quickstart/introduction" + }, + { + "file": "docs/quickstart/next-steps.mdx", + "route": "/quickstart/next-steps", + "publicRoute": "/docs/quickstart/next-steps" + }, + { + "file": "docs/references/index.mdx", + "route": "/references", + "publicRoute": "/docs/references" + }, + { + "file": "docs/references/backend-sdks/api-overrides.mdx", + "route": "/references/backend-sdks/api-overrides", + "publicRoute": "/docs/references/backend-sdks/api-overrides" + }, + { + "file": "docs/references/backend-sdks/backend-sdk-core-interceptor.mdx", + "route": "/references/backend-sdks/backend-sdk-core-interceptor", + "publicRoute": "/docs/references/backend-sdks/backend-sdk-core-interceptor" + }, + { + "file": "docs/references/backend-sdks/function-overrides.mdx", + "route": "/references/backend-sdks/function-overrides", + "publicRoute": "/docs/references/backend-sdks/function-overrides" + }, + { + "file": "docs/references/backend-sdks/other-frameworks.mdx", + "route": "/references/backend-sdks/other-frameworks", + "publicRoute": "/docs/references/backend-sdks/other-frameworks" + }, + { + "file": "docs/references/backend-sdks/reference.mdx", + "route": "/references/backend-sdks/reference", + "publicRoute": "/docs/references/backend-sdks/reference" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/package.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/package", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/package" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-accountlinking", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-accountlinking-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-accountlinking-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-dashboard", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-dashboard-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-dashboard-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-emailpassword", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-emailpassword-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-emailpassword-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-emailverification", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-emailverification-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-emailverification-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-jwt.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-jwt", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-jwt" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-jwt-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-jwt-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-jwt-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-multifactorauth-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-multitenancy", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-multitenancy-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-multitenancy-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-oauth2provider-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-openid.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-openid", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-openid" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-openid-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-openid-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-openid-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-passwordless", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-passwordless-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-passwordless-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-thirdparty", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-thirdparty-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-thirdparty-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-totp.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-totp", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-totp" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-totp-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-totp-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-totp-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-usermetadata", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-usermetadata-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-usermetadata-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-userroles.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-userroles", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-userroles" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-userroles-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-userroles-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-userroles-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-webauthn", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn-types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/recipe-webauthn-types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/recipe-webauthn-types" + }, + { + "file": "docs/references/backend-sdks/supertokens-nodejs/types.mdx", + "route": "/references/backend-sdks/supertokens-nodejs/types", + "publicRoute": "/docs/references/backend-sdks/supertokens-nodejs/types" + }, + { + "file": "docs/references/backend-sdks/user-context.mdx", + "route": "/references/backend-sdks/user-context", + "publicRoute": "/docs/references/backend-sdks/user-context" + }, + { + "file": "docs/references/backend-sdks/user-object.mdx", + "route": "/references/backend-sdks/user-object", + "publicRoute": "/docs/references/backend-sdks/user-object" + }, + { + "file": "docs/references/cdi/account-linking/get-accountlinking-user-link-check.mdx", + "route": "/references/cdi/account-linking/get-accountlinking-user-link-check", + "publicRoute": "/docs/references/cdi/account-linking/get-accountlinking-user-link-check" + }, + { + "file": "docs/references/cdi/account-linking/get-accountlinking-user-primary-check.mdx", + "route": "/references/cdi/account-linking/get-accountlinking-user-primary-check", + "publicRoute": "/docs/references/cdi/account-linking/get-accountlinking-user-primary-check" + }, + { + "file": "docs/references/cdi/account-linking/post-accountlinking-user-link.mdx", + "route": "/references/cdi/account-linking/post-accountlinking-user-link", + "publicRoute": "/docs/references/cdi/account-linking/post-accountlinking-user-link" + }, + { + "file": "docs/references/cdi/account-linking/post-accountlinking-user-primary.mdx", + "route": "/references/cdi/account-linking/post-accountlinking-user-primary", + "publicRoute": "/docs/references/cdi/account-linking/post-accountlinking-user-primary" + }, + { + "file": "docs/references/cdi/account-linking/post-accountlinking-user-unlink.mdx", + "route": "/references/cdi/account-linking/post-accountlinking-user-unlink", + "publicRoute": "/docs/references/cdi/account-linking/post-accountlinking-user-unlink" + }, + { + "file": "docs/references/cdi/core/delete-ee-license.mdx", + "route": "/references/cdi/core/delete-ee-license", + "publicRoute": "/docs/references/cdi/core/delete-ee-license" + }, + { + "file": "docs/references/cdi/core/delete-hello.mdx", + "route": "/references/cdi/core/delete-hello", + "publicRoute": "/docs/references/cdi/core/delete-hello" + }, + { + "file": "docs/references/cdi/core/get-apiversion.mdx", + "route": "/references/cdi/core/get-apiversion", + "publicRoute": "/docs/references/cdi/core/get-apiversion" + }, + { + "file": "docs/references/cdi/core/get-config.mdx", + "route": "/references/cdi/core/get-config", + "publicRoute": "/docs/references/cdi/core/get-config" + }, + { + "file": "docs/references/cdi/core/get-ee-featureflag.mdx", + "route": "/references/cdi/core/get-ee-featureflag", + "publicRoute": "/docs/references/cdi/core/get-ee-featureflag" + }, + { + "file": "docs/references/cdi/core/get-ee-license.mdx", + "route": "/references/cdi/core/get-ee-license", + "publicRoute": "/docs/references/cdi/core/get-ee-license" + }, + { + "file": "docs/references/cdi/core/get-hello.mdx", + "route": "/references/cdi/core/get-hello", + "publicRoute": "/docs/references/cdi/core/get-hello" + }, + { + "file": "docs/references/cdi/core/get-requests-stats.mdx", + "route": "/references/cdi/core/get-requests-stats", + "publicRoute": "/docs/references/cdi/core/get-requests-stats" + }, + { + "file": "docs/references/cdi/core/get-root.mdx", + "route": "/references/cdi/core/get-root", + "publicRoute": "/docs/references/cdi/core/get-root" + }, + { + "file": "docs/references/cdi/core/get-telemetry.mdx", + "route": "/references/cdi/core/get-telemetry", + "publicRoute": "/docs/references/cdi/core/get-telemetry" + }, + { + "file": "docs/references/cdi/core/get-user-id.mdx", + "route": "/references/cdi/core/get-user-id", + "publicRoute": "/docs/references/cdi/core/get-user-id" + }, + { + "file": "docs/references/cdi/core/get-user-search-tags.mdx", + "route": "/references/cdi/core/get-user-search-tags", + "publicRoute": "/docs/references/cdi/core/get-user-search-tags" + }, + { + "file": "docs/references/cdi/core/get-userid-map.mdx", + "route": "/references/cdi/core/get-userid-map", + "publicRoute": "/docs/references/cdi/core/get-userid-map" + }, + { + "file": "docs/references/cdi/core/get-users.mdx", + "route": "/references/cdi/core/get-users", + "publicRoute": "/docs/references/cdi/core/get-users" + }, + { + "file": "docs/references/cdi/core/get-users-by-accountinfo.mdx", + "route": "/references/cdi/core/get-users-by-accountinfo", + "publicRoute": "/docs/references/cdi/core/get-users-by-accountinfo" + }, + { + "file": "docs/references/cdi/core/get-users-count.mdx", + "route": "/references/cdi/core/get-users-count", + "publicRoute": "/docs/references/cdi/core/get-users-count" + }, + { + "file": "docs/references/cdi/core/get-users-count-active.mdx", + "route": "/references/cdi/core/get-users-count-active", + "publicRoute": "/docs/references/cdi/core/get-users-count-active" + }, + { + "file": "docs/references/cdi/core/post-hello.mdx", + "route": "/references/cdi/core/post-hello", + "publicRoute": "/docs/references/cdi/core/post-hello" + }, + { + "file": "docs/references/cdi/core/post-user-remove.mdx", + "route": "/references/cdi/core/post-user-remove", + "publicRoute": "/docs/references/cdi/core/post-user-remove" + }, + { + "file": "docs/references/cdi/core/post-userid-map.mdx", + "route": "/references/cdi/core/post-userid-map", + "publicRoute": "/docs/references/cdi/core/post-userid-map" + }, + { + "file": "docs/references/cdi/core/post-userid-map-remove.mdx", + "route": "/references/cdi/core/post-userid-map-remove", + "publicRoute": "/docs/references/cdi/core/post-userid-map-remove" + }, + { + "file": "docs/references/cdi/core/put-ee-license.mdx", + "route": "/references/cdi/core/put-ee-license", + "publicRoute": "/docs/references/cdi/core/put-ee-license" + }, + { + "file": "docs/references/cdi/core/put-hello.mdx", + "route": "/references/cdi/core/put-hello", + "publicRoute": "/docs/references/cdi/core/put-hello" + }, + { + "file": "docs/references/cdi/core/put-userid-external-user-id-info.mdx", + "route": "/references/cdi/core/put-userid-external-user-id-info", + "publicRoute": "/docs/references/cdi/core/put-userid-external-user-id-info" + }, + { + "file": "docs/references/cdi/dashboard/delete-dashboard-session.mdx", + "route": "/references/cdi/dashboard/delete-dashboard-session", + "publicRoute": "/docs/references/cdi/dashboard/delete-dashboard-session" + }, + { + "file": "docs/references/cdi/dashboard/delete-dashboard-user.mdx", + "route": "/references/cdi/dashboard/delete-dashboard-user", + "publicRoute": "/docs/references/cdi/dashboard/delete-dashboard-user" + }, + { + "file": "docs/references/cdi/dashboard/get-dashboard-tenant-core-config.mdx", + "route": "/references/cdi/dashboard/get-dashboard-tenant-core-config", + "publicRoute": "/docs/references/cdi/dashboard/get-dashboard-tenant-core-config" + }, + { + "file": "docs/references/cdi/dashboard/get-dashboard-user-sessions.mdx", + "route": "/references/cdi/dashboard/get-dashboard-user-sessions", + "publicRoute": "/docs/references/cdi/dashboard/get-dashboard-user-sessions" + }, + { + "file": "docs/references/cdi/dashboard/get-dashboard-users.mdx", + "route": "/references/cdi/dashboard/get-dashboard-users", + "publicRoute": "/docs/references/cdi/dashboard/get-dashboard-users" + }, + { + "file": "docs/references/cdi/dashboard/post-dashboard-session-verify.mdx", + "route": "/references/cdi/dashboard/post-dashboard-session-verify", + "publicRoute": "/docs/references/cdi/dashboard/post-dashboard-session-verify" + }, + { + "file": "docs/references/cdi/dashboard/post-dashboard-signin.mdx", + "route": "/references/cdi/dashboard/post-dashboard-signin", + "publicRoute": "/docs/references/cdi/dashboard/post-dashboard-signin" + }, + { + "file": "docs/references/cdi/dashboard/post-dashboard-user.mdx", + "route": "/references/cdi/dashboard/post-dashboard-user", + "publicRoute": "/docs/references/cdi/dashboard/post-dashboard-user" + }, + { + "file": "docs/references/cdi/dashboard/put-dashboard-user.mdx", + "route": "/references/cdi/dashboard/put-dashboard-user", + "publicRoute": "/docs/references/cdi/dashboard/put-dashboard-user" + }, + { + "file": "docs/references/cdi/email-password/get-user.mdx", + "route": "/references/cdi/email-password/get-user", + "publicRoute": "/docs/references/cdi/email-password/get-user" + }, + { + "file": "docs/references/cdi/email-password/post-signin.mdx", + "route": "/references/cdi/email-password/post-signin", + "publicRoute": "/docs/references/cdi/email-password/post-signin" + }, + { + "file": "docs/references/cdi/email-password/post-signup.mdx", + "route": "/references/cdi/email-password/post-signup", + "publicRoute": "/docs/references/cdi/email-password/post-signup" + }, + { + "file": "docs/references/cdi/email-password/post-user-password-reset.mdx", + "route": "/references/cdi/email-password/post-user-password-reset", + "publicRoute": "/docs/references/cdi/email-password/post-user-password-reset" + }, + { + "file": "docs/references/cdi/email-password/post-user-password-reset-token.mdx", + "route": "/references/cdi/email-password/post-user-password-reset-token", + "publicRoute": "/docs/references/cdi/email-password/post-user-password-reset-token" + }, + { + "file": "docs/references/cdi/email-password/post-user-password-reset-token-consume.mdx", + "route": "/references/cdi/email-password/post-user-password-reset-token-consume", + "publicRoute": "/docs/references/cdi/email-password/post-user-password-reset-token-consume" + }, + { + "file": "docs/references/cdi/email-password/post-user-passwordhash-import.mdx", + "route": "/references/cdi/email-password/post-user-passwordhash-import", + "publicRoute": "/docs/references/cdi/email-password/post-user-passwordhash-import" + }, + { + "file": "docs/references/cdi/email-password/put-user.mdx", + "route": "/references/cdi/email-password/put-user", + "publicRoute": "/docs/references/cdi/email-password/put-user" + }, + { + "file": "docs/references/cdi/email-verification/get-user-email-verify.mdx", + "route": "/references/cdi/email-verification/get-user-email-verify", + "publicRoute": "/docs/references/cdi/email-verification/get-user-email-verify" + }, + { + "file": "docs/references/cdi/email-verification/post-user-email-verify.mdx", + "route": "/references/cdi/email-verification/post-user-email-verify", + "publicRoute": "/docs/references/cdi/email-verification/post-user-email-verify" + }, + { + "file": "docs/references/cdi/email-verification/post-user-email-verify-remove.mdx", + "route": "/references/cdi/email-verification/post-user-email-verify-remove", + "publicRoute": "/docs/references/cdi/email-verification/post-user-email-verify-remove" + }, + { + "file": "docs/references/cdi/email-verification/post-user-email-verify-token.mdx", + "route": "/references/cdi/email-verification/post-user-email-verify-token", + "publicRoute": "/docs/references/cdi/email-verification/post-user-email-verify-token" + }, + { + "file": "docs/references/cdi/email-verification/post-user-email-verify-token-remove.mdx", + "route": "/references/cdi/email-verification/post-user-email-verify-token-remove", + "publicRoute": "/docs/references/cdi/email-verification/post-user-email-verify-token-remove" + }, + { + "file": "docs/references/cdi/import/delete-bulk-import-users.mdx", + "route": "/references/cdi/import/delete-bulk-import-users", + "publicRoute": "/docs/references/cdi/import/delete-bulk-import-users" + }, + { + "file": "docs/references/cdi/import/get-bulk-import-users.mdx", + "route": "/references/cdi/import/get-bulk-import-users", + "publicRoute": "/docs/references/cdi/import/get-bulk-import-users" + }, + { + "file": "docs/references/cdi/import/get-bulk-import-users-count.mdx", + "route": "/references/cdi/import/get-bulk-import-users-count", + "publicRoute": "/docs/references/cdi/import/get-bulk-import-users-count" + }, + { + "file": "docs/references/cdi/import/post-bulk-import-import.mdx", + "route": "/references/cdi/import/post-bulk-import-import", + "publicRoute": "/docs/references/cdi/import/post-bulk-import-import" + }, + { + "file": "docs/references/cdi/import/post-bulk-import-users.mdx", + "route": "/references/cdi/import/post-bulk-import-users", + "publicRoute": "/docs/references/cdi/import/post-bulk-import-users" + }, + { + "file": "docs/references/cdi/introduction.mdx", + "route": "/references/cdi/introduction", + "publicRoute": "/docs/references/cdi/introduction" + }, + { + "file": "docs/references/cdi/mfa/get-totp-device-list.mdx", + "route": "/references/cdi/mfa/get-totp-device-list", + "publicRoute": "/docs/references/cdi/mfa/get-totp-device-list" + }, + { + "file": "docs/references/cdi/mfa/post-totp-device.mdx", + "route": "/references/cdi/mfa/post-totp-device", + "publicRoute": "/docs/references/cdi/mfa/post-totp-device" + }, + { + "file": "docs/references/cdi/mfa/post-totp-device-import.mdx", + "route": "/references/cdi/mfa/post-totp-device-import", + "publicRoute": "/docs/references/cdi/mfa/post-totp-device-import" + }, + { + "file": "docs/references/cdi/mfa/post-totp-device-remove.mdx", + "route": "/references/cdi/mfa/post-totp-device-remove", + "publicRoute": "/docs/references/cdi/mfa/post-totp-device-remove" + }, + { + "file": "docs/references/cdi/mfa/post-totp-device-verify.mdx", + "route": "/references/cdi/mfa/post-totp-device-verify", + "publicRoute": "/docs/references/cdi/mfa/post-totp-device-verify" + }, + { + "file": "docs/references/cdi/mfa/post-totp-verify.mdx", + "route": "/references/cdi/mfa/post-totp-verify", + "publicRoute": "/docs/references/cdi/mfa/post-totp-verify" + }, + { + "file": "docs/references/cdi/mfa/put-totp-device.mdx", + "route": "/references/cdi/mfa/put-totp-device", + "publicRoute": "/docs/references/cdi/mfa/put-totp-device" + }, + { + "file": "docs/references/cdi/multitenancy/get-multitenancy-app-list.mdx", + "route": "/references/cdi/multitenancy/get-multitenancy-app-list", + "publicRoute": "/docs/references/cdi/multitenancy/get-multitenancy-app-list" + }, + { + "file": "docs/references/cdi/multitenancy/get-multitenancy-app-list-v2.mdx", + "route": "/references/cdi/multitenancy/get-multitenancy-app-list-v2", + "publicRoute": "/docs/references/cdi/multitenancy/get-multitenancy-app-list-v2" + }, + { + "file": "docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list.mdx", + "route": "/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list", + "publicRoute": "/docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list" + }, + { + "file": "docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list-v2.mdx", + "route": "/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list-v2", + "publicRoute": "/docs/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list-v2" + }, + { + "file": "docs/references/cdi/multitenancy/get-multitenancy-tenant.mdx", + "route": "/references/cdi/multitenancy/get-multitenancy-tenant", + "publicRoute": "/docs/references/cdi/multitenancy/get-multitenancy-tenant" + }, + { + "file": "docs/references/cdi/multitenancy/get-multitenancy-tenant-list.mdx", + "route": "/references/cdi/multitenancy/get-multitenancy-tenant-list", + "publicRoute": "/docs/references/cdi/multitenancy/get-multitenancy-tenant-list" + }, + { + "file": "docs/references/cdi/multitenancy/get-multitenancy-tenant-list-v2.mdx", + "route": "/references/cdi/multitenancy/get-multitenancy-tenant-list-v2", + "publicRoute": "/docs/references/cdi/multitenancy/get-multitenancy-tenant-list-v2" + }, + { + "file": "docs/references/cdi/multitenancy/get-multitenancy-tenant-v2.mdx", + "route": "/references/cdi/multitenancy/get-multitenancy-tenant-v2", + "publicRoute": "/docs/references/cdi/multitenancy/get-multitenancy-tenant-v2" + }, + { + "file": "docs/references/cdi/multitenancy/post-multitenancy-app-remove.mdx", + "route": "/references/cdi/multitenancy/post-multitenancy-app-remove", + "publicRoute": "/docs/references/cdi/multitenancy/post-multitenancy-app-remove" + }, + { + "file": "docs/references/cdi/multitenancy/post-multitenancy-config-thirdparty-remove.mdx", + "route": "/references/cdi/multitenancy/post-multitenancy-config-thirdparty-remove", + "publicRoute": "/docs/references/cdi/multitenancy/post-multitenancy-config-thirdparty-remove" + }, + { + "file": "docs/references/cdi/multitenancy/post-multitenancy-connectionuridomain-remove.mdx", + "route": "/references/cdi/multitenancy/post-multitenancy-connectionuridomain-remove", + "publicRoute": "/docs/references/cdi/multitenancy/post-multitenancy-connectionuridomain-remove" + }, + { + "file": "docs/references/cdi/multitenancy/post-multitenancy-tenant-remove.mdx", + "route": "/references/cdi/multitenancy/post-multitenancy-tenant-remove", + "publicRoute": "/docs/references/cdi/multitenancy/post-multitenancy-tenant-remove" + }, + { + "file": "docs/references/cdi/multitenancy/post-multitenancy-tenant-user.mdx", + "route": "/references/cdi/multitenancy/post-multitenancy-tenant-user", + "publicRoute": "/docs/references/cdi/multitenancy/post-multitenancy-tenant-user" + }, + { + "file": "docs/references/cdi/multitenancy/post-multitenancy-tenant-user-remove.mdx", + "route": "/references/cdi/multitenancy/post-multitenancy-tenant-user-remove", + "publicRoute": "/docs/references/cdi/multitenancy/post-multitenancy-tenant-user-remove" + }, + { + "file": "docs/references/cdi/multitenancy/put-multitenancy-app.mdx", + "route": "/references/cdi/multitenancy/put-multitenancy-app", + "publicRoute": "/docs/references/cdi/multitenancy/put-multitenancy-app" + }, + { + "file": "docs/references/cdi/multitenancy/put-multitenancy-app-v2.mdx", + "route": "/references/cdi/multitenancy/put-multitenancy-app-v2", + "publicRoute": "/docs/references/cdi/multitenancy/put-multitenancy-app-v2" + }, + { + "file": "docs/references/cdi/multitenancy/put-multitenancy-config-thirdparty.mdx", + "route": "/references/cdi/multitenancy/put-multitenancy-config-thirdparty", + "publicRoute": "/docs/references/cdi/multitenancy/put-multitenancy-config-thirdparty" + }, + { + "file": "docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain.mdx", + "route": "/references/cdi/multitenancy/put-multitenancy-connectionuridomain", + "publicRoute": "/docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain" + }, + { + "file": "docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain-v2.mdx", + "route": "/references/cdi/multitenancy/put-multitenancy-connectionuridomain-v2", + "publicRoute": "/docs/references/cdi/multitenancy/put-multitenancy-connectionuridomain-v2" + }, + { + "file": "docs/references/cdi/multitenancy/put-multitenancy-tenant.mdx", + "route": "/references/cdi/multitenancy/put-multitenancy-tenant", + "publicRoute": "/docs/references/cdi/multitenancy/put-multitenancy-tenant" + }, + { + "file": "docs/references/cdi/multitenancy/put-multitenancy-tenant-v2.mdx", + "route": "/references/cdi/multitenancy/put-multitenancy-tenant-v2", + "publicRoute": "/docs/references/cdi/multitenancy/put-multitenancy-tenant-v2" + }, + { + "file": "docs/references/cdi/oauth/get-jwks.mdx", + "route": "/references/cdi/oauth/get-jwks", + "publicRoute": "/docs/references/cdi/oauth/get-jwks" + }, + { + "file": "docs/references/cdi/oauth/get-oauth2-auth.mdx", + "route": "/references/cdi/oauth/get-oauth2-auth", + "publicRoute": "/docs/references/cdi/oauth/get-oauth2-auth" + }, + { + "file": "docs/references/cdi/oauth/get-oauth2-client.mdx", + "route": "/references/cdi/oauth/get-oauth2-client", + "publicRoute": "/docs/references/cdi/oauth/get-oauth2-client" + }, + { + "file": "docs/references/cdi/oauth/get-oauth2-clients.mdx", + "route": "/references/cdi/oauth/get-oauth2-clients", + "publicRoute": "/docs/references/cdi/oauth/get-oauth2-clients" + }, + { + "file": "docs/references/cdi/oauth/get-oauth2-consent-request.mdx", + "route": "/references/cdi/oauth/get-oauth2-consent-request", + "publicRoute": "/docs/references/cdi/oauth/get-oauth2-consent-request" + }, + { + "file": "docs/references/cdi/oauth/get-oauth2-login-request.mdx", + "route": "/references/cdi/oauth/get-oauth2-login-request", + "publicRoute": "/docs/references/cdi/oauth/get-oauth2-login-request" + }, + { + "file": "docs/references/cdi/oauth/get-oauth2-sessions-logout.mdx", + "route": "/references/cdi/oauth/get-oauth2-sessions-logout", + "publicRoute": "/docs/references/cdi/oauth/get-oauth2-sessions-logout" + }, + { + "file": "docs/references/cdi/oauth/get-oauth2-token.mdx", + "route": "/references/cdi/oauth/get-oauth2-token", + "publicRoute": "/docs/references/cdi/oauth/get-oauth2-token" + }, + { + "file": "docs/references/cdi/oauth/get-well-known-jwks.mdx", + "route": "/references/cdi/oauth/get-well-known-jwks", + "publicRoute": "/docs/references/cdi/oauth/get-well-known-jwks" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-client.mdx", + "route": "/references/cdi/oauth/post-oauth2-client", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-client" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-client-remove.mdx", + "route": "/references/cdi/oauth/post-oauth2-client-remove", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-client-remove" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-consent-request-accept.mdx", + "route": "/references/cdi/oauth/post-oauth2-consent-request-accept", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-consent-request-accept" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-consent-request-reject.mdx", + "route": "/references/cdi/oauth/post-oauth2-consent-request-reject", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-consent-request-reject" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-login-request-accept.mdx", + "route": "/references/cdi/oauth/post-oauth2-login-request-accept", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-login-request-accept" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-login-request-reject.mdx", + "route": "/references/cdi/oauth/post-oauth2-login-request-reject", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-login-request-reject" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-logout-request-accept.mdx", + "route": "/references/cdi/oauth/post-oauth2-logout-request-accept", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-logout-request-accept" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-logout-request-reject.mdx", + "route": "/references/cdi/oauth/post-oauth2-logout-request-reject", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-logout-request-reject" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-session-revoke.mdx", + "route": "/references/cdi/oauth/post-oauth2-session-revoke", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-session-revoke" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-token-introspect.mdx", + "route": "/references/cdi/oauth/post-oauth2-token-introspect", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-token-introspect" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-token-revoke.mdx", + "route": "/references/cdi/oauth/post-oauth2-token-revoke", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-token-revoke" + }, + { + "file": "docs/references/cdi/oauth/post-oauth2-tokens-revoke.mdx", + "route": "/references/cdi/oauth/post-oauth2-tokens-revoke", + "publicRoute": "/docs/references/cdi/oauth/post-oauth2-tokens-revoke" + }, + { + "file": "docs/references/cdi/oauth/put-oauth2-client.mdx", + "route": "/references/cdi/oauth/put-oauth2-client", + "publicRoute": "/docs/references/cdi/oauth/put-oauth2-client" + }, + { + "file": "docs/references/cdi/passwordless/get-signinup-codes.mdx", + "route": "/references/cdi/passwordless/get-signinup-codes", + "publicRoute": "/docs/references/cdi/passwordless/get-signinup-codes" + }, + { + "file": "docs/references/cdi/passwordless/get-user.mdx", + "route": "/references/cdi/passwordless/get-user", + "publicRoute": "/docs/references/cdi/passwordless/get-user" + }, + { + "file": "docs/references/cdi/passwordless/post-signinup-code.mdx", + "route": "/references/cdi/passwordless/post-signinup-code", + "publicRoute": "/docs/references/cdi/passwordless/post-signinup-code" + }, + { + "file": "docs/references/cdi/passwordless/post-signinup-code-check.mdx", + "route": "/references/cdi/passwordless/post-signinup-code-check", + "publicRoute": "/docs/references/cdi/passwordless/post-signinup-code-check" + }, + { + "file": "docs/references/cdi/passwordless/post-signinup-code-consume.mdx", + "route": "/references/cdi/passwordless/post-signinup-code-consume", + "publicRoute": "/docs/references/cdi/passwordless/post-signinup-code-consume" + }, + { + "file": "docs/references/cdi/passwordless/post-signinup-code-remove.mdx", + "route": "/references/cdi/passwordless/post-signinup-code-remove", + "publicRoute": "/docs/references/cdi/passwordless/post-signinup-code-remove" + }, + { + "file": "docs/references/cdi/passwordless/post-signinup-codes-remove.mdx", + "route": "/references/cdi/passwordless/post-signinup-codes-remove", + "publicRoute": "/docs/references/cdi/passwordless/post-signinup-codes-remove" + }, + { + "file": "docs/references/cdi/passwordless/put-user.mdx", + "route": "/references/cdi/passwordless/put-user", + "publicRoute": "/docs/references/cdi/passwordless/put-user" + }, + { + "file": "docs/references/cdi/session/get-jwt-data.mdx", + "route": "/references/cdi/session/get-jwt-data", + "publicRoute": "/docs/references/cdi/session/get-jwt-data" + }, + { + "file": "docs/references/cdi/session/get-session.mdx", + "route": "/references/cdi/session/get-session", + "publicRoute": "/docs/references/cdi/session/get-session" + }, + { + "file": "docs/references/cdi/session/get-session-data.mdx", + "route": "/references/cdi/session/get-session-data", + "publicRoute": "/docs/references/cdi/session/get-session-data" + }, + { + "file": "docs/references/cdi/session/get-session-user.mdx", + "route": "/references/cdi/session/get-session-user", + "publicRoute": "/docs/references/cdi/session/get-session-user" + }, + { + "file": "docs/references/cdi/session/post-jwt.mdx", + "route": "/references/cdi/session/post-jwt", + "publicRoute": "/docs/references/cdi/session/post-jwt" + }, + { + "file": "docs/references/cdi/session/post-session.mdx", + "route": "/references/cdi/session/post-session", + "publicRoute": "/docs/references/cdi/session/post-session" + }, + { + "file": "docs/references/cdi/session/post-session-refresh.mdx", + "route": "/references/cdi/session/post-session-refresh", + "publicRoute": "/docs/references/cdi/session/post-session-refresh" + }, + { + "file": "docs/references/cdi/session/post-session-regenerate.mdx", + "route": "/references/cdi/session/post-session-regenerate", + "publicRoute": "/docs/references/cdi/session/post-session-regenerate" + }, + { + "file": "docs/references/cdi/session/post-session-remove.mdx", + "route": "/references/cdi/session/post-session-remove", + "publicRoute": "/docs/references/cdi/session/post-session-remove" + }, + { + "file": "docs/references/cdi/session/post-session-verify.mdx", + "route": "/references/cdi/session/post-session-verify", + "publicRoute": "/docs/references/cdi/session/post-session-verify" + }, + { + "file": "docs/references/cdi/session/put-jwt-data.mdx", + "route": "/references/cdi/session/put-jwt-data", + "publicRoute": "/docs/references/cdi/session/put-jwt-data" + }, + { + "file": "docs/references/cdi/session/put-session-data.mdx", + "route": "/references/cdi/session/put-session-data", + "publicRoute": "/docs/references/cdi/session/put-session-data" + }, + { + "file": "docs/references/cdi/thirdparty/get-user.mdx", + "route": "/references/cdi/thirdparty/get-user", + "publicRoute": "/docs/references/cdi/thirdparty/get-user" + }, + { + "file": "docs/references/cdi/thirdparty/get-users-by-email.mdx", + "route": "/references/cdi/thirdparty/get-users-by-email", + "publicRoute": "/docs/references/cdi/thirdparty/get-users-by-email" + }, + { + "file": "docs/references/cdi/thirdparty/post-signinup.mdx", + "route": "/references/cdi/thirdparty/post-signinup", + "publicRoute": "/docs/references/cdi/thirdparty/post-signinup" + }, + { + "file": "docs/references/cdi/user-metadata/get-user-metadata.mdx", + "route": "/references/cdi/user-metadata/get-user-metadata", + "publicRoute": "/docs/references/cdi/user-metadata/get-user-metadata" + }, + { + "file": "docs/references/cdi/user-metadata/post-user-metadata-remove.mdx", + "route": "/references/cdi/user-metadata/post-user-metadata-remove", + "publicRoute": "/docs/references/cdi/user-metadata/post-user-metadata-remove" + }, + { + "file": "docs/references/cdi/user-metadata/put-user-metadata.mdx", + "route": "/references/cdi/user-metadata/put-user-metadata", + "publicRoute": "/docs/references/cdi/user-metadata/put-user-metadata" + }, + { + "file": "docs/references/cdi/user-roles/get-permission-roles.mdx", + "route": "/references/cdi/user-roles/get-permission-roles", + "publicRoute": "/docs/references/cdi/user-roles/get-permission-roles" + }, + { + "file": "docs/references/cdi/user-roles/get-role-permissions.mdx", + "route": "/references/cdi/user-roles/get-role-permissions", + "publicRoute": "/docs/references/cdi/user-roles/get-role-permissions" + }, + { + "file": "docs/references/cdi/user-roles/get-role-users.mdx", + "route": "/references/cdi/user-roles/get-role-users", + "publicRoute": "/docs/references/cdi/user-roles/get-role-users" + }, + { + "file": "docs/references/cdi/user-roles/get-roles.mdx", + "route": "/references/cdi/user-roles/get-roles", + "publicRoute": "/docs/references/cdi/user-roles/get-roles" + }, + { + "file": "docs/references/cdi/user-roles/get-user-roles.mdx", + "route": "/references/cdi/user-roles/get-user-roles", + "publicRoute": "/docs/references/cdi/user-roles/get-user-roles" + }, + { + "file": "docs/references/cdi/user-roles/post-role-permissions-remove.mdx", + "route": "/references/cdi/user-roles/post-role-permissions-remove", + "publicRoute": "/docs/references/cdi/user-roles/post-role-permissions-remove" + }, + { + "file": "docs/references/cdi/user-roles/post-role-remove.mdx", + "route": "/references/cdi/user-roles/post-role-remove", + "publicRoute": "/docs/references/cdi/user-roles/post-role-remove" + }, + { + "file": "docs/references/cdi/user-roles/post-user-role-remove.mdx", + "route": "/references/cdi/user-roles/post-user-role-remove", + "publicRoute": "/docs/references/cdi/user-roles/post-user-role-remove" + }, + { + "file": "docs/references/cdi/user-roles/put-role.mdx", + "route": "/references/cdi/user-roles/put-role", + "publicRoute": "/docs/references/cdi/user-roles/put-role" + }, + { + "file": "docs/references/cdi/user-roles/put-user-role.mdx", + "route": "/references/cdi/user-roles/put-user-role", + "publicRoute": "/docs/references/cdi/user-roles/put-user-role" + }, + { + "file": "docs/references/cdi/webauthn/delete-webauthn-credential.mdx", + "route": "/references/cdi/webauthn/delete-webauthn-credential", + "publicRoute": "/docs/references/cdi/webauthn/delete-webauthn-credential" + }, + { + "file": "docs/references/cdi/webauthn/delete-webauthn-options.mdx", + "route": "/references/cdi/webauthn/delete-webauthn-options", + "publicRoute": "/docs/references/cdi/webauthn/delete-webauthn-options" + }, + { + "file": "docs/references/cdi/webauthn/get-webauthn-credential.mdx", + "route": "/references/cdi/webauthn/get-webauthn-credential", + "publicRoute": "/docs/references/cdi/webauthn/get-webauthn-credential" + }, + { + "file": "docs/references/cdi/webauthn/get-webauthn-credentials.mdx", + "route": "/references/cdi/webauthn/get-webauthn-credentials", + "publicRoute": "/docs/references/cdi/webauthn/get-webauthn-credentials" + }, + { + "file": "docs/references/cdi/webauthn/get-webauthn-options.mdx", + "route": "/references/cdi/webauthn/get-webauthn-options", + "publicRoute": "/docs/references/cdi/webauthn/get-webauthn-options" + }, + { + "file": "docs/references/cdi/webauthn/post-webauthn-recover.mdx", + "route": "/references/cdi/webauthn/post-webauthn-recover", + "publicRoute": "/docs/references/cdi/webauthn/post-webauthn-recover" + }, + { + "file": "docs/references/cdi/webauthn/post-webauthn-register.mdx", + "route": "/references/cdi/webauthn/post-webauthn-register", + "publicRoute": "/docs/references/cdi/webauthn/post-webauthn-register" + }, + { + "file": "docs/references/cdi/webauthn/post-webauthn-registration-options.mdx", + "route": "/references/cdi/webauthn/post-webauthn-registration-options", + "publicRoute": "/docs/references/cdi/webauthn/post-webauthn-registration-options" + }, + { + "file": "docs/references/cdi/webauthn/post-webauthn-signin.mdx", + "route": "/references/cdi/webauthn/post-webauthn-signin", + "publicRoute": "/docs/references/cdi/webauthn/post-webauthn-signin" + }, + { + "file": "docs/references/cdi/webauthn/post-webauthn-signin-options.mdx", + "route": "/references/cdi/webauthn/post-webauthn-signin-options", + "publicRoute": "/docs/references/cdi/webauthn/post-webauthn-signin-options" + }, + { + "file": "docs/references/cdi/webauthn/post-webauthn-signup.mdx", + "route": "/references/cdi/webauthn/post-webauthn-signup", + "publicRoute": "/docs/references/cdi/webauthn/post-webauthn-signup" + }, + { + "file": "docs/references/cdi/webauthn/post-webauthn-token-consume.mdx", + "route": "/references/cdi/webauthn/post-webauthn-token-consume", + "publicRoute": "/docs/references/cdi/webauthn/post-webauthn-token-consume" + }, + { + "file": "docs/references/cdi/webauthn/post-webauthn-token-recovery.mdx", + "route": "/references/cdi/webauthn/post-webauthn-token-recovery", + "publicRoute": "/docs/references/cdi/webauthn/post-webauthn-token-recovery" + }, + { + "file": "docs/references/cdi/webauthn/put-webauthn-email.mdx", + "route": "/references/cdi/webauthn/put-webauthn-email", + "publicRoute": "/docs/references/cdi/webauthn/put-webauthn-email" + }, + { + "file": "docs/references/compatibility-table.mdx", + "route": "/references/compatibility-table", + "publicRoute": "/docs/references/compatibility-table" + }, + { + "file": "docs/references/fdi/email-password/get-emailpassword-email-exists.mdx", + "route": "/references/fdi/email-password/get-emailpassword-email-exists", + "publicRoute": "/docs/references/fdi/email-password/get-emailpassword-email-exists" + }, + { + "file": "docs/references/fdi/email-password/get-signup-email-exists.mdx", + "route": "/references/fdi/email-password/get-signup-email-exists", + "publicRoute": "/docs/references/fdi/email-password/get-signup-email-exists" + }, + { + "file": "docs/references/fdi/email-password/post-signin.mdx", + "route": "/references/fdi/email-password/post-signin", + "publicRoute": "/docs/references/fdi/email-password/post-signin" + }, + { + "file": "docs/references/fdi/email-password/post-signup.mdx", + "route": "/references/fdi/email-password/post-signup", + "publicRoute": "/docs/references/fdi/email-password/post-signup" + }, + { + "file": "docs/references/fdi/email-password/post-user-password-reset.mdx", + "route": "/references/fdi/email-password/post-user-password-reset", + "publicRoute": "/docs/references/fdi/email-password/post-user-password-reset" + }, + { + "file": "docs/references/fdi/email-password/post-user-password-reset-token.mdx", + "route": "/references/fdi/email-password/post-user-password-reset-token", + "publicRoute": "/docs/references/fdi/email-password/post-user-password-reset-token" + }, + { + "file": "docs/references/fdi/email-verification/get-user-email-verify.mdx", + "route": "/references/fdi/email-verification/get-user-email-verify", + "publicRoute": "/docs/references/fdi/email-verification/get-user-email-verify" + }, + { + "file": "docs/references/fdi/email-verification/post-user-email-verify.mdx", + "route": "/references/fdi/email-verification/post-user-email-verify", + "publicRoute": "/docs/references/fdi/email-verification/post-user-email-verify" + }, + { + "file": "docs/references/fdi/email-verification/post-user-email-verify-token.mdx", + "route": "/references/fdi/email-verification/post-user-email-verify-token", + "publicRoute": "/docs/references/fdi/email-verification/post-user-email-verify-token" + }, + { + "file": "docs/references/fdi/get-example.mdx", + "route": "/references/fdi/get-example", + "publicRoute": "/docs/references/fdi/get-example" + }, + { + "file": "docs/references/fdi/get-jwt-jwks-json.mdx", + "route": "/references/fdi/get-jwt-jwks-json", + "publicRoute": "/docs/references/fdi/get-jwt-jwks-json" + }, + { + "file": "docs/references/fdi/get-loginmethods.mdx", + "route": "/references/fdi/get-loginmethods", + "publicRoute": "/docs/references/fdi/get-loginmethods" + }, + { + "file": "docs/references/fdi/get-well-known-openid-configuration.mdx", + "route": "/references/fdi/get-well-known-openid-configuration", + "publicRoute": "/docs/references/fdi/get-well-known-openid-configuration" + }, + { + "file": "docs/references/fdi/introduction.mdx", + "route": "/references/fdi/introduction", + "publicRoute": "/docs/references/fdi/introduction" + }, + { + "file": "docs/references/fdi/mfa/get-totp-device-list.mdx", + "route": "/references/fdi/mfa/get-totp-device-list", + "publicRoute": "/docs/references/fdi/mfa/get-totp-device-list" + }, + { + "file": "docs/references/fdi/mfa/post-totp-device.mdx", + "route": "/references/fdi/mfa/post-totp-device", + "publicRoute": "/docs/references/fdi/mfa/post-totp-device" + }, + { + "file": "docs/references/fdi/mfa/post-totp-device-remove.mdx", + "route": "/references/fdi/mfa/post-totp-device-remove", + "publicRoute": "/docs/references/fdi/mfa/post-totp-device-remove" + }, + { + "file": "docs/references/fdi/mfa/post-totp-device-verify.mdx", + "route": "/references/fdi/mfa/post-totp-device-verify", + "publicRoute": "/docs/references/fdi/mfa/post-totp-device-verify" + }, + { + "file": "docs/references/fdi/mfa/post-totp-verify.mdx", + "route": "/references/fdi/mfa/post-totp-verify", + "publicRoute": "/docs/references/fdi/mfa/post-totp-verify" + }, + { + "file": "docs/references/fdi/mfa/put-mfa-info.mdx", + "route": "/references/fdi/mfa/put-mfa-info", + "publicRoute": "/docs/references/fdi/mfa/put-mfa-info" + }, + { + "file": "docs/references/fdi/oauth/get-oauth-auth.mdx", + "route": "/references/fdi/oauth/get-oauth-auth", + "publicRoute": "/docs/references/fdi/oauth/get-oauth-auth" + }, + { + "file": "docs/references/fdi/oauth/get-oauth-end_session.mdx", + "route": "/references/fdi/oauth/get-oauth-end_session", + "publicRoute": "/docs/references/fdi/oauth/get-oauth-end_session" + }, + { + "file": "docs/references/fdi/oauth/get-oauth-login.mdx", + "route": "/references/fdi/oauth/get-oauth-login", + "publicRoute": "/docs/references/fdi/oauth/get-oauth-login" + }, + { + "file": "docs/references/fdi/oauth/get-oauth-logininfo.mdx", + "route": "/references/fdi/oauth/get-oauth-logininfo", + "publicRoute": "/docs/references/fdi/oauth/get-oauth-logininfo" + }, + { + "file": "docs/references/fdi/oauth/get-oauth-userinfo.mdx", + "route": "/references/fdi/oauth/get-oauth-userinfo", + "publicRoute": "/docs/references/fdi/oauth/get-oauth-userinfo" + }, + { + "file": "docs/references/fdi/oauth/post-oauth-end_session.mdx", + "route": "/references/fdi/oauth/post-oauth-end_session", + "publicRoute": "/docs/references/fdi/oauth/post-oauth-end_session" + }, + { + "file": "docs/references/fdi/oauth/post-oauth-introspect.mdx", + "route": "/references/fdi/oauth/post-oauth-introspect", + "publicRoute": "/docs/references/fdi/oauth/post-oauth-introspect" + }, + { + "file": "docs/references/fdi/oauth/post-oauth-logout.mdx", + "route": "/references/fdi/oauth/post-oauth-logout", + "publicRoute": "/docs/references/fdi/oauth/post-oauth-logout" + }, + { + "file": "docs/references/fdi/oauth/post-oauth-revoke.mdx", + "route": "/references/fdi/oauth/post-oauth-revoke", + "publicRoute": "/docs/references/fdi/oauth/post-oauth-revoke" + }, + { + "file": "docs/references/fdi/oauth/post-oauth-token.mdx", + "route": "/references/fdi/oauth/post-oauth-token", + "publicRoute": "/docs/references/fdi/oauth/post-oauth-token" + }, + { + "file": "docs/references/fdi/passwordless/get-passwordless-email-exists.mdx", + "route": "/references/fdi/passwordless/get-passwordless-email-exists", + "publicRoute": "/docs/references/fdi/passwordless/get-passwordless-email-exists" + }, + { + "file": "docs/references/fdi/passwordless/get-passwordless-phoneNumber-exists.mdx", + "route": "/references/fdi/passwordless/get-passwordless-phoneNumber-exists", + "publicRoute": "/docs/references/fdi/passwordless/get-passwordless-phoneNumber-exists" + }, + { + "file": "docs/references/fdi/passwordless/get-signup-email-exists.mdx", + "route": "/references/fdi/passwordless/get-signup-email-exists", + "publicRoute": "/docs/references/fdi/passwordless/get-signup-email-exists" + }, + { + "file": "docs/references/fdi/passwordless/get-signup-phoneNumber-exists.mdx", + "route": "/references/fdi/passwordless/get-signup-phoneNumber-exists", + "publicRoute": "/docs/references/fdi/passwordless/get-signup-phoneNumber-exists" + }, + { + "file": "docs/references/fdi/passwordless/post-signinup-code.mdx", + "route": "/references/fdi/passwordless/post-signinup-code", + "publicRoute": "/docs/references/fdi/passwordless/post-signinup-code" + }, + { + "file": "docs/references/fdi/passwordless/post-signinup-code-consume.mdx", + "route": "/references/fdi/passwordless/post-signinup-code-consume", + "publicRoute": "/docs/references/fdi/passwordless/post-signinup-code-consume" + }, + { + "file": "docs/references/fdi/passwordless/post-signinup-code-resend.mdx", + "route": "/references/fdi/passwordless/post-signinup-code-resend", + "publicRoute": "/docs/references/fdi/passwordless/post-signinup-code-resend" + }, + { + "file": "docs/references/fdi/session/post-session-refresh.mdx", + "route": "/references/fdi/session/post-session-refresh", + "publicRoute": "/docs/references/fdi/session/post-session-refresh" + }, + { + "file": "docs/references/fdi/session/post-signout.mdx", + "route": "/references/fdi/session/post-signout", + "publicRoute": "/docs/references/fdi/session/post-signout" + }, + { + "file": "docs/references/fdi/thirdparty/get-authorisationurl.mdx", + "route": "/references/fdi/thirdparty/get-authorisationurl", + "publicRoute": "/docs/references/fdi/thirdparty/get-authorisationurl" + }, + { + "file": "docs/references/fdi/thirdparty/post-callback-apple.mdx", + "route": "/references/fdi/thirdparty/post-callback-apple", + "publicRoute": "/docs/references/fdi/thirdparty/post-callback-apple" + }, + { + "file": "docs/references/fdi/thirdparty/post-signinup.mdx", + "route": "/references/fdi/thirdparty/post-signinup", + "publicRoute": "/docs/references/fdi/thirdparty/post-signinup" + }, + { + "file": "docs/references/fdi/webauthn/get-webauthn-email-exists.mdx", + "route": "/references/fdi/webauthn/get-webauthn-email-exists", + "publicRoute": "/docs/references/fdi/webauthn/get-webauthn-email-exists" + }, + { + "file": "docs/references/fdi/webauthn/post-webauthn-credential.mdx", + "route": "/references/fdi/webauthn/post-webauthn-credential", + "publicRoute": "/docs/references/fdi/webauthn/post-webauthn-credential" + }, + { + "file": "docs/references/fdi/webauthn/post-webauthn-recover-account.mdx", + "route": "/references/fdi/webauthn/post-webauthn-recover-account", + "publicRoute": "/docs/references/fdi/webauthn/post-webauthn-recover-account" + }, + { + "file": "docs/references/fdi/webauthn/post-webauthn-recover-account-token.mdx", + "route": "/references/fdi/webauthn/post-webauthn-recover-account-token", + "publicRoute": "/docs/references/fdi/webauthn/post-webauthn-recover-account-token" + }, + { + "file": "docs/references/fdi/webauthn/post-webauthn-register-options.mdx", + "route": "/references/fdi/webauthn/post-webauthn-register-options", + "publicRoute": "/docs/references/fdi/webauthn/post-webauthn-register-options" + }, + { + "file": "docs/references/fdi/webauthn/post-webauthn-signin.mdx", + "route": "/references/fdi/webauthn/post-webauthn-signin", + "publicRoute": "/docs/references/fdi/webauthn/post-webauthn-signin" + }, + { + "file": "docs/references/fdi/webauthn/post-webauthn-signin-options.mdx", + "route": "/references/fdi/webauthn/post-webauthn-signin-options", + "publicRoute": "/docs/references/fdi/webauthn/post-webauthn-signin-options" + }, + { + "file": "docs/references/fdi/webauthn/post-webauthn-signup.mdx", + "route": "/references/fdi/webauthn/post-webauthn-signup", + "publicRoute": "/docs/references/fdi/webauthn/post-webauthn-signup" + }, + { + "file": "docs/references/frontend-sdks/function-overrides.mdx", + "route": "/references/frontend-sdks/function-overrides", + "publicRoute": "/docs/references/frontend-sdks/function-overrides" + }, + { + "file": "docs/references/frontend-sdks/hooks.mdx", + "route": "/references/frontend-sdks/hooks", + "publicRoute": "/docs/references/frontend-sdks/hooks" + }, + { + "file": "docs/references/frontend-sdks/prebuilt-ui/changing-colours.mdx", + "route": "/references/frontend-sdks/prebuilt-ui/changing-colours", + "publicRoute": "/docs/references/frontend-sdks/prebuilt-ui/changing-colours" + }, + { + "file": "docs/references/frontend-sdks/prebuilt-ui/changing-style.mdx", + "route": "/references/frontend-sdks/prebuilt-ui/changing-style", + "publicRoute": "/docs/references/frontend-sdks/prebuilt-ui/changing-style" + }, + { + "file": "docs/references/frontend-sdks/prebuilt-ui/embed-sign-in-up-form.mdx", + "route": "/references/frontend-sdks/prebuilt-ui/embed-sign-in-up-form", + "publicRoute": "/docs/references/frontend-sdks/prebuilt-ui/embed-sign-in-up-form" + }, + { + "file": "docs/references/frontend-sdks/prebuilt-ui/override-react-components.mdx", + "route": "/references/frontend-sdks/prebuilt-ui/override-react-components", + "publicRoute": "/docs/references/frontend-sdks/prebuilt-ui/override-react-components" + }, + { + "file": "docs/references/frontend-sdks/prebuilt-ui/shadow-dom.mdx", + "route": "/references/frontend-sdks/prebuilt-ui/shadow-dom", + "publicRoute": "/docs/references/frontend-sdks/prebuilt-ui/shadow-dom" + }, + { + "file": "docs/references/frontend-sdks/prebuilt-ui/toc-privacypolicy.mdx", + "route": "/references/frontend-sdks/prebuilt-ui/toc-privacypolicy", + "publicRoute": "/docs/references/frontend-sdks/prebuilt-ui/toc-privacypolicy" + }, + { + "file": "docs/references/frontend-sdks/prebuilt-ui/translations.mdx", + "route": "/references/frontend-sdks/prebuilt-ui/translations", + "publicRoute": "/docs/references/frontend-sdks/prebuilt-ui/translations" + }, + { + "file": "docs/references/frontend-sdks/prebuilt-ui/ui-showcase.mdx", + "route": "/references/frontend-sdks/prebuilt-ui/ui-showcase", + "publicRoute": "/docs/references/frontend-sdks/prebuilt-ui/ui-showcase" + }, + { + "file": "docs/references/frontend-sdks/reference.mdx", + "route": "/references/frontend-sdks/reference", + "publicRoute": "/docs/references/frontend-sdks/reference" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/package.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/package", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/package" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword-types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailpassword-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-emailverification", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification-types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-emailverification-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-emailverification-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth-types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-multifactorauth-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy-types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-multitenancy-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider-types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-oauth2provider-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-passwordless", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless-types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-passwordless-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-passwordless-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-session.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-session", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-session" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-session-types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-session-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-session-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty-types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-thirdparty-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-totp.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-totp", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-totp" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-totp-types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-totp-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-totp-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-userroles.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-userroles", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-userroles" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-webauthn", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn-types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/recipe-webauthn-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/recipe-webauthn-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-auth-react/types.mdx", + "route": "/references/frontend-sdks/supertokens-auth-react/types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-auth-react/types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/package.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/package", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/package" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-emailpassword", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword-types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-emailpassword-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-emailpassword-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-emailverification", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification-types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-emailverification-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-emailverification-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth-types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-multifactorauth-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-multitenancy", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy-types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-multitenancy-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-multitenancy-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider-types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-oauth2provider-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-passwordless", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless-types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-passwordless-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-passwordless-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-session.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-session", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-session" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-session-types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-session-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-session-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-thirdparty", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty-types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-thirdparty-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-thirdparty-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-totp.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-totp", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-totp" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-totp-types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-totp-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-totp-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-userroles.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-userroles", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-userroles" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-webauthn", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn-types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/recipe-webauthn-types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/recipe-webauthn-types" + }, + { + "file": "docs/references/frontend-sdks/supertokens-web-js/types.mdx", + "route": "/references/frontend-sdks/supertokens-web-js/types", + "publicRoute": "/docs/references/frontend-sdks/supertokens-web-js/types" + }, + { + "file": "docs/references/how-supertokens-works.mdx", + "route": "/references/how-supertokens-works", + "publicRoute": "/docs/references/how-supertokens-works" + }, + { + "file": "docs/references/plugins/captcha-nodejs.mdx", + "route": "/references/plugins/captcha-nodejs", + "publicRoute": "/docs/references/plugins/captcha-nodejs" + }, + { + "file": "docs/references/plugins/captcha-react.mdx", + "route": "/references/plugins/captcha-react", + "publicRoute": "/docs/references/plugins/captcha-react" + }, + { + "file": "docs/references/plugins/introduction.mdx", + "route": "/references/plugins/introduction", + "publicRoute": "/docs/references/plugins/introduction" + }, + { + "file": "docs/references/plugins/opentelemetry-nodejs.mdx", + "route": "/references/plugins/opentelemetry-nodejs", + "publicRoute": "/docs/references/plugins/opentelemetry-nodejs" + }, + { + "file": "docs/references/plugins/profile-base-react.mdx", + "route": "/references/plugins/profile-base-react", + "publicRoute": "/docs/references/plugins/profile-base-react" + }, + { + "file": "docs/references/plugins/profile-details-nodejs.mdx", + "route": "/references/plugins/profile-details-nodejs", + "publicRoute": "/docs/references/plugins/profile-details-nodejs" + }, + { + "file": "docs/references/plugins/profile-details-react.mdx", + "route": "/references/plugins/profile-details-react", + "publicRoute": "/docs/references/plugins/profile-details-react" + }, + { + "file": "docs/references/plugins/profile-details-shared.mdx", + "route": "/references/plugins/profile-details-shared", + "publicRoute": "/docs/references/plugins/profile-details-shared" + }, + { + "file": "docs/references/plugins/progressive-profiling-nodejs.mdx", + "route": "/references/plugins/progressive-profiling-nodejs", + "publicRoute": "/docs/references/plugins/progressive-profiling-nodejs" + }, + { + "file": "docs/references/plugins/progressive-profiling-react.mdx", + "route": "/references/plugins/progressive-profiling-react", + "publicRoute": "/docs/references/plugins/progressive-profiling-react" + }, + { + "file": "docs/references/plugins/progressive-profiling-shared.mdx", + "route": "/references/plugins/progressive-profiling-shared", + "publicRoute": "/docs/references/plugins/progressive-profiling-shared" + }, + { + "file": "docs/references/plugins/tenant-discovery-nodejs.mdx", + "route": "/references/plugins/tenant-discovery-nodejs", + "publicRoute": "/docs/references/plugins/tenant-discovery-nodejs" + }, + { + "file": "docs/references/plugins/tenant-discovery-react.mdx", + "route": "/references/plugins/tenant-discovery-react", + "publicRoute": "/docs/references/plugins/tenant-discovery-react" + }, + { + "file": "docs/references/plugins/tenants-nodejs.mdx", + "route": "/references/plugins/tenants-nodejs", + "publicRoute": "/docs/references/plugins/tenants-nodejs" + }, + { + "file": "docs/references/plugins/tenants-react.mdx", + "route": "/references/plugins/tenants-react", + "publicRoute": "/docs/references/plugins/tenants-react" + }, + { + "file": "docs/references/plugins/user-banning-nodejs.mdx", + "route": "/references/plugins/user-banning-nodejs", + "publicRoute": "/docs/references/plugins/user-banning-nodejs" + }, + { + "file": "docs/references/plugins/user-banning-react.mdx", + "route": "/references/plugins/user-banning-react", + "publicRoute": "/docs/references/plugins/user-banning-react" + }, + { + "file": "docs/references/testing-and-debugging/api-testing.mdx", + "route": "/references/testing-and-debugging/api-testing", + "publicRoute": "/docs/references/testing-and-debugging/api-testing" + }, + { + "file": "docs/references/testing-and-debugging/common-issues.mdx", + "route": "/references/testing-and-debugging/common-issues", + "publicRoute": "/docs/references/testing-and-debugging/common-issues" + }, + { + "file": "docs/references/testing-and-debugging/how-to-troubleshoot.mdx", + "route": "/references/testing-and-debugging/how-to-troubleshoot", + "publicRoute": "/docs/references/testing-and-debugging/how-to-troubleshoot" + }, + { + "file": "docs/references/updating-supertokens.mdx", + "route": "/references/updating-supertokens", + "publicRoute": "/docs/references/updating-supertokens" + } + ], + "openapi": [ + { + "operationId": "canLinkAccounts", + "from": "/references/cdi/account-linking/get-accountlinking-user-link-check", + "to": "/references/cdi/account-linking-recipe/canlinkaccounts" + }, + { + "operationId": "canCreatePrimaryUser", + "from": "/references/cdi/account-linking/get-accountlinking-user-primary-check", + "to": "/references/cdi/account-linking-recipe/cancreateprimaryuser" + }, + { + "operationId": "linkAccounts", + "from": "/references/cdi/account-linking/post-accountlinking-user-link", + "to": "/references/cdi/account-linking-recipe/linkaccounts" + }, + { + "operationId": "createPrimaryUser", + "from": "/references/cdi/account-linking/post-accountlinking-user-primary", + "to": "/references/cdi/account-linking-recipe/createprimaryuser" + }, + { + "operationId": "unlinkAccounts", + "from": "/references/cdi/account-linking/post-accountlinking-user-unlink", + "to": "/references/cdi/account-linking-recipe/unlinkaccounts" + }, + { + "operationId": "deleteLicense", + "from": "/references/cdi/core/delete-ee-license", + "to": "/references/cdi/core/deletelicense" + }, + { + "operationId": "deleteHello", + "from": "/references/cdi/core/delete-hello", + "to": "/references/cdi/core/deletehello" + }, + { + "operationId": "getApiVersion", + "from": "/references/cdi/core/get-apiversion", + "to": "/references/cdi/core/getapiversion" + }, + { + "operationId": "getConfig", + "from": "/references/cdi/core/get-config", + "to": "/references/cdi/core/getconfig" + }, + { + "operationId": "getFeatureFlag", + "from": "/references/cdi/core/get-ee-featureflag", + "to": "/references/cdi/core/getfeatureflag" + }, + { + "operationId": "getLicense", + "from": "/references/cdi/core/get-ee-license", + "to": "/references/cdi/core/getlicense" + }, + { + "operationId": "getHello", + "from": "/references/cdi/core/get-hello", + "to": "/references/cdi/core/gethello" + }, + { + "operationId": "getRequestsStats", + "from": "/references/cdi/core/get-requests-stats", + "to": "/references/cdi/core/getrequestsstats" + }, + { + "operationId": "getHelloOnRootPath", + "from": "/references/cdi/core/get-root", + "to": "/references/cdi/core/gethelloonrootpath" + }, + { + "operationId": "getTelemetry", + "from": "/references/cdi/core/get-telemetry", + "to": "/references/cdi/core/gettelemetry" + }, + { + "operationId": "getUserId", + "from": "/references/cdi/core/get-user-id", + "to": "/references/cdi/core/getuserid" + }, + { + "operationId": "getSearchTags", + "from": "/references/cdi/core/get-user-search-tags", + "to": "/references/cdi/core/getsearchtags" + }, + { + "operationId": "userIdMappingGetMapping", + "from": "/references/cdi/core/get-userid-map", + "to": "/references/cdi/useridmapping-recipe/useridmappinggetmapping" + }, + { + "operationId": "getUsers", + "from": "/references/cdi/core/get-users", + "to": "/references/cdi/core/getusers" + }, + { + "operationId": "getUsersByAccountInfo", + "from": "/references/cdi/core/get-users-by-accountinfo", + "to": "/references/cdi/core/getusersbyaccountinfo" + }, + { + "operationId": "getUsersCount", + "from": "/references/cdi/core/get-users-count", + "to": "/references/cdi/core/getuserscount" + }, + { + "operationId": "getActiveUsersCount", + "from": "/references/cdi/core/get-users-count-active", + "to": "/references/cdi/core/getactiveuserscount" + }, + { + "operationId": "postHello", + "from": "/references/cdi/core/post-hello", + "to": "/references/cdi/core/posthello" + }, + { + "operationId": "deleteUser", + "from": "/references/cdi/core/post-user-remove", + "to": "/references/cdi/core/deleteuser" + }, + { + "operationId": "userIdMappingCreateMapping", + "from": "/references/cdi/core/post-userid-map", + "to": "/references/cdi/useridmapping-recipe/useridmappingcreatemapping" + }, + { + "operationId": "userIdMappingRemoveMapping", + "from": "/references/cdi/core/post-userid-map-remove", + "to": "/references/cdi/useridmapping-recipe/useridmappingremovemapping" + }, + { + "operationId": "setLicense", + "from": "/references/cdi/core/put-ee-license", + "to": "/references/cdi/core/setlicense" + }, + { + "operationId": "putHello", + "from": "/references/cdi/core/put-hello", + "to": "/references/cdi/core/puthello" + }, + { + "operationId": "userIdMappingUpateExternalUserIdInfo", + "from": "/references/cdi/core/put-userid-external-user-id-info", + "to": "/references/cdi/useridmapping-recipe/useridmappingupateexternaluseridinfo" + }, + { + "operationId": "RevokeDashboardUsersSession", + "from": "/references/cdi/dashboard/delete-dashboard-session", + "to": "/references/cdi/dashboard-recipe/revokedashboarduserssession" + }, + { + "operationId": "deleteDashboardUser", + "from": "/references/cdi/dashboard/delete-dashboard-user", + "to": "/references/cdi/dashboard-recipe/deletedashboarduser" + }, + { + "operationId": "tenantCoreConfigForDashboardGET", + "from": "/references/cdi/dashboard/get-dashboard-tenant-core-config", + "to": "/references/cdi/dashboard-recipe/tenantcoreconfigfordashboardget" + }, + { + "operationId": "getAllSessionsForDashboardUser", + "from": "/references/cdi/dashboard/get-dashboard-user-sessions", + "to": "/references/cdi/dashboard-recipe/getallsessionsfordashboarduser" + }, + { + "operationId": "getAllDashboardUsers", + "from": "/references/cdi/dashboard/get-dashboard-users", + "to": "/references/cdi/dashboard-recipe/getalldashboardusers" + }, + { + "operationId": "verifyDashboardUserSession", + "from": "/references/cdi/dashboard/post-dashboard-session-verify", + "to": "/references/cdi/dashboard-recipe/verifydashboardusersession" + }, + { + "operationId": "signInDashboardUser", + "from": "/references/cdi/dashboard/post-dashboard-signin", + "to": "/references/cdi/dashboard-recipe/signindashboarduser" + }, + { + "operationId": "createDashboardUser", + "from": "/references/cdi/dashboard/post-dashboard-user", + "to": "/references/cdi/dashboard-recipe/createdashboarduser" + }, + { + "operationId": "updateDashboardUser", + "from": "/references/cdi/dashboard/put-dashboard-user", + "to": "/references/cdi/dashboard-recipe/updatedashboarduser" + }, + { + "operationId": "emailPasswordGetUser", + "from": "/references/cdi/email-password/get-user", + "to": "/references/cdi/emailpassword-recipe/emailpasswordgetuser" + }, + { + "operationId": "emailPasswordSignin", + "from": "/references/cdi/email-password/post-signin", + "to": "/references/cdi/emailpassword-recipe/emailpasswordsignin" + }, + { + "operationId": "emailPasswordSignup", + "from": "/references/cdi/email-password/post-signup", + "to": "/references/cdi/emailpassword-recipe/emailpasswordsignup" + }, + { + "operationId": "emailPasswordGetPasswordReset", + "from": "/references/cdi/email-password/post-user-password-reset", + "to": "/references/cdi/emailpassword-recipe/emailpasswordgetpasswordreset" + }, + { + "operationId": "emailPasswordGetPasswordResetToken", + "from": "/references/cdi/email-password/post-user-password-reset-token", + "to": "/references/cdi/emailpassword-recipe/emailpasswordgetpasswordresettoken" + }, + { + "operationId": "emailPasswordResetPasswordConsumeToken", + "from": "/references/cdi/email-password/post-user-password-reset-token-consume", + "to": "/references/cdi/emailpassword-recipe/emailpasswordresetpasswordconsumetoken" + }, + { + "operationId": "userImport", + "from": "/references/cdi/email-password/post-user-passwordhash-import", + "to": "/references/cdi/emailpassword-recipe/userimport" + }, + { + "operationId": "emailPasswordPutUser", + "from": "/references/cdi/email-password/put-user", + "to": "/references/cdi/emailpassword-recipe/emailpasswordputuser" + }, + { + "operationId": "emailVerificationVerifyGet", + "from": "/references/cdi/email-verification/get-user-email-verify", + "to": "/references/cdi/emailverification-recipe/emailverificationverifyget" + }, + { + "operationId": "emailVerificationVerify", + "from": "/references/cdi/email-verification/post-user-email-verify", + "to": "/references/cdi/emailverification-recipe/emailverificationverify" + }, + { + "operationId": "emailVerificationVerifyRemove", + "from": "/references/cdi/email-verification/post-user-email-verify-remove", + "to": "/references/cdi/emailverification-recipe/emailverificationverifyremove" + }, + { + "operationId": "emailVerificationVerifyToken", + "from": "/references/cdi/email-verification/post-user-email-verify-token", + "to": "/references/cdi/emailverification-recipe/emailverificationverifytoken" + }, + { + "operationId": "emailVerificationVerifyTokenRemove", + "from": "/references/cdi/email-verification/post-user-email-verify-token-remove", + "to": "/references/cdi/emailverification-recipe/emailverificationverifytokenremove" + }, + { + "operationId": "deleteBulkImportUsers", + "from": "/references/cdi/import/delete-bulk-import-users", + "to": "/references/cdi/bulk-import/deletebulkimportusers" + }, + { + "operationId": "getBulkImportUsers", + "from": "/references/cdi/import/get-bulk-import-users", + "to": "/references/cdi/bulk-import/getbulkimportusers" + }, + { + "operationId": "importOneUserWithBulkImport", + "from": "/references/cdi/import/get-bulk-import-users-count", + "to": "/references/cdi/bulk-import/importoneuserwithbulkimport" + }, + { + "operationId": "countBulkImportUsers", + "from": "/references/cdi/import/post-bulk-import-import", + "to": "/references/cdi/bulk-import/countbulkimportusers" + }, + { + "operationId": "addBulkImportUsers", + "from": "/references/cdi/import/post-bulk-import-users", + "to": "/references/cdi/bulk-import/addbulkimportusers" + }, + { + "operationId": "getTotpDevices", + "from": "/references/cdi/mfa/get-totp-device-list", + "to": "/references/cdi/totp-recipe/gettotpdevices" + }, + { + "operationId": "createTotpDevice", + "from": "/references/cdi/mfa/post-totp-device", + "to": "/references/cdi/totp-recipe/createtotpdevice" + }, + { + "operationId": "importTotpDevice", + "from": "/references/cdi/mfa/post-totp-device-import", + "to": "/references/cdi/totp-recipe/importtotpdevice" + }, + { + "operationId": "removeTotpDevice", + "from": "/references/cdi/mfa/post-totp-device-remove", + "to": "/references/cdi/totp-recipe/removetotpdevice" + }, + { + "operationId": "verifyTotpDevice", + "from": "/references/cdi/mfa/post-totp-device-verify", + "to": "/references/cdi/totp-recipe/verifytotpdevice" + }, + { + "operationId": "verifyTotpCode", + "from": "/references/cdi/mfa/post-totp-verify", + "to": "/references/cdi/totp-recipe/verifytotpcode" + }, + { + "operationId": "updateTotpDeviceName", + "from": "/references/cdi/mfa/put-totp-device", + "to": "/references/cdi/totp-recipe/updatetotpdevicename" + }, + { + "operationId": "appListGET", + "from": "/references/cdi/multitenancy/get-multitenancy-app-list", + "to": "/references/cdi/multitenancy-recipe/applistget" + }, + { + "operationId": "appListV2GET", + "from": "/references/cdi/multitenancy/get-multitenancy-app-list-v2", + "to": "/references/cdi/multitenancy-recipe/applistv2get" + }, + { + "operationId": "connectionUriDomainListGET", + "from": "/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list", + "to": "/references/cdi/multitenancy-recipe/connectionuridomainlistget" + }, + { + "operationId": "connectionUriDomainListV2GET", + "from": "/references/cdi/multitenancy/get-multitenancy-connectionuridomain-list-v2", + "to": "/references/cdi/multitenancy-recipe/connectionuridomainlistv2get" + }, + { + "operationId": "tenantConfigGet", + "from": "/references/cdi/multitenancy/get-multitenancy-tenant", + "to": "/references/cdi/multitenancy-recipe/tenantconfigget" + }, + { + "operationId": "tenantListGET", + "from": "/references/cdi/multitenancy/get-multitenancy-tenant-list", + "to": "/references/cdi/multitenancy-recipe/tenantlistget" + }, + { + "operationId": "tenantListV2GET", + "from": "/references/cdi/multitenancy/get-multitenancy-tenant-list-v2", + "to": "/references/cdi/multitenancy-recipe/tenantlistv2get" + }, + { + "operationId": "tenantConfigV2Get", + "from": "/references/cdi/multitenancy/get-multitenancy-tenant-v2", + "to": "/references/cdi/multitenancy-recipe/tenantconfigv2get" + }, + { + "operationId": "deleteAppPOST", + "from": "/references/cdi/multitenancy/post-multitenancy-app-remove", + "to": "/references/cdi/multitenancy-recipe/deleteapppost" + }, + { + "operationId": "deleteTenantConfigPOST", + "from": "/references/cdi/multitenancy/post-multitenancy-config-thirdparty-remove", + "to": "/references/cdi/multitenancy-recipe/deletetenantconfigpost" + }, + { + "operationId": "deleteConnectionUriDomainPOST", + "from": "/references/cdi/multitenancy/post-multitenancy-connectionuridomain-remove", + "to": "/references/cdi/multitenancy-recipe/deleteconnectionuridomainpost" + }, + { + "operationId": "deleteTenantPOST", + "from": "/references/cdi/multitenancy/post-multitenancy-tenant-remove", + "to": "/references/cdi/multitenancy-recipe/deletetenantpost" + }, + { + "operationId": "addUserToTenant", + "from": "/references/cdi/multitenancy/post-multitenancy-tenant-user", + "to": "/references/cdi/multitenancy-recipe/addusertotenant" + }, + { + "operationId": "removeUserFromTenant", + "from": "/references/cdi/multitenancy/post-multitenancy-tenant-user-remove", + "to": "/references/cdi/multitenancy-recipe/removeuserfromtenant" + }, + { + "operationId": "createOrUpdateAppPUT", + "from": "/references/cdi/multitenancy/put-multitenancy-app", + "to": "/references/cdi/multitenancy-recipe/createorupdateappput" + }, + { + "operationId": "createOrUpdateAppV2PUT", + "from": "/references/cdi/multitenancy/put-multitenancy-app-v2", + "to": "/references/cdi/multitenancy-recipe/createorupdateappv2put" + }, + { + "operationId": "createOrUpdateTenantConfigPUT", + "from": "/references/cdi/multitenancy/put-multitenancy-config-thirdparty", + "to": "/references/cdi/multitenancy-recipe/createorupdatetenantconfigput" + }, + { + "operationId": "createOrUpdateConnectionURIDomainPUT", + "from": "/references/cdi/multitenancy/put-multitenancy-connectionuridomain", + "to": "/references/cdi/multitenancy-recipe/createorupdateconnectionuridomainput" + }, + { + "operationId": "createOrUpdateConnectionURIDomainV2PUT", + "from": "/references/cdi/multitenancy/put-multitenancy-connectionuridomain-v2", + "to": "/references/cdi/multitenancy-recipe/createorupdateconnectionuridomainv2put" + }, + { + "operationId": "createOrUpdateTenantPUT", + "from": "/references/cdi/multitenancy/put-multitenancy-tenant", + "to": "/references/cdi/multitenancy-recipe/createorupdatetenantput" + }, + { + "operationId": "createOrUpdateTenantV2PUT", + "from": "/references/cdi/multitenancy/put-multitenancy-tenant-v2", + "to": "/references/cdi/multitenancy-recipe/createorupdatetenantv2put" + }, + { + "operationId": "getJWKS", + "from": "/references/cdi/oauth/get-jwks", + "to": "/references/cdi/jwt-recipe/getjwks" + }, + { + "operationId": "getOAuth2Auth", + "from": "/references/cdi/oauth/get-oauth2-auth", + "to": "/references/cdi/oauth2provider-recipe/getoauth2auth" + }, + { + "operationId": "getOAuth2Client", + "from": "/references/cdi/oauth/get-oauth2-client", + "to": "/references/cdi/oauth2provider-recipe/getoauth2client" + }, + { + "operationId": "listOAuth2Clients", + "from": "/references/cdi/oauth/get-oauth2-clients", + "to": "/references/cdi/oauth2provider-recipe/listoauth2clients" + }, + { + "operationId": "getOAuth2ConsentRequest", + "from": "/references/cdi/oauth/get-oauth2-consent-request", + "to": "/references/cdi/oauth2provider-recipe/getoauth2consentrequest" + }, + { + "operationId": "getOAuth2LoginRequest", + "from": "/references/cdi/oauth/get-oauth2-login-request", + "to": "/references/cdi/oauth2provider-recipe/getoauth2loginrequest" + }, + { + "operationId": "getOAuth2SessionsLogout", + "from": "/references/cdi/oauth/get-oauth2-sessions-logout", + "to": "/references/cdi/oauth2provider-recipe/getoauth2sessionslogout" + }, + { + "operationId": "getOAuth2Token", + "from": "/references/cdi/oauth/get-oauth2-token", + "to": "/references/cdi/oauth2provider-recipe/getoauth2token" + }, + { + "operationId": "getWellKnownJWKS", + "from": "/references/cdi/oauth/get-well-known-jwks", + "to": "/references/cdi/core/getwellknownjwks" + }, + { + "operationId": "createOAuth2Client", + "from": "/references/cdi/oauth/post-oauth2-client", + "to": "/references/cdi/oauth2provider-recipe/createoauth2client" + }, + { + "operationId": "removeOAuth2Client", + "from": "/references/cdi/oauth/post-oauth2-client-remove", + "to": "/references/cdi/oauth2provider-recipe/removeoauth2client" + }, + { + "operationId": "acceptOAuth2ConsentRequest", + "from": "/references/cdi/oauth/post-oauth2-consent-request-accept", + "to": "/references/cdi/oauth2provider-recipe/acceptoauth2consentrequest" + }, + { + "operationId": "rejectOAuth2ConsentRequest", + "from": "/references/cdi/oauth/post-oauth2-consent-request-reject", + "to": "/references/cdi/oauth2provider-recipe/rejectoauth2consentrequest" + }, + { + "operationId": "acceptOAuth2LoginRequest", + "from": "/references/cdi/oauth/post-oauth2-login-request-accept", + "to": "/references/cdi/oauth2provider-recipe/acceptoauth2loginrequest" + }, + { + "operationId": "rejectOAuth2LoginRequest", + "from": "/references/cdi/oauth/post-oauth2-login-request-reject", + "to": "/references/cdi/oauth2provider-recipe/rejectoauth2loginrequest" + }, + { + "operationId": "acceptOAuth2LogoutRequest", + "from": "/references/cdi/oauth/post-oauth2-logout-request-accept", + "to": "/references/cdi/oauth2provider-recipe/acceptoauth2logoutrequest" + }, + { + "operationId": "rejectOAuth2LogoutRequest", + "from": "/references/cdi/oauth/post-oauth2-logout-request-reject", + "to": "/references/cdi/oauth2provider-recipe/rejectoauth2logoutrequest" + }, + { + "operationId": "revokeOAuth2Session", + "from": "/references/cdi/oauth/post-oauth2-session-revoke", + "to": "/references/cdi/oauth2provider-recipe/revokeoauth2session" + }, + { + "operationId": "introspectOAuth2Token", + "from": "/references/cdi/oauth/post-oauth2-token-introspect", + "to": "/references/cdi/oauth2provider-recipe/introspectoauth2token" + }, + { + "operationId": "revokeOAuth2Token", + "from": "/references/cdi/oauth/post-oauth2-token-revoke", + "to": "/references/cdi/oauth2provider-recipe/revokeoauth2token" + }, + { + "operationId": "revokeOAuth2Tokens", + "from": "/references/cdi/oauth/post-oauth2-tokens-revoke", + "to": "/references/cdi/oauth2provider-recipe/revokeoauth2tokens" + }, + { + "operationId": "updateOAuth2Client", + "from": "/references/cdi/oauth/put-oauth2-client", + "to": "/references/cdi/oauth2provider-recipe/updateoauth2client" + }, + { + "operationId": "passwordlessListCodes", + "from": "/references/cdi/passwordless/get-signinup-codes", + "to": "/references/cdi/passwordless-recipe/passwordlesslistcodes" + }, + { + "operationId": "passwordlessGetUser", + "from": "/references/cdi/passwordless/get-user", + "to": "/references/cdi/passwordless-recipe/passwordlessgetuser" + }, + { + "operationId": "passwordlessStartSignIn", + "from": "/references/cdi/passwordless/post-signinup-code", + "to": "/references/cdi/passwordless-recipe/passwordlessstartsignin" + }, + { + "operationId": "passwordlessCheckCode", + "from": "/references/cdi/passwordless/post-signinup-code-check", + "to": "/references/cdi/passwordless-recipe/passwordlesscheckcode" + }, + { + "operationId": "passwordlessTryUseCode", + "from": "/references/cdi/passwordless/post-signinup-code-consume", + "to": "/references/cdi/passwordless-recipe/passwordlesstryusecode" + }, + { + "operationId": "passwordlessRevokeCode", + "from": "/references/cdi/passwordless/post-signinup-code-remove", + "to": "/references/cdi/passwordless-recipe/passwordlessrevokecode" + }, + { + "operationId": "passwordlessRevokeAllCodesOfUser", + "from": "/references/cdi/passwordless/post-signinup-codes-remove", + "to": "/references/cdi/passwordless-recipe/passwordlessrevokeallcodesofuser" + }, + { + "operationId": "passwordlessPutUser", + "from": "/references/cdi/passwordless/put-user", + "to": "/references/cdi/passwordless-recipe/passwordlessputuser" + }, + { + "operationId": "getJWTData", + "from": "/references/cdi/session/get-jwt-data", + "to": "/references/cdi/session-recipe/getjwtdata" + }, + { + "operationId": "getSessionInfo", + "from": "/references/cdi/session/get-session", + "to": "/references/cdi/session-recipe/getsessioninfo" + }, + { + "operationId": "getSessionData", + "from": "/references/cdi/session/get-session-data", + "to": "/references/cdi/session-recipe/getsessiondata" + }, + { + "operationId": "getUserSessionHandles", + "from": "/references/cdi/session/get-session-user", + "to": "/references/cdi/session-recipe/getusersessionhandles" + }, + { + "operationId": "createSignedJWT", + "from": "/references/cdi/session/post-jwt", + "to": "/references/cdi/jwt-recipe/createsignedjwt" + }, + { + "operationId": "createNewSession", + "from": "/references/cdi/session/post-session", + "to": "/references/cdi/session-recipe/createnewsession" + }, + { + "operationId": "refreshSession", + "from": "/references/cdi/session/post-session-refresh", + "to": "/references/cdi/session-recipe/refreshsession" + }, + { + "operationId": "regenerateSession", + "from": "/references/cdi/session/post-session-regenerate", + "to": "/references/cdi/session-recipe/regeneratesession" + }, + { + "operationId": "deleteSession", + "from": "/references/cdi/session/post-session-remove", + "to": "/references/cdi/session-recipe/deletesession" + }, + { + "operationId": "verifySession", + "from": "/references/cdi/session/post-session-verify", + "to": "/references/cdi/session-recipe/verifysession" + }, + { + "operationId": "putJWTData", + "from": "/references/cdi/session/put-jwt-data", + "to": "/references/cdi/session-recipe/putjwtdata" + }, + { + "operationId": "putSessionData", + "from": "/references/cdi/session/put-session-data", + "to": "/references/cdi/session-recipe/putsessiondata" + }, + { + "operationId": "thirdPartyGetUser", + "from": "/references/cdi/thirdparty/get-user", + "to": "/references/cdi/thirdparty-recipe/thirdpartygetuser" + }, + { + "operationId": "thirdPartyGetUsersByEmail", + "from": "/references/cdi/thirdparty/get-users-by-email", + "to": "/references/cdi/thirdparty-recipe/thirdpartygetusersbyemail" + }, + { + "operationId": "thirdPartySigninup", + "from": "/references/cdi/thirdparty/post-signinup", + "to": "/references/cdi/thirdparty-recipe/thirdpartysigninup" + }, + { + "operationId": "userMetadataRead", + "from": "/references/cdi/user-metadata/get-user-metadata", + "to": "/references/cdi/user-metadata-recipe/usermetadataread" + }, + { + "operationId": "userMetadataDelete", + "from": "/references/cdi/user-metadata/post-user-metadata-remove", + "to": "/references/cdi/user-metadata-recipe/usermetadatadelete" + }, + { + "operationId": "userMetadataUpdate", + "from": "/references/cdi/user-metadata/put-user-metadata", + "to": "/references/cdi/user-metadata-recipe/usermetadataupdate" + }, + { + "operationId": "getPermissionRoles", + "from": "/references/cdi/user-roles/get-permission-roles", + "to": "/references/cdi/user-roles-recipe/getpermissionroles" + }, + { + "operationId": "getRolePermissions", + "from": "/references/cdi/user-roles/get-role-permissions", + "to": "/references/cdi/user-roles-recipe/getrolepermissions" + }, + { + "operationId": "getRoleUsers", + "from": "/references/cdi/user-roles/get-role-users", + "to": "/references/cdi/user-roles-recipe/getroleusers" + }, + { + "operationId": "getRoles", + "from": "/references/cdi/user-roles/get-roles", + "to": "/references/cdi/user-roles-recipe/getroles" + }, + { + "operationId": "getUserRoles", + "from": "/references/cdi/user-roles/get-user-roles", + "to": "/references/cdi/user-roles-recipe/getuserroles" + }, + { + "operationId": "removeRolePermissions", + "from": "/references/cdi/user-roles/post-role-permissions-remove", + "to": "/references/cdi/user-roles-recipe/removerolepermissions" + }, + { + "operationId": "removeRole", + "from": "/references/cdi/user-roles/post-role-remove", + "to": "/references/cdi/user-roles-recipe/removerole" + }, + { + "operationId": "removeUserRole", + "from": "/references/cdi/user-roles/post-user-role-remove", + "to": "/references/cdi/user-roles-recipe/removeuserrole" + }, + { + "operationId": "putRole", + "from": "/references/cdi/user-roles/put-role", + "to": "/references/cdi/user-roles-recipe/putrole" + }, + { + "operationId": "addUserRole", + "from": "/references/cdi/user-roles/put-user-role", + "to": "/references/cdi/user-roles-recipe/adduserrole" + }, + { + "operationId": "removeWebAuthNCredential", + "from": "/references/cdi/webauthn/delete-webauthn-credential", + "to": "/references/cdi/webauthn-recipe/removewebauthncredential" + }, + { + "operationId": "removeWebAuthNOptions", + "from": "/references/cdi/webauthn/delete-webauthn-options", + "to": "/references/cdi/webauthn-recipe/removewebauthnoptions" + }, + { + "operationId": "getWebAuthNCredential", + "from": "/references/cdi/webauthn/get-webauthn-credential", + "to": "/references/cdi/webauthn-recipe/getwebauthncredential" + }, + { + "operationId": "listWebAuthNCredentials", + "from": "/references/cdi/webauthn/get-webauthn-credentials", + "to": "/references/cdi/webauthn-recipe/listwebauthncredentials" + }, + { + "operationId": "getWebAuthNOptions", + "from": "/references/cdi/webauthn/get-webauthn-options", + "to": "/references/cdi/webauthn-recipe/getwebauthnoptions" + }, + { + "operationId": "recoverWebAuthNUser", + "from": "/references/cdi/webauthn/post-webauthn-recover", + "to": "/references/cdi/webauthn-recipe/recoverwebauthnuser" + }, + { + "operationId": "registerWebAuthNCredential", + "from": "/references/cdi/webauthn/post-webauthn-register", + "to": "/references/cdi/webauthn-recipe/registerwebauthncredential" + }, + { + "operationId": "generateRegistrationOptions", + "from": "/references/cdi/webauthn/post-webauthn-registration-options", + "to": "/references/cdi/webauthn-recipe/generateregistrationoptions" + }, + { + "operationId": "signInWebAuthNUser", + "from": "/references/cdi/webauthn/post-webauthn-signin", + "to": "/references/cdi/webauthn-recipe/signinwebauthnuser" + }, + { + "operationId": "generateSigninOptions", + "from": "/references/cdi/webauthn/post-webauthn-signin-options", + "to": "/references/cdi/webauthn-recipe/generatesigninoptions" + }, + { + "operationId": "signUpWebAuthNUser", + "from": "/references/cdi/webauthn/post-webauthn-signup", + "to": "/references/cdi/webauthn-recipe/signupwebauthnuser" + }, + { + "operationId": "consumeWebAuthNToken", + "from": "/references/cdi/webauthn/post-webauthn-token-consume", + "to": "/references/cdi/webauthn-recipe/consumewebauthntoken" + }, + { + "operationId": "generateTokenForRecovery", + "from": "/references/cdi/webauthn/post-webauthn-token-recovery", + "to": "/references/cdi/webauthn-recipe/generatetokenforrecovery" + }, + { + "operationId": "updateEmail", + "from": "/references/cdi/webauthn/put-webauthn-email", + "to": "/references/cdi/webauthn-recipe/updateemail" + }, + { + "operationId": "emailExists", + "from": "/references/fdi/email-password/get-emailpassword-email-exists", + "to": "/references/fdi/emailpassword-recipe/emailexists" + }, + { + "operationId": "emailExistsDepr", + "from": "/references/fdi/email-password/get-signup-email-exists", + "to": "/references/fdi/emailpassword-recipe/emailexistsdepr" + }, + { + "operationId": "signIn", + "from": "/references/fdi/email-password/post-signin", + "to": "/references/fdi/emailpassword-recipe/signin" + }, + { + "operationId": "signUp", + "from": "/references/fdi/email-password/post-signup", + "to": "/references/fdi/emailpassword-recipe/signup" + }, + { + "operationId": "passwordReset", + "from": "/references/fdi/email-password/post-user-password-reset", + "to": "/references/fdi/emailpassword-recipe/passwordreset" + }, + { + "operationId": "passwordResetToken", + "from": "/references/fdi/email-password/post-user-password-reset-token", + "to": "/references/fdi/emailpassword-recipe/passwordresettoken" + }, + { + "operationId": "getVerifyEmail", + "from": "/references/fdi/email-verification/get-user-email-verify", + "to": "/references/fdi/emailverification-recipe/getverifyemail" + }, + { + "operationId": "verifyEmail", + "from": "/references/fdi/email-verification/post-user-email-verify", + "to": "/references/fdi/emailverification-recipe/verifyemail" + }, + { + "operationId": "verifyEmailToken", + "from": "/references/fdi/email-verification/post-user-email-verify-token", + "to": "/references/fdi/emailverification-recipe/verifyemailtoken" + }, + { + "operationId": "exampleAppAPI", + "from": "/references/fdi/get-example", + "to": "/references/fdi/app-api/exampleappapi" + }, + { + "operationId": "getJWKS", + "from": "/references/fdi/get-jwt-jwks-json", + "to": "/references/fdi/jwt-recipe/getjwks" + }, + { + "operationId": "loginmethods", + "from": "/references/fdi/get-loginmethods", + "to": "/references/fdi/multitenancy-recipe/loginmethods" + }, + { + "operationId": "getOpenIdDiscoveryConfiguration", + "from": "/references/fdi/get-well-known-openid-configuration", + "to": "/references/fdi/openid-recipe/getopeniddiscoveryconfiguration" + }, + { + "operationId": "listTOTPdevices", + "from": "/references/fdi/mfa/get-totp-device-list", + "to": "/references/fdi/totp-recipe/listtotpdevices" + }, + { + "operationId": "createTOTPDevice", + "from": "/references/fdi/mfa/post-totp-device", + "to": "/references/fdi/totp-recipe/createtotpdevice" + }, + { + "operationId": "removeTOTPDevice", + "from": "/references/fdi/mfa/post-totp-device-remove", + "to": "/references/fdi/totp-recipe/removetotpdevice" + }, + { + "operationId": "verifyTOTPDevice", + "from": "/references/fdi/mfa/post-totp-device-verify", + "to": "/references/fdi/totp-recipe/verifytotpdevice" + }, + { + "operationId": "verifyTOTP", + "from": "/references/fdi/mfa/post-totp-verify", + "to": "/references/fdi/totp-recipe/verifytotp" + }, + { + "operationId": "getMFAInfo", + "from": "/references/fdi/mfa/put-mfa-info", + "to": "/references/fdi/multifactorauth-recipe/getmfainfo" + }, + { + "operationId": "oauthAuthGET", + "from": "/references/fdi/oauth/get-oauth-auth", + "to": "/references/fdi/oauth2provider-recipe/oauthauthget" + }, + { + "operationId": "oauthEndSessionGET", + "from": "/references/fdi/oauth/get-oauth-end_session", + "to": "/references/fdi/oauth2provider-recipe/oauthendsessionget" + }, + { + "operationId": "oauthLoginGET", + "from": "/references/fdi/oauth/get-oauth-login", + "to": "/references/fdi/oauth2provider-recipe/oauthloginget" + }, + { + "operationId": "oauthLoginInfoGET", + "from": "/references/fdi/oauth/get-oauth-logininfo", + "to": "/references/fdi/oauth2provider-recipe/oauthlogininfoget" + }, + { + "operationId": "oauthUserInfoGET", + "from": "/references/fdi/oauth/get-oauth-userinfo", + "to": "/references/fdi/oauth2provider-recipe/oauthuserinfoget" + }, + { + "operationId": "oauthEndSessionPOST", + "from": "/references/fdi/oauth/post-oauth-end_session", + "to": "/references/fdi/oauth2provider-recipe/oauthendsessionpost" + }, + { + "operationId": "oauthIntrospectPOST", + "from": "/references/fdi/oauth/post-oauth-introspect", + "to": "/references/fdi/oauth2provider-recipe/oauthintrospectpost" + }, + { + "operationId": "oauthLogoutPOST", + "from": "/references/fdi/oauth/post-oauth-logout", + "to": "/references/fdi/oauth2provider-recipe/oauthlogoutpost" + }, + { + "operationId": "oauthRevokePOST", + "from": "/references/fdi/oauth/post-oauth-revoke", + "to": "/references/fdi/oauth2provider-recipe/oauthrevokepost" + }, + { + "operationId": "oauthTokenPOST", + "from": "/references/fdi/oauth/post-oauth-token", + "to": "/references/fdi/oauth2provider-recipe/oauthtokenpost" + }, + { + "operationId": "passwordlessEmailExists", + "from": "/references/fdi/passwordless/get-passwordless-email-exists", + "to": "/references/fdi/passwordless-recipe/passwordlessemailexists" + }, + { + "operationId": "passwordlessPhoneNumberExists", + "from": "/references/fdi/passwordless/get-passwordless-phoneNumber-exists", + "to": "/references/fdi/passwordless-recipe/passwordlessphonenumberexists" + }, + { + "operationId": "passwordlessEmailExistsDepr", + "from": "/references/fdi/passwordless/get-signup-email-exists", + "to": "/references/fdi/passwordless-recipe/passwordlessemailexistsdepr" + }, + { + "operationId": "passwordlessPhoneNumberExistsDepr", + "from": "/references/fdi/passwordless/get-signup-phoneNumber-exists", + "to": "/references/fdi/passwordless-recipe/passwordlessphonenumberexistsdepr" + }, + { + "operationId": "passwordlessSignInUpStart", + "from": "/references/fdi/passwordless/post-signinup-code", + "to": "/references/fdi/passwordless-recipe/passwordlesssigninupstart" + }, + { + "operationId": "passwordlessSignInUpConsume", + "from": "/references/fdi/passwordless/post-signinup-code-consume", + "to": "/references/fdi/passwordless-recipe/passwordlesssigninupconsume" + }, + { + "operationId": "passwordlessSignInUpResend", + "from": "/references/fdi/passwordless/post-signinup-code-resend", + "to": "/references/fdi/passwordless-recipe/passwordlesssigninupresend" + }, + { + "operationId": "refresh", + "from": "/references/fdi/session/post-session-refresh", + "to": "/references/fdi/session-recipe/refresh" + }, + { + "operationId": "signout", + "from": "/references/fdi/session/post-signout", + "to": "/references/fdi/session-recipe/signout" + }, + { + "operationId": "authorisationUrl", + "from": "/references/fdi/thirdparty/get-authorisationurl", + "to": "/references/fdi/thirdparty-recipe/authorisationurl" + }, + { + "operationId": "thirdPartyCallbackApple", + "from": "/references/fdi/thirdparty/post-callback-apple", + "to": "/references/fdi/thirdparty-recipe/thirdpartycallbackapple" + }, + { + "operationId": "signInUp", + "from": "/references/fdi/thirdparty/post-signinup", + "to": "/references/fdi/thirdparty-recipe/signinup" + }, + { + "operationId": "webauthnEmailExists", + "from": "/references/fdi/webauthn/get-webauthn-email-exists", + "to": "/references/fdi/webauthn-recipe/webauthnemailexists" + }, + { + "operationId": "webauthnRegisterCredential", + "from": "/references/fdi/webauthn/post-webauthn-credential", + "to": "/references/fdi/webauthn-recipe/webauthnregistercredential" + }, + { + "operationId": "webauthnRecoverAccount", + "from": "/references/fdi/webauthn/post-webauthn-recover-account", + "to": "/references/fdi/webauthn-recipe/webauthnrecoveraccount" + }, + { + "operationId": "webauthnGenerateRecoverAccountToken", + "from": "/references/fdi/webauthn/post-webauthn-recover-account-token", + "to": "/references/fdi/webauthn-recipe/webauthngeneraterecoveraccounttoken" + }, + { + "operationId": "webauthnRegisterOptions", + "from": "/references/fdi/webauthn/post-webauthn-register-options", + "to": "/references/fdi/webauthn-recipe/webauthnregisteroptions" + }, + { + "operationId": "webauthnSignIn", + "from": "/references/fdi/webauthn/post-webauthn-signin", + "to": "/references/fdi/webauthn-recipe/webauthnsignin" + }, + { + "operationId": "webauthnSignInOptions", + "from": "/references/fdi/webauthn/post-webauthn-signin-options", + "to": "/references/fdi/webauthn-recipe/webauthnsigninoptions" + }, + { + "operationId": "webauthnSignUp", + "from": "/references/fdi/webauthn/post-webauthn-signup", + "to": "/references/fdi/webauthn-recipe/webauthnsignup" + } + ] +} diff --git a/scripts/generate-api-reference-pages.ts b/scripts/generate-api-reference-pages.ts deleted file mode 100644 index 4e800a44b0..0000000000 --- a/scripts/generate-api-reference-pages.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { dereference, load } from "@scalar/openapi-parser"; -import { file, write, $ } from "bun"; -import type { OpenAPIV3 } from "@scalar/openapi-types"; -import { mkdir, exists, readdir } from "node:fs/promises"; -import path from "path"; - -type APIPageMapping = Record< - string, - { - path: string; - method: string; - frontmatter: Record; - filePath: string; - } ->; - -async function generateAPIReferencePages(apiType: "cdi" | "fdi") { - await writeSchema(apiType); - await writePageMapping(apiType); - const schema = (await file(`./static/${apiType}.json`).json()) as OpenAPIV3.Document; - const pageMapping = (await file(`./static/${apiType}-mapping.json`).json()) as APIPageMapping; - - for (const route in schema.paths) { - for (const method in schema.paths[route]) { - const operationId = schema.paths[route][method].operationId; - const mapping = pageMapping[operationId]; - if (!mapping) { - throw new Error(`No mapping found for ${operationId}`); - } - await writePage(operationId, apiType, mapping); - } - } - - await reorderCategories(apiType); -} - -async function writeSchema(apiType: "cdi" | "fdi") { - const schemaPath = `./static/${apiType}.yml`; - const ymlContent = await file(schemaPath).text(); - const api = await dereference(ymlContent); - - await write(`./static/${apiType}.json`, JSON.stringify(api.schema, null, 2)); -} - -async function writePageMapping(apiType: "cdi" | "fdi") { - const schemaPath = `./static/${apiType}.yml`; - const ymlContent = await file(schemaPath).text(); - // These vales are specific to how we display the pages inside the docs - // They cannot be determined based on the OpenAPI spec alone - const filePathsMappingPath = `./static/${apiType}-file-paths.json`; - const filePathsMapping = (await file(filePathsMappingPath).json()) as Record; - const { schema, errors } = await dereference(ymlContent); - - if (errors?.length) { - throw new Error(`Failed to dereference ${schemaPath}: ${errors.join("\n")}`); - } - - const typedSchema = schema as OpenAPIV3.Document; - - const mapping: APIPageMapping = {}; - - for (const route in typedSchema.paths) { - for (const method in typedSchema.paths[route]) { - const operation = typedSchema.paths[route][method]; - mapping[operation.operationId] = { - frontmatter: { - sidebar_position: 1, - sidebar_label: `${method} ${operation.summary || route}${operation.deprecated ? " (deprecated)" : ""}`, - title: operation.summary || route, - description: operation.description || `${apiType.toUpperCase()} API specification for the ${route} endpoint`, - }, - path: route, - method: method, - filePath: filePathsMapping[operation.operationId], - }; - } - } - - const pageOrderingMap: Record> = {}; - for (const operationId in mapping) { - if (!mapping[operationId].filePath) { - console.error(`File path not found for ${operationId}`); - continue; - } - const folderName = path.dirname(mapping[operationId].filePath); - if (!pageOrderingMap[folderName]) { - pageOrderingMap[folderName] = []; - } - pageOrderingMap[folderName].push({ - method: mapping[operationId].method, - path: mapping[operationId].path, - operationId, - }); - } - - const methodPriority = { get: 1, post: 2, put: 3, patch: 4, delete: 5 }; - for (const folderName in pageOrderingMap) { - pageOrderingMap[folderName].sort((a, b) => { - const priorityA = methodPriority[a.method as keyof typeof methodPriority]; - const priorityB = methodPriority[b.method as keyof typeof methodPriority]; - - if (priorityA === priorityB) { - return a.path.localeCompare(b.path, undefined, { sensitivity: "base" }); - } - - return priorityA - priorityB; - }); - - for (const [index, operation] of pageOrderingMap[folderName].entries()) { - const operationId = operation.operationId; - mapping[operationId].frontmatter.sidebar_position = index + 1; - } - } - - await write(`./static/${apiType}-mapping.json`, JSON.stringify(mapping, null, 2)); -} - -async function writePage(operationId: string, apiType: "cdi" | "fdi", mapping: APIPageMapping[string]) { - const dirName = path.dirname(mapping.filePath); - const fullDirPath = `./docs/references/${dirName}`; - if (!(await exists(fullDirPath))) { - await mkdir(fullDirPath, { recursive: true }); - await write( - `${fullDirPath}/_category_.json`, - ` -{ - "label": "${dirName}", - "position": 1 -} -`, - ); - } - - // const description = (mapping.frontmatter.description as string) || ""; - - const fileContent = `--- -title: ${mapping.frontmatter.title} -sidebar_label: ${mapping.frontmatter.sidebar_label} -sidebar_position: ${mapping.frontmatter.sidebar_position} -description: ${mapping.method.toUpperCase()} ${mapping.path} endpoint exposed by the ${apiType.toUpperCase()} API -page_type: api-reference -hide_title: true ---- - - -`; - - await write(`./docs/references/${mapping.filePath}`, fileContent); -} - -async function reorderCategories(apiType: "cdi" | "fdi") { - const filePaths = await readdir(`./docs/references/${apiType}`, { recursive: true, withFileTypes: true }); - const categoryFiles = filePaths.filter( - (categoryFile) => - categoryFile.isFile() && - categoryFile.name.endsWith("_category_.json") && - categoryFile.parentPath !== `docs/references/${apiType}`, - ); - - const categories = await Promise.all( - categoryFiles.map(async (categoryFile) => { - const category = await file(`${categoryFile.parentPath}/${categoryFile.name}`).json(); - return { - mapping: category, - file: categoryFile, - }; - }), - ); - categories.sort((a, b) => a.mapping.label.localeCompare(b.mapping.label)); - - await Promise.all( - categories.map(async (category, index) => { - category.mapping.position = index + 1; - await write(`${category.file.parentPath}/${category.file.name}`, JSON.stringify(category.mapping, null, 2)); - }), - ); -} - -(async () => { - await Promise.all([generateAPIReferencePages("cdi")]); -})(); diff --git a/scripts/search.ts b/scripts/search.ts deleted file mode 100644 index 2f2a3ba60e..0000000000 --- a/scripts/search.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { algoliasearch, SetSettingsProps, SynonymHit } from "algoliasearch"; -import * as fs from "fs-extra"; -import * as path from "path"; - -import type { OpenAPIV3 } from "@scalar/openapi-types"; - -const APPLICATION_ID = process.env.ALGOLIA_APPLICATION_ID; -const API_KEY = process.env.ALGOLIA_ADMIN_API_KEY; -const INDEX_NAME = "supertokens_api_references"; - -interface APIReferenceDocument extends Record { - objectID: string; - endpoint: { - path: string; - method: string; - summary: string; - description?: string; - operationId?: string; - tags: string[]; - deprecated: boolean; - path_depth: number; - }; - apiType: string; - parameters?: Array<{ - name: string; - type: string; - required: boolean; - description?: string; - }>; - responses?: Array<{ - status: string; - description: string; - }>; - version?: string; -} - -export async function updateSearchDocuments() { - if (!APPLICATION_ID || !API_KEY) { - throw new Error("Missing required environment variables: ALGOLIA_APP_ID or ALGOLIA_ADMIN_API_KEY"); - } - - try { - const client = algoliasearch(APPLICATION_ID, API_KEY); - const documents = await extractAPIDocuments(); - - if (documents.length === 0) { - console.log("⚠️ No API documents found to index"); - return; - } - - await client.clearObjects({ indexName: INDEX_NAME }); - const responses = await client.saveObjects({ - indexName: INDEX_NAME, - objects: documents, - }); - - console.log(`✅ Updated API reference index with ${responses.length} documents`); - return responses; - } catch (error) { - console.error("❌ Error updating API reference index:", error); - throw error; - } -} - -async function extractAPIDocuments(): Promise { - const documents: APIReferenceDocument[] = []; - const specPaths = ["static/fdi.json", "static/cdi.json"]; - - for (const specPath of specPaths) { - const fullPath = path.join(process.cwd(), specPath); - - try { - if (await fs.pathExists(fullPath)) { - const spec = (await fs.readJson(fullPath)) as OpenAPIV3.Document; - const apiType = path.basename(specPath, ".json").toUpperCase(); - documents.push(...parseOpenAPISpec(spec, apiType)); - } - } catch (error) { - console.warn(`⚠️ Could not process API spec at ${specPath}:`, error); - } - } - - return documents; -} - -function parseOpenAPISpec(spec: OpenAPIV3.Document, apiType: string): APIReferenceDocument[] { - const documents: APIReferenceDocument[] = []; - - if (!spec.paths) { - return documents; - } - - for (const [pathKey, pathItem] of Object.entries(spec.paths)) { - if (!pathItem) continue; - - const methods = ["get", "post", "put", "delete", "patch", "head", "options"] as const; - - for (const method of methods) { - const operation = pathItem[method]; - if (!operation) continue; - - const objectID = `${apiType}-${method}-${pathKey}`.replace(/[^a-zA-Z0-9-_]/g, "-"); - const pathDepth = pathKey.split("/").filter(Boolean).length; - - const document: APIReferenceDocument = { - objectID, - endpoint: { - path: pathKey, - method: method.toUpperCase(), - summary: operation.summary || "", - description: operation.description, - operationId: operation.operationId, - tags: operation.tags || [], - deprecated: operation.deprecated || false, - path_depth: pathDepth, - }, - apiType, - version: spec.info?.version, - }; - - if (operation.parameters) { - document.parameters = operation.parameters.map((param: any) => ({ - name: param.name, - type: param.schema?.type || "unknown", - required: param.required || false, - description: param.description, - })); - } - - if (operation.responses) { - document.responses = Object.entries(operation.responses).map(([status, response]: [string, any]) => ({ - status, - description: response.description || "", - })); - } - - documents.push(document); - } - } - - return documents; -} - -const IndexSettings: SetSettingsProps["indexSettings"] = { - searchableAttributes: [ - "unordered(endpoint.summary)", - "unordered(endpoint.description)", - "unordered(endpoint.path)", - "unordered(endpoint.method)", - "unordered(endpoint.tags)", - // "unordered(parameters.name)", - // "unordered(parameters.description)", - // "unordered(responses.description)", - // "unordered(requestBody.description)", - // "unordered(schemas.title)", - // "unordered(schemas.description)", - // "unordered(schemas.properties.name)", - // "unordered(schemas.properties.description)", - ], - attributesForFaceting: [ - "filterOnly(endpoint.deprecated)", - "searchable(endpoint.tags)", - "searchable(endpoint.method)", - // "filterOnly(endpoint.security)", - // "filterOnly(parameters.required)", - // "filterOnly(parameters.in)", - // "filterOnly(responses.statusCode)", - "searchable(apiType)", - // "filterOnly(apiVersion)", - // "filterOnly(servers.url)", - ], - customRanking: ["asc(endpoint.deprecated)", "asc(endpoint.method)", "asc(endpoint.path_depth)"], - ranking: ["typo", "geo", "words", "filters", "proximity", "attribute", "exact", "custom"], - attributesToRetrieve: [ - "objectID", - "endpoint.path", - "endpoint.method", - "endpoint.summary", - "endpoint.description", - "endpoint.operationId", - "endpoint.tags", - "endpoint.deprecated", - "apiType", - ], - attributesToHighlight: ["endpoint.summary", "endpoint.description", "endpoint.path", "endpoint.method"], - attributesToSnippet: ["endpoint.description:50"], - highlightPreTag: "", - highlightPostTag: "", - snippetEllipsisText: "...", - distinct: true, - attributeForDistinct: "endpoint.operationId", - relevancyStrictness: 90, - disableTypoToleranceOnAttributes: ["endpoint.method", "endpoint.path"], - disableTypoToleranceOnWords: ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"], - minWordSizefor1Typo: 4, - minWordSizefor2Typos: 8, - typoTolerance: true, - removeWordsIfNoResults: "lastWords", - advancedSyntax: true, - allowTyposOnNumericTokens: false, - ignorePlurals: true, - removeStopWords: true, - queryLanguages: ["en"], - indexLanguages: ["en"], - camelCaseAttributes: ["endpoint.operationId", "parameters.name", "schemas.properties.name"], - userData: { - indexType: "openapi_reference", - version: "1.0.0", - lastUpdated: new Date().toISOString(), - }, -}; - -const IndexSynonyms: SynonymHit[] = [ - { - objectID: "api-synonyms-1", - type: "synonym", - synonyms: ["create", "post", "add", "new"], - }, - { - objectID: "api-synonyms-2", - type: "synonym", - synonyms: ["update", "put", "patch", "modify", "edit"], - }, - { - objectID: "api-synonyms-3", - type: "synonym", - synonyms: ["delete", "remove", "destroy"], - }, - { - objectID: "api-synonyms-4", - type: "synonym", - synonyms: ["get", "fetch", "retrieve", "read", "list"], - }, - { - objectID: "api-synonyms-5", - type: "synonym", - synonyms: ["auth", "authentication", "authorization", "oauth", "jwt", "token"], - }, - { - objectID: "api-synonyms-6", - type: "synonym", - synonyms: ["param", "parameter", "argument", "input"], - }, - { - objectID: "api-synonyms-7", - type: "synonym", - synonyms: ["response", "output", "result", "return"], - }, - { - objectID: "api-synonyms-8", - type: "synonym", - synonyms: ["schema", "model", "type", "structure"], - }, - { - objectID: "api-synonyms-9", - type: "oneWaySynonym", - input: "404", - synonyms: ["not found", "missing", "does not exist"], - }, - { - objectID: "api-synonyms-10", - type: "oneWaySynonym", - input: "401", - synonyms: ["unauthorized", "not authenticated"], - }, - { - objectID: "api-synonyms-11", - type: "oneWaySynonym", - input: "403", - synonyms: ["forbidden", "not authorized", "access denied"], - }, - { - objectID: "api-synonyms-12", - type: "oneWaySynonym", - input: "200", - synonyms: ["success", "ok", "successful"], - }, -]; - -async function updateIndex() { - if (!APPLICATION_ID || !API_KEY) { - throw new Error("Missing required environment variables: ALGOLIA_APP_ID or ALGOLIA_ADMIN_API_KEY"); - } - - try { - const client = algoliasearch(APPLICATION_ID, API_KEY); - console.log("Updating index settings..."); - await client.setSettings({ - indexName: INDEX_NAME, - indexSettings: IndexSettings, - forwardToReplicas: true, - }); - console.log("Updating synonyms..."); - await client.saveSynonyms({ - indexName: INDEX_NAME, - synonymHit: IndexSynonyms, - forwardToReplicas: true, - replaceExistingSynonyms: true, - }); - } catch (error) { - console.error("❌ Error updating API reference index:", error); - throw error; - } -} - -(async () => { - await updateIndex(); -})(); diff --git a/scripts/search/api-reference-index.ts b/scripts/search/api-reference-index.ts deleted file mode 100644 index 696a58ae05..0000000000 --- a/scripts/search/api-reference-index.ts +++ /dev/null @@ -1,281 +0,0 @@ -/** - * This file is used to create and update the Algolia API reference index. - * Make sure to create an index that can work efficiently with API reference documents. - */ - -import { SetSettingsProps, SynonymHit } from "algoliasearch"; -import fs from "fs-extra"; -import path from "path"; -import { OpenAPIV3 } from "@scalar/openapi-types"; - -import { SearchIndex } from "./search-index"; - -export class ApiReferenceIndex extends SearchIndex { - indexName = "supertokens_api_references"; - async updateDocuments(): Promise { - const documents = await this.extractAPIDocuments(); - if (documents.length === 0) { - console.log("⚠️ No API documents found to index"); - return; - } - - await this.client.clearObjects({ indexName: this.indexName }); - const responses = await this.client.saveObjects({ - indexName: this.indexName, - objects: documents, - }); - - console.log(`✅ Updated API reference index with ${responses.length} documents`); - } - - async updateConfiguration(): Promise { - await this.client.setSettings({ - indexName: this.indexName, - indexSettings: IndexSettings, - forwardToReplicas: true, - }); - await this.client.saveSynonyms({ - indexName: this.indexName, - synonymHit: IndexSynonyms, - forwardToReplicas: true, - replaceExistingSynonyms: true, - }); - } - - private async extractAPIDocuments(): Promise { - const documents: APIReferenceDocument[] = []; - const specPaths = ["static/fdi.json", "static/cdi.json"]; - - for (const specPath of specPaths) { - const fullPath = path.join(process.cwd(), specPath); - - if (await fs.pathExists(fullPath)) { - const spec = (await fs.readJson(fullPath)) as OpenAPIV3.Document; - const apiType = path.basename(specPath, ".json").toUpperCase(); - documents.push(...this.parseOpenAPISpec(spec, apiType)); - } - } - - return documents; - } - - private parseOpenAPISpec(spec: OpenAPIV3.Document, apiType: string): APIReferenceDocument[] { - const documents: APIReferenceDocument[] = []; - - if (!spec.paths) { - return documents; - } - - for (const [pathKey, pathItem] of Object.entries(spec.paths)) { - if (!pathItem) continue; - - const methods = ["get", "post", "put", "delete", "patch", "head", "options"] as const; - - for (const method of methods) { - const operation = pathItem[method]; - if (!operation) continue; - - const objectID = `${apiType}-${method}-${pathKey}`.replace(/[^a-zA-Z0-9-_]/g, "-"); - const pathDepth = pathKey.split("/").filter(Boolean).length; - - const document: APIReferenceDocument = { - objectID, - endpoint: { - path: pathKey, - method: method.toUpperCase(), - summary: operation.summary || "", - description: operation.description, - operationId: operation.operationId, - tags: operation.tags || [], - deprecated: operation.deprecated || false, - path_depth: pathDepth, - }, - apiType, - version: spec.info?.version, - }; - - if (operation.parameters) { - document.parameters = operation.parameters.map((param: any) => ({ - name: param.name, - type: param.schema?.type || "unknown", - required: param.required || false, - description: param.description, - })); - } - - if (operation.responses) { - document.responses = Object.entries(operation.responses).map(([status, response]: [string, any]) => ({ - status, - description: response.description || "", - })); - } - - documents.push(document); - } - } - - return documents; - } -} - -interface APIReferenceDocument extends Record { - objectID: string; - endpoint: { - path: string; - method: string; - summary: string; - description?: string; - operationId?: string; - tags: string[]; - deprecated: boolean; - path_depth: number; - }; - apiType: string; - parameters?: Array<{ - name: string; - type: string; - required: boolean; - description?: string; - }>; - responses?: Array<{ - status: string; - description: string; - }>; - version?: string; -} - -const IndexSettings: SetSettingsProps["indexSettings"] = { - searchableAttributes: [ - "unordered(endpoint.summary)", - "unordered(endpoint.description)", - "unordered(endpoint.path)", - "unordered(endpoint.method)", - "unordered(endpoint.tags)", - // "unordered(parameters.name)", - // "unordered(parameters.description)", - // "unordered(responses.description)", - // "unordered(requestBody.description)", - // "unordered(schemas.title)", - // "unordered(schemas.description)", - // "unordered(schemas.properties.name)", - // "unordered(schemas.properties.description)", - ], - attributesForFaceting: [ - "filterOnly(endpoint.deprecated)", - "searchable(endpoint.tags)", - "searchable(endpoint.method)", - // "filterOnly(endpoint.security)", - // "filterOnly(parameters.required)", - // "filterOnly(parameters.in)", - // "filterOnly(responses.statusCode)", - "searchable(apiType)", - // "filterOnly(apiVersion)", - // "filterOnly(servers.url)", - ], - customRanking: ["asc(endpoint.deprecated)", "asc(endpoint.method)", "asc(endpoint.path_depth)"], - ranking: ["typo", "geo", "words", "filters", "proximity", "attribute", "exact", "custom"], - attributesToRetrieve: [ - "objectID", - "endpoint.path", - "endpoint.method", - "endpoint.summary", - "endpoint.description", - "endpoint.operationId", - "endpoint.tags", - "endpoint.deprecated", - "apiType", - ], - attributesToHighlight: ["endpoint.summary", "endpoint.description", "endpoint.path", "endpoint.method"], - attributesToSnippet: ["endpoint.description:50"], - highlightPreTag: "", - highlightPostTag: "", - snippetEllipsisText: "...", - distinct: true, - attributeForDistinct: "endpoint.operationId", - relevancyStrictness: 90, - disableTypoToleranceOnAttributes: ["endpoint.method", "endpoint.path"], - disableTypoToleranceOnWords: ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"], - minWordSizefor1Typo: 4, - minWordSizefor2Typos: 8, - typoTolerance: true, - removeWordsIfNoResults: "lastWords", - advancedSyntax: true, - allowTyposOnNumericTokens: false, - ignorePlurals: true, - removeStopWords: true, - queryLanguages: ["en"], - indexLanguages: ["en"], - camelCaseAttributes: ["endpoint.operationId", "parameters.name", "schemas.properties.name"], - userData: { - indexType: "openapi_reference", - version: "1.0.0", - lastUpdated: new Date().toISOString(), - }, -}; - -const IndexSynonyms: SynonymHit[] = [ - { - objectID: "api-synonyms-1", - type: "synonym", - synonyms: ["create", "post", "add", "new"], - }, - { - objectID: "api-synonyms-2", - type: "synonym", - synonyms: ["update", "put", "patch", "modify", "edit"], - }, - { - objectID: "api-synonyms-3", - type: "synonym", - synonyms: ["delete", "remove", "destroy"], - }, - { - objectID: "api-synonyms-4", - type: "synonym", - synonyms: ["get", "fetch", "retrieve", "read", "list"], - }, - { - objectID: "api-synonyms-5", - type: "synonym", - synonyms: ["auth", "authentication", "authorization", "oauth", "jwt", "token"], - }, - { - objectID: "api-synonyms-6", - type: "synonym", - synonyms: ["param", "parameter", "argument", "input"], - }, - { - objectID: "api-synonyms-7", - type: "synonym", - synonyms: ["response", "output", "result", "return"], - }, - { - objectID: "api-synonyms-8", - type: "synonym", - synonyms: ["schema", "model", "type", "structure"], - }, - { - objectID: "api-synonyms-9", - type: "oneWaySynonym", - input: "404", - synonyms: ["not found", "missing", "does not exist"], - }, - { - objectID: "api-synonyms-10", - type: "oneWaySynonym", - input: "401", - synonyms: ["unauthorized", "not authenticated"], - }, - { - objectID: "api-synonyms-11", - type: "oneWaySynonym", - input: "403", - synonyms: ["forbidden", "not authorized", "access denied"], - }, - { - objectID: "api-synonyms-12", - type: "oneWaySynonym", - input: "200", - synonyms: ["success", "ok", "successful"], - }, -]; diff --git a/scripts/search/index.ts b/scripts/search/index.ts deleted file mode 100644 index 070e2024b0..0000000000 --- a/scripts/search/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ApiReferenceIndex } from "./api-reference-index"; -import { SdkReferenceIndex } from "./sdk-reference-index"; - -const apiReferenceIndex = new ApiReferenceIndex(); -const sdkReferenceIndex = new SdkReferenceIndex(); - -const SearchIndexes = { - [apiReferenceIndex.indexName]: apiReferenceIndex, - [sdkReferenceIndex.indexName]: sdkReferenceIndex, -}; - -async function main() { - const args = process.argv.slice(2); - - if (args.length !== 1) { - console.error("Usage: bun run scripts/search/index.ts "); - process.exit(1); - } - - const indexName = args[0]; - const searchIndex = SearchIndexes[indexName]; - if (!searchIndex) { - console.error(`Invalid index name: ${indexName}`); - process.exit(1); - } - - try { - // await searchIndex.updateDocuments(); - await searchIndex.updateConfiguration(); - } catch (error) { - console.error("❌ Error updating API reference index:", error); - throw error; - } -} - -(async () => { - await main(); -})(); diff --git a/scripts/search/sdk-reference-index.ts b/scripts/search/sdk-reference-index.ts deleted file mode 100644 index 13f3b6b06d..0000000000 --- a/scripts/search/sdk-reference-index.ts +++ /dev/null @@ -1,292 +0,0 @@ -import fs from "fs-extra"; -import { SetSettingsProps, SynonymHit } from "algoliasearch"; -import path from "path"; -import { mkdir, exists } from "node:fs/promises"; -import { resolve, join } from "node:path"; -import { algoliasearch } from "algoliasearch"; -import { $, file, write } from "bun"; - -import { SearchIndex } from "./search-index"; - -import { TypeScriptSymbolExtractor } from "../search/typescript-symbol-extractor"; -import { GoSymbolExtractor } from "../search/go-symbol-extractor"; -import { PythonSymbolExtractor } from "../search/python-symbol-extractor"; -import { SymbolExtractor, Symbol, FunctionSymbol, ClassSymbol } from "../search/types"; -import { BaseSymbolExtractor } from "../search/symbol-extractor"; - -const TMP_DIR_PATH = "./tmp"; - -type Repository = { - url: string; - files: { path: string; namespace: string; extract?: string[] }[]; - name: string; - language: "typescript" | "go" | "python"; -}; - -const SymbolExtractorsMap = { - typescript: TypeScriptSymbolExtractor, - go: GoSymbolExtractor, - python: PythonSymbolExtractor, -} as const; - -export class SdkReferenceIndex extends SearchIndex { - indexName = "supertokens_sdk_references"; - repositories: Repository[] = [ - { - url: "https://github.com/supertokens/supertokens-node", - files: [ - { path: "./lib/ts/index.ts", namespace: "SuperTokens" }, - { path: "./lib/ts/recipe/accountlinking/index.ts", namespace: "AccountLinking" }, - { path: "./lib/ts/recipe/dashboard/index.ts", namespace: "Dashboard" }, - { path: "./lib/ts/recipe/emailpassword/index.ts", namespace: "EmailPassword" }, - { path: "./lib/ts/recipe/emailverification/index.ts", namespace: "EmailVerification" }, - { path: "./lib/ts/recipe/jwt/index.ts", namespace: "JWT" }, - { path: "./lib/ts/recipe/multifactorauth/index.ts", namespace: "MultiFactorAuth" }, - { path: "./lib/ts/recipe/multitenancy/index.ts", namespace: "MultiTenancy" }, - { path: "./lib/ts/recipe/oauth2provider/index.ts", namespace: "OAuth2Provider" }, - { path: "./lib/ts/recipe/openid/index.ts", namespace: "OpenID" }, - { path: "./lib/ts/recipe/passwordless/index.ts", namespace: "Passwordless" }, - { path: "./lib/ts/recipe/session/index.ts", namespace: "Session" }, - { path: "./lib/ts/recipe/thirdparty/index.ts", namespace: "ThirdParty" }, - { path: "./lib/ts/recipe/totp/index.ts", namespace: "TOTP" }, - { path: "./lib/ts/recipe/usermetadata/index.ts", namespace: "UserMetadata" }, - { path: "./lib/ts/recipe/userroles/index.ts", namespace: "UserRoles" }, - { path: "./lib/ts/recipe/webauthn/index.ts", namespace: "WebAuthn" }, - ], - name: "supertokens-node", - language: "typescript", - }, - { - url: "https://github.com/supertokens/supertokens-auth-react", - files: [ - { path: "./lib/ts/index.ts", namespace: "SuperTokens" }, - { path: "./lib/ts/recipe/emailpassword/index.ts", namespace: "EmailPassword" }, - { path: "./lib/ts/recipe/emailverification/index.ts", namespace: "EmailVerification" }, - { path: "./lib/ts/recipe/multifactorauth/index.ts", namespace: "MultiFactorAuth" }, - { path: "./lib/ts/recipe/multitenancy/index.ts", namespace: "MultiTenancy" }, - { path: "./lib/ts/recipe/oauth2provider/index.ts", namespace: "OAuth2Provider" }, - { path: "./lib/ts/recipe/passwordless/index.ts", namespace: "Passwordless" }, - { path: "./lib/ts/recipe/session/index.ts", namespace: "Session" }, - { path: "./lib/ts/recipe/thirdparty/index.ts", namespace: "ThirdParty" }, - { path: "./lib/ts/recipe/totp/index.ts", namespace: "TOTP" }, - { path: "./lib/ts/recipe/userroles/index.ts", namespace: "UserRoles" }, - { path: "./lib/ts/recipe/webauthn/index.ts", namespace: "WebAuthn" }, - ], - name: "supertokens-node", - language: "typescript", - }, - { - url: "https://github.com/supertokens/supertokens-web-js", - files: [ - { path: "./lib/ts/index.ts", namespace: "SuperTokens" }, - { path: "./lib/ts/recipe/emailpassword/index.ts", namespace: "EmailPassword" }, - { path: "./lib/ts/recipe/emailverification/index.ts", namespace: "EmailVerification" }, - { path: "./lib/ts/recipe/multifactorauth/index.ts", namespace: "MultiFactorAuth" }, - { path: "./lib/ts/recipe/multitenancy/index.ts", namespace: "MultiTenancy" }, - { path: "./lib/ts/recipe/oauth2provider/index.ts", namespace: "OAuth2Provider" }, - { path: "./lib/ts/recipe/passwordless/index.ts", namespace: "Passwordless" }, - { path: "./lib/ts/recipe/session/index.ts", namespace: "Session" }, - { path: "./lib/ts/recipe/thirdparty/index.ts", namespace: "ThirdParty" }, - { path: "./lib/ts/recipe/totp/index.ts", namespace: "TOTP" }, - { path: "./lib/ts/recipe/userroles/index.ts", namespace: "UserRoles" }, - { path: "./lib/ts/recipe/webauthn/index.ts", namespace: "WebAuthn" }, - ], - name: "supertokens-node", - language: "typescript", - }, - ]; - - async updateDocuments(): Promise { - const documents: SDKReferenceDocument[] = []; - - console.log("Initializing SDK indexer"); - const tmpDirPath = "./tmp"; - const tmpDirExists = await exists(tmpDirPath); - if (!tmpDirExists) { - mkdir(tmpDirPath); - } - - for (const repository of this.repositories) { - console.log(`Extracting symbols from ${repository.name}`); - await this.cloneRepository(repository); - const symbols = this.extractSymbols(repository); - console.log(`Transforming documents`); - const repositoryDocuments = this.transformSymbolsToDocuments(symbols, repository); - documents.push(...repositoryDocuments); - } - - console.log(`Updating index`); - await this.client.clearObjects({ indexName: this.indexName }); - const responses = await this.client.saveObjects({ - indexName: this.indexName, - objects: documents, - }); - } - - async updateConfiguration(): Promise { - await this.client.setSettings({ - indexName: this.indexName, - indexSettings: IndexSettings, - forwardToReplicas: true, - }); - await this.client.saveSynonyms({ - indexName: this.indexName, - synonymHit: IndexSynonyms, - forwardToReplicas: true, - replaceExistingSynonyms: true, - }); - } - - private async cloneRepository(repository: Repository): Promise { - const repositoryDirectoryPath = `./tmp/${repository.name}`; - const repositoryDirectoryExists = await exists(repositoryDirectoryPath); - if (repositoryDirectoryExists) { - return; - } - console.log(`Cloning ${repository.url}`); - await $`git clone ${repository.url} ${repository.name} --depth 1`.cwd("./tmp"); - } - - private extractSymbols(repository: Repository): Symbol[] { - const ExtractorClass = SymbolExtractorsMap[repository.language]; - if (!ExtractorClass) throw new Error(`No extractor found for language ${repository.language}`); - const extractor = new ExtractorClass( - repository.files.map((f) => ({ - namespace: f.namespace, - path: resolve(`${TMP_DIR_PATH}/${repository.name}/${f.path}`), - })), - ); - return extractor.extract(); - } - - private transformSymbolsToDocuments(symbols: Symbol[], repository: Repository): SDKReferenceDocument[] { - return repository.files - .map((file) => { - const absolutePath = resolve(`${TMP_DIR_PATH}/${repository.name}/${file.path}`); - const symbolsInFile = symbols.filter((symbol) => symbol.file === absolutePath); - const relativePath = file.path.replace(`${TMP_DIR_PATH}/${repository.name}/`, ""); - - return symbolsInFile - .map((symbol) => { - const meta: Record = symbol.meta || {}; - const docs: SDKReferenceDocument[] = []; - - switch (symbol.type) { - case "function": - const funcSymbol = symbol as FunctionSymbol; - docs.push({ - objectID: `${repository.language}-${symbol.name}-${relativePath}-${symbol.line}`, - name: symbol.name, - type: symbol.type, - language: repository.language, - repository: repository.name, - content: symbol.content, - file: relativePath, - line: symbol.line, - comments: symbol.comments || undefined, - namespace: symbol.namespace, - returnType: funcSymbol.meta?.returnType, - tags: [], - signature: funcSymbol.meta?.parameters - ?.map((p) => `${p.name}: ${p.optional ? "?" : ""}${p.type}`) - .join(", "), - parameters: funcSymbol.meta?.parameters, - deprecated: symbol.deprecated, - }); - break; - case "class": - const classSymbol = symbol as ClassSymbol; - docs.push( - ...classSymbol.meta.methods.map((method) => ({ - objectID: `${repository.language}-${method.name}-${relativePath}-${method.line}`, - name: method.name, - type: "method" as SDKReferenceDocument["type"], - language: repository.language, - repository: repository.name, - content: method.content, - signature: method.parameters?.map((p) => `${p.name}: ${p.type}${p.optional ? "?" : ""}`).join(", "), - parameters: method.parameters, - file: relativePath, - line: method.line, - comments: method.comments || undefined, - returnType: method.returnType, - deprecated: method.deprecated, - namespace: classSymbol.namespace, - tags: [], - })), - ); - break; - } - return docs; - }) - .flat(); - }) - .flat(); - } -} - -interface SDKReferenceDocument extends Record { - objectID: string; - name: string; - type: "variable" | "function" | "class" | "type" | "method"; - language: "typescript" | "go" | "python"; - repository: string; - file: string; - line: number; - content: string; - comments?: string; - signature?: string; - returnType?: string; - parameters?: Array<{ name: string; type: string; optional?: boolean }>; - className?: string; - namespace: string; - tags: string[]; - deprecated: boolean; - version?: string; -} - -const IndexSettings: SetSettingsProps["indexSettings"] = { - searchableAttributes: ["name", "namespace"], - attributesForFaceting: ["type", "language", "className", "namespace", "tags", "deprecated"], - customRanking: ["asc(name)"], - ranking: ["typo", "geo", "words", "filters", "proximity", "attribute", "exact", "custom"], - attributesToRetrieve: [ - "objectID", - "name", - "signature", - "returnType", - "namespace", - "line", - "file", - "deprecated", - "language", - "type", - "repository", - ], - attributesToHighlight: ["name", "namespace"], - attributesToSnippet: ["signature:50"], - disableTypoToleranceOnAttributes: ["name", "namespace"], - highlightPreTag: "", - highlightPostTag: "", - snippetEllipsisText: "…", - queryLanguages: ["en"], - indexLanguages: ["en"], - userData: { - indexType: "sdk_reference", - version: "1.0.0", - lastUpdated: new Date().toISOString(), - }, -}; - -const IndexSynonyms: SynonymHit[] = [ - { - objectID: "sdk-synonyms-1", - type: "synonym", - synonyms: ["multifactorauth", "mfa", "multi-factor authentication", "multifactor authentication"], - }, - { - objectID: "api-synonyms-2", - type: "synonym", - synonyms: ["multi-tenant", "multitenant"], - }, -]; diff --git a/scripts/search/search-index.ts b/scripts/search/search-index.ts deleted file mode 100644 index 1b0b30c123..0000000000 --- a/scripts/search/search-index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { algoliasearch, Algoliasearch } from "algoliasearch"; - -const APPLICATION_ID = process.env.ALGOLIA_APPLICATION_ID; -const API_KEY = process.env.ALGOLIA_ADMIN_API_KEY; - -export abstract class SearchIndex { - client: Algoliasearch; - abstract indexName: string; - - constructor() { - if (!APPLICATION_ID || !API_KEY) { - throw new Error("Missing required environment variables: ALGOLIA_APP_ID or ALGOLIA_ADMIN_API_KEY"); - } - this.client = algoliasearch(APPLICATION_ID, API_KEY); - } - - abstract updateDocuments(): Promise; - abstract updateConfiguration(): Promise; -} diff --git a/sidebars.ts b/sidebars.ts deleted file mode 100644 index 899c8be01d..0000000000 --- a/sidebars.ts +++ /dev/null @@ -1,64 +0,0 @@ -import type { SidebarsConfig } from "@docusaurus/plugin-content-docs"; - -// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) -const sidebars: SidebarsConfig = { - docs: [ - { type: "doc", id: "index" }, - { - type: "category", - label: "Quickstart", - customProps: { isMainCategory: true }, - items: [ - { - type: "autogenerated", - dirName: "quickstart", - }, - ], - }, - { - type: "category", - label: "Authentication", - customProps: { isMainCategory: true }, - collapsed: true, - items: [ - { - type: "autogenerated", - dirName: "authentication", - }, - ], - }, - { - type: "category", - label: "Additional Verification", - customProps: { isMainCategory: true }, - items: [{ type: "autogenerated", dirName: "additional-verification" }], - }, - { - type: "category", - label: "Post Authentication", - customProps: { isMainCategory: true }, - items: [{ type: "autogenerated", dirName: "post-authentication" }], - }, - { - type: "category", - label: "Migration", - customProps: { isMainCategory: true }, - items: [{ type: "autogenerated", dirName: "migration" }], - }, - { - type: "category", - label: "Platform Configuration", - customProps: { isMainCategory: true }, - items: [{ type: "autogenerated", dirName: "platform-configuration" }], - }, - { - type: "category", - label: "Deployment", - customProps: { isMainCategory: true }, - items: [{ type: "autogenerated", dirName: "deployment" }], - }, - ], - references: [{ type: "autogenerated", dirName: "references" }], -}; - -export default sidebars; diff --git a/src/components/APIRequest/APIRequest.scss b/src/components/APIRequest/APIRequest.scss deleted file mode 100644 index 5ce67cb05d..0000000000 --- a/src/components/APIRequest/APIRequest.scss +++ /dev/null @@ -1,282 +0,0 @@ -.api-request { -} - -.api-request-accordion { - &__item-2 { - &:hover { - outline: 2px solid var(--gray-7); - outline-offset: -1px; - } - - &:first-child { - border-top-left-radius: var(--card-border-radius); - border-top-right-radius: var(--card-border-radius); - } - - &:last-child { - border-bottom-left-radius: var(--card-border-radius); - border-bottom-right-radius: var(--card-border-radius); - } - - &:not(:last-child) { - border-bottom: 1px solid var(--gray-a6); - } - } - - &__item { - &[data-border="true"] { - border-bottom: 1px solid var(--gray-a6); - - &:hover { - border-bottom-color: var(--gray-7); - } - } - } - - &__trigger { - cursor: pointer; - - &:first-child, - &:last-child { - padding-top: var(--space-3); - padding-bottom: var(--space-3); - } - - border-bottom: 1px solid var(--gray-a6); - - &:hover { - border-bottom-color: var(--gray-7); - - .api-request-accordion__icon { - color: var(--gray-12); - } - } - - &[data-border="false"] { - border-bottom: none; - &:hover { - border-bottom: none; - } - } - - &[data-state="open"] > .api-request-accordion__icon { - transform: rotate(0deg); - } - } - - &__icon { - color: var(--gray-11); - transform: rotate(-90deg); - transition: transform 300ms cubic-bezier(0.87, 0, 0.13, 1); - width: 18px; - height: 18px; - } - - &__content { - // &[data-state="open"] { - // animation: slideDown 300ms cubic-bezier(0.87, 0, 0.13, 1); - // } - // - // &[data-state="closed"] { - // animation: slideUp 300ms cubic-bezier(0.87, 0, 0.13, 1); - // } - - .rt-BaseTabList, - .rt-TabsList { - border-radius: 0 !important; - &::before { - border-radius: 0 !important; - } - } - .rt-TabsRoot { - // There's an additional spacing that gets created - // probably because of the hidden content - margin-bottom: -15px !important; - } - } - - @keyframes slideDown { - from { - height: 0; - opacity: 0; - } - to { - height: var(--radix-accordion-content-height); - opacity: 1; - } - } - - @keyframes slideUp { - from { - height: var(--radix-accordion-content-height); - opacity: 1; - } - to { - opacity: 0; - height: 0; - } - } -} - -.api-request-parameters-card { - &__parameter { - &:not(:last-child) { - border-bottom: 1px solid var(--gray-a6); - } - } -} - -.api-request-property-example { - cursor: pointer; - position: relative; - - input { - cursor: pointer; - } - - &__hover-card { - div { - margin-bottom: 0; - } - } - - &__icon { - position: absolute; - display: none; - left: -25px; - top: 5px; - width: 20px; - height: 20px; - } - - &:hover { - .api-request-property-example__input { - outline: 1px solid var(--gray-7); - } - - .api-request-property-example__icon { - display: block; - } - } -} - -.api-request-code-snippet, -.api-request-response-preview { - .theme-code-block { - margin-bottom: 0; - box-shadow: none; - border: none; - pre { - border-radius: 0; - } - overflow-y: auto; - max-height: 500px; - } -} - -.api-request-path-title { - cursor: pointer; - min-width: 0; - flex: 1; - - code { - white-space: nowrap; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - } - - &__icon { - display: none; - width: 25px; - height: 25px; - } - - &:hover { - .api-request-path-title__icon { - display: block; - } - } -} - -// API Request Client -.scalar-app { - .scalar-container { - background: var(--black-a8); - } - - ul[role="listbox"] { - li { - & > div { - margin: 0; - } - - & > span { - margin: 0; - } - - &:before { - content: none; - } - } - - li[class*="group/item"] { - min-height: 30px; - } - div[id^="scalar-combobox-items-scalar-client-"] { - min-height: 30px; - } - } - h1 { - font-size: var(--scalar-font-size-1) !important; - line-height: var(--scalar-line-height-1) !important; - } - - h2 { - font-size: var(--scalar-font-size-2) !important; - line-height: var(--scalar-line-height-2) !important; - } - - h3 { - font-size: var(--scalar-font-size-3) !important; - line-height: var(--scalar-line-height-3) !important; - } - - h4 { - font-size: var(--scalar-font-size-4) !important; - line-height: var(--scalar-line-height-4) !important; - } - - h5 { - font-size: var(--scalar-font-size-5) !important; - line-height: var(--scalar-line-height-5) !important; - } - - h6 { - font-size: var(--scalar-font-size-6) !important; - line-height: var(--scalar-line-height-6) !important; - } - - td { - border-color: var(--gray-6) !important; - } - tr { - border-color: var(--gray-6) !important; - } - - button[aria-expanded="true"] { - border-color: var(--gray-6) !important; - } -} - -:root { - --scalar-color-1: var(--gray-12); - --scalar-color-2: var(--gray-11); - --scalar-color-3: var(--gray-10); - --scalar-color-accent: var(--orange-11); - --scalar-background-1: var(--color-background); - --scalar-background-2: var(--gray-2); - --scalar-background-3: var(--gray-3); - --scalar-background-accent: var(--accent-a3); - --scalar-border-color: var(--gray-6); -} diff --git a/src/components/APIRequest/APIRequest.tsx b/src/components/APIRequest/APIRequest.tsx deleted file mode 100644 index 821ad3b03d..0000000000 --- a/src/components/APIRequest/APIRequest.tsx +++ /dev/null @@ -1,753 +0,0 @@ -import { Badge, Card, Text, Code, Skeleton, Flex, Heading, HoverCard, Box, Separator, Callout } from "@radix-ui/themes"; -import { DocItemContext } from "@site/src/context"; -import { ApiClientModalProvider, useApiClientModal } from "@scalar/api-client-react"; -import InfoCircledIcon from "/img/icons/info-circled.svg"; -import CopyIcon from "/img/icons/copy.svg"; -import CheckIcon from "/img/icons/check.svg"; -import ExclamationTriangleIcon from "/img/icons/exclamation-triangle.svg"; -import { useDocPageData, useLoadOpenApiDocument } from "@site/src/hooks"; -import { normalizePath } from "@site/src/lib"; -import Link from "@docusaurus/Link"; -import { APIRequestMethod } from "@site/src/types"; -import ChevronDownIcon from "/img/icons/chevron-down.svg"; -import { createContext, useCallback, useContext, useMemo, useState } from "react"; -import { APIRequestParametersCard } from "./APIRequestParametersCard"; -import * as Accordion from "@radix-ui/react-accordion"; -import { APIRequestSchemaCard } from "./APIRequestSchemaCard"; -import type { OpenAPIV3 } from "@scalar/openapi-types"; -import "@scalar/api-client-react/style.css"; - -import "./APIRequest.scss"; - -type APIRequestContextType = { - path: string; - formattedPath: string; - method: APIRequestMethod; - security: OpenAPIV3.Document["components"]["securitySchemes"] | null; - title: string; - operation: OpenAPIV3.OperationObject | null; - apiName: "fdi" | "cdi"; -}; - -export const APIRequestContext = createContext({} as APIRequestContextType); - -export function APIRequestProvider({ - children, - apiName, - path, - method, - title, -}: { - children: React.ReactNode; - apiName: "fdi" | "cdi"; - path: string; - method: APIRequestMethod; - title: string; -}) { - const { appInfo } = useContext(DocItemContext); - const tenantType = useDocPageData("tenantType"); - const apiBasePath = appInfo.apiBasePath || "/auth"; - - const document = useLoadOpenApiDocument(apiName); - - const operation = useMemo(() => { - if (!document) return null; - return document.paths[path][method] as OpenAPIV3.OperationObject; - }, [document, path, method]); - - const securitySchemes = useMemo(() => { - if (!document) return null; - return document.components?.securitySchemes; - }, [document]); - - const formattedPath = useMemo(() => { - if (apiName === "fdi") return buildFDIFormattedPath(path, apiBasePath, tenantType); - return path; - }, [path, appInfo, tenantType, apiName]); - - return ( - - {children} - - ); -} - -function buildFDIFormattedPath(path: string, apiBasePath: string, tenantType: "single-tenant" | "multi-tenant") { - return tenantType === "multi-tenant" - ? `${apiBasePath}/${normalizePath(path)}` - : `${apiBasePath}${normalizePath(path)}`; -} - -export function APIRequestTitle() { - const { title } = useContext(APIRequestContext); - - return ( - - {title} - - ); -} - -import Markdown from "react-markdown"; -import { APIRequestClient } from "./APIRequestClient"; - -export function APIRequestDescription() { - const { operation } = useContext(APIRequestContext); - - if (!operation) return null; - if (!operation.description) return null; - - // TODO: This is a temp solution. Need to figure out how to use mdx-js - return ( - - {operation.description} - - ); -} - -const MethodToColorMap: Record = { - get: "green", - delete: "red", - post: "blue", - put: "orange", - patch: "yellow", - options: "gray", - head: "gray", - trace: "gray", -}; - -export function APIRequestMethodBadge({ - size = "3", - method, -}: Pick, "size"> & { method: APIRequestMethod }) { - return ( - - {method.toUpperCase()} - - ); -} - -export function APIRequestPath() { - const { path, method } = useContext(APIRequestContext); - const [hasCopied, setHasCopied] = useState(false); - - const IconComponent = hasCopied ? CheckIcon : CopyIcon; - - const copyToClipboard = useCallback(() => { - navigator.clipboard.writeText(path); - setHasCopied(true); - }, [path]); - - return ( - - - - - {method.toUpperCase()} - - setHasCopied(false)} - onClick={copyToClipboard} - className="api-request-path-title" - > - - {path} - - - - - - - ); -} - -export function APIRequestPathParameters() { - const { operation: schema } = useContext(APIRequestContext); - - const pathParameters = useMemo(() => { - if (!schema || !schema.parameters) return null; - return schema.parameters.filter((param) => param.in === "path") as OpenAPIV3.ParameterObject[]; - }, [schema]); - - if (!pathParameters || pathParameters.length === 0) return null; - - return ( - - - Path parameters - - - - - ); -} - -export function APIRequestQueryParameters() { - const { operation: schema } = useContext(APIRequestContext); - - const queryParameters = useMemo(() => { - if (!schema || !schema.parameters) return null; - return schema.parameters.filter((param) => param.in === "query") as OpenAPIV3.ParameterObject[]; - }, [schema]); - - if (!queryParameters || queryParameters.length === 0) return null; - - return ( - - - Query parameters - - - - - ); -} - -export function APIRequestHeaderParameters() { - const { operation: schema } = useContext(APIRequestContext); - - const headerParameters = useMemo(() => { - if (!schema || !schema.parameters) return null; - return schema.parameters.filter((param) => param.in === "header") as OpenAPIV3.ParameterObject[]; - }, [schema]); - - if (!headerParameters || headerParameters.length === 0) return null; - - return ( - - - Headers - - - - - ); -} - -export function APIRequestBody() { - const { operation } = useContext(APIRequestContext); - - if (!operation || !operation.requestBody) return null; - const requestBody = operation.requestBody as OpenAPIV3.RequestBodyObject; - if (!requestBody.content || Object.keys(requestBody.content).length === 0) return null; - - const mediaTypeObject = requestBody.content["application/json"]; - if (!mediaTypeObject) return null; - - const bodySchema = mediaTypeObject.schema as OpenAPIV3.SchemaObject; - - if (bodySchema.type === "array") { - return ( - - - Body - - - - Use one of the following schemas: - - - - {bodySchema.items.map((schemaOption, index) => { - const itemSchema = schemaOption as OpenAPIV3.SchemaObject; - return ( - <> - - - - {index !== bodySchema.length - 1 && ( - - - - OR - - - - )} - - ); - })} - - - ); - } - - if (bodySchema.type === "object" && !bodySchema.properties) { - return null; - } - - if (bodySchema.oneOf) { - return ( - - - Body - - - - - One of the following schemas can be used: - - - - - {bodySchema.oneOf.map((schema, index) => { - const typedSchema = schema as OpenAPIV3.SchemaObject; - return ( - - - - - - - - {index !== bodySchema.oneOf.length - 1 && ( - - - - OR - - - - )} - - ); - })} - - - ); - } - - return ( - - - Body - - - - - ); -} - -export function APIRequestResponse() { - const { operation } = useContext(APIRequestContext); - - if (!operation) return null; - if (!operation.responses) return null; - const statusCodes = Object.keys(operation.responses); - if (!statusCodes.length) return null; - - return ( - - - Responses - - - - {statusCodes.map((statusCode, index) => { - const response = operation.responses[statusCode] as OpenAPIV3.ResponseObject; - - const hasContent = response.content && Object.keys(response.content).length > 0; - const hasHeaders = response?.headers && Object.keys(response.headers).length > 0; - - const firstContentType = hasContent ? Object.keys(response.content)[0] : null; - const content = hasContent ? response.content[firstContentType] : null; - - let statusCodeColor: "green" | "red" = "green"; - if (statusCode.startsWith("4") || statusCode.startsWith("5")) statusCodeColor = "red"; - - return ( - - - - - - - - {statusCode} - - - - {response.description} - - - - - - - {firstContentType || "application/json"} - - - - - - - {hasContent && } - {hasHeaders && ( - - - - Headers - - - After a successful request, the following headers will be set. - - - - - ({ - name: key, - ...response.headers[key], - })) as OpenAPIV3.ParameterObject[] - } - /> - - - - )} - - - - ); - })} - - - ); -} - -function APIRequestResponseBody({ - mediaTypeObject, - mediaType, -}: { - mediaTypeObject: OpenAPIV3.MediaTypeObject; - mediaType: string; -}) { - const bodySchema = mediaTypeObject.schema as OpenAPIV3.SchemaObject; - - if (!bodySchema) return null; - - if (mediaType !== "application/json" && bodySchema.enum) { - return ( - - {bodySchema.enum[0]} - - ); - } - - if (bodySchema.oneOf) { - return ( - <> - - - One of the following body schemas will be returned: - - - - {bodySchema.oneOf.map((schema, index) => { - const typedSchema = schema as OpenAPIV3.SchemaObject; - return ( - - - - - - - {index !== bodySchema.oneOf.length - 1 && ( - - - - OR - - - - )} - - ); - })} - - - ); - } - - if (bodySchema.type === "array") { - return ( - <> - - - One of the following body schemas will be returned: - - - - {bodySchema.items.map((schema, index) => { - const typedSchema = schema as OpenAPIV3.SchemaObject; - return ( - - - - - - - {index !== bodySchema.items.length - 1 && ( - - - - OR - - - - )} - - ); - })} - - - ); - } - - return ( - <> - - Body - - - - - - - - - ); -} - -export function APIRequestApiTypeBadge() { - const { apiName } = useContext(APIRequestContext); - - return ( - - - - - {apiName.toUpperCase()} - - - - - - - - - - - - - {apiName.toUpperCase()} Endpoint - - - {apiName === "cdi" ? ( - <> - The endpoint is part of the{" "} - - Core Driver Interface - {" "} - API. It's exposed by the SuperTokens Core service and you should only use it from your backend - applications. - - ) : ( - <> - This endpoint is part of the{" "} - - Frontend Driver Interface - {" "} - API. It's exposed by the SuperTokens Backend SDKs and you should only use it from your frontend - applications. - - )} - - - - - - - - ); -} - -export function APIRequestDeprecatedCallout() { - const { operation } = useContext(APIRequestContext); - - if (!operation) return null; - if (!operation.deprecated) return null; - - return ( - - - - - - - - - - Deprecated - - This endpoint is deprecated. Please use the newer version. - - - - ); -} - -export function APIRequestSecuritySection() { - const { operation, security } = useContext(APIRequestContext); - - const securityRequirements = useMemo(() => { - if (!operation) return []; - if (!operation.security) return []; - if (!security) return []; - - return operation.security - .map((securityRequirement) => { - const requirementName = Object.keys(securityRequirement)[0]; - const req = security[requirementName] as OpenAPIV3.SecuritySchemeObject | null; - return req; - }) - .filter((v) => v); - }, [security]); - - return ( - - - - - - {securityRequirements.length > 0 && ( - - )} - - - - Authorization - - - - - - {securityRequirements.length ? "Required" : "None"} - - - - - - - {securityRequirements.map((securityRequirement, index) => { - return ; - })} - - - - - - ); -} - -function APISecuritySchemeItem({ scheme }: { scheme: OpenAPIV3.SecuritySchemeObject }) { - if (scheme.type === "http") { - return ( - - - - - {scheme.scheme} - - - - {scheme.type} - - - - {scheme.description} - - - - ); - } - - if (scheme.type === "apiKey") { - return ( - - - - - {scheme.name} - - - - {scheme.in} - - - - {scheme.description} - - - - ); - } - - return null; -} - -export function APIRequestSkeleton({ children }: { children?: React.ReactNode }) { - const { operation, title } = useContext(APIRequestContext); - - if (operation) return children; - - return ( - - - - {title} - - - - - - - {" "} - - - - - - ); -} diff --git a/src/components/APIRequest/APIRequestClient.tsx b/src/components/APIRequest/APIRequestClient.tsx deleted file mode 100644 index 7345665ef0..0000000000 --- a/src/components/APIRequest/APIRequestClient.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { useCallback, useContext, forwardRef, ReactNode, useEffect, useMemo, useState, createContext } from "react"; -import { APIRequestContext } from "./APIRequest"; -import { useDocPageData, useLoadOpenApiDocument } from "@site/src/hooks"; -import { ApiClientModalProvider, useApiClientModal } from "@scalar/api-client-react"; - -import type { OpenAPIV3 } from "@scalar/openapi-types"; -import { Slot } from "@radix-ui/themes"; -import { replaceVariablesForScalar, replaceVariablesInApiPath } from "@site/src/lib"; - -type ScalarContextType = { - path: string; - method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS" | "HEAD"; -}; - -const ScalarContext = createContext({} as ScalarContextType); - -function APIRequestClientProvider({ children }: { children: React.ReactNode }) { - const { apiName, path, method } = useContext(APIRequestContext); - const apiDocument = useLoadOpenApiDocument(apiName); - const apiDomain = useDocPageData("apiDomain"); - const apiBasePath = useDocPageData("apiBasePath"); - const coreDomain = useDocPageData("coreDomain"); - const tenantId = useDocPageData("tenantId"); - const appId = useDocPageData("appId"); - - const parsedApiDocument = useMemo(() => { - if (!apiDocument) return null; - - return replaceVariablesForScalar(apiDocument, apiName, { - apiDomain, - apiBasePath, - coreDomain, - tenantId, - appId, - }); - }, [apiDocument, apiDomain, apiName, coreDomain, apiBasePath, tenantId, appId]); - - const parsedPath = useMemo(() => { - return replaceVariablesInApiPath(path, { apiBasePath, tenantId, appId }); - }, [path, apiBasePath, tenantId, appId]); - - if (!apiDocument) return children; - - return ( - - {children} - - ); -} - -const APIRequestClientTrigger = forwardRef( - function APIRequestClientTrigger(props, ref) { - const { children } = props; - const { path, method } = useContext(ScalarContext); - const client = useApiClientModal(); - - useEffect(() => { - if (!client) return; - const mountingEl = document.getElementById("docusaurus-scalar-root"); - client.mount(mountingEl); - }, [client]); - - const onClick = useCallback(() => { - client.open({ path, method }); - }, [client, path, method]); - - return ( - - {children} - - ); - }, -); - -export const APIRequestClient = { - Provider: APIRequestClientProvider, - Trigger: APIRequestClientTrigger, -}; diff --git a/src/components/APIRequest/APIRequestCodeSnippet.tsx b/src/components/APIRequest/APIRequestCodeSnippet.tsx deleted file mode 100644 index 90780eab44..0000000000 --- a/src/components/APIRequest/APIRequestCodeSnippet.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { Text, Flex, Button, Select, Card, Separator } from "@radix-ui/themes"; -import { useDocPageData, useLoadOpenApiDocument } from "@site/src/hooks"; -import { - DocPageState, - docPageStore, - generateCodeSnippetFromAPIRequest, - replaceVariablesForScalar, - replaceVariablesInApiPath, -} from "@site/src/lib"; -import CodeBlock from "@site/src/theme/CodeBlock"; -import { useCallback, useContext, useMemo } from "react"; -import { useApiClientModal } from "@scalar/api-client-react"; -import { APIRequestContext } from "./APIRequest"; -import * as z from "zod"; -import { APIRequestClient } from "./APIRequestClient"; -import { APIRequestEditParametersModal } from "./APIRequestEditParametersModal"; -import { Play, Edit } from "lucide-react"; - -export function APIRequestCodeSnippetSegmentedControl() { - const language = useDocPageData("apiRequestExampleLanguage"); - const { apiName } = useContext(APIRequestContext); - const apiDomain = useDocPageData("apiDomain"); - const coreDomain = useDocPageData("coreDomain"); - const apiDocument = useLoadOpenApiDocument(apiName); - - const { path, method } = useContext(APIRequestContext); - const apiClient = useApiClientModal(); - - const title = useMemo(() => { - if (language === "shell") return "Curl Example"; - if (language === "nodejs") return "Fetch Example"; - if (language === "python") return "Requests Example"; - if (language === "go") return "HTTP Example"; - }, [language]); - - const shouldConfigureServer = useMemo(() => { - const server = apiName === "fdi" ? apiDomain : coreDomain; - return !z.string().url().safeParse(server).success; - }, [apiName, apiDomain, coreDomain]); - - const onEditConfigurationSuccess = useCallback( - async (data) => { - if (!apiClient) return; - await apiClient.updateConfig({ - content: replaceVariablesForScalar(apiDocument, apiName, data), - }); - if (!shouldConfigureServer) return; - apiClient.open({ path: replaceVariablesInApiPath(path, data), method }); - }, - [shouldConfigureServer, apiClient, path, method, apiDocument, apiName], - ); - - return ( - - - - - {title} - - - - docPageStore.updateValue("apiRequestExampleLanguage", value as DocPageState["apiRequestExampleLanguage"]) - } - > - - - Shell - Javascript - Python - Go - - - - - - - - - - - - - - {shouldConfigureServer ? ( - - - - ) : ( - - - - )} - - - - - ); -} - -function CodeSnippetSection({ language }: { language: DocPageState["apiRequestExampleLanguage"] }) { - const { operation, security, method, path, apiName } = useContext(APIRequestContext); - const apiRequestExampleLanguage = useDocPageData("apiRequestExampleLanguage"); - const apiDomain = useDocPageData("apiDomain"); - const coreDomain = useDocPageData("coreDomain"); - const apiBasePath = useDocPageData("apiBasePath"); - const tenantId = useDocPageData("tenantId"); - const appId = useDocPageData("appId"); - const codeBlockLanguage = useMemo(() => { - if (language === "shell") return "bash"; - if (language === "nodejs") return "typescript"; - if (language === "python") return "python"; - if (language === "go") return "go"; - }, [language]); - const parsedPath = useMemo(() => { - return replaceVariablesInApiPath(path, { apiBasePath, tenantId, appId }); - }, [path, apiBasePath, tenantId, appId]); - - const host = useMemo(() => { - const url = apiName === "fdi" ? apiDomain : coreDomain; - return url.endsWith("/") ? url.slice(0, -1) : url; - }, [apiName, apiDomain, coreDomain]); - - const snippet = useMemo(() => { - if (!operation) return null; - return generateCodeSnippetFromAPIRequest({ - host, - operation, - environment: language, - method, - security, - path: parsedPath, - }); - }, [operation, method, path, language]); - - if (!operation) return null; - if (language !== apiRequestExampleLanguage) return null; - - return {snippet}; -} diff --git a/src/components/APIRequest/APIRequestEditParametersModal.tsx b/src/components/APIRequest/APIRequestEditParametersModal.tsx deleted file mode 100644 index 02769ad753..0000000000 --- a/src/components/APIRequest/APIRequestEditParametersModal.tsx +++ /dev/null @@ -1,248 +0,0 @@ -import { useState, useCallback, useContext, useMemo, forwardRef, ReactNode, createContext } from "react"; -import { Button, Flex, Text, Heading, TextField, Separator, Dialog, Slot } from "@radix-ui/themes"; -import * as Form from "@radix-ui/react-form"; -import { useDocPageData } from "@site/src/hooks"; -import { DOC_PAGE_STORE_DEFAULT_VALUES, docPageStore } from "@site/src/lib"; -import { APIRequestContext } from "./APIRequest"; -import type { OpenAPIV3 } from "@scalar/openapi-types"; - -type FormData = { - apiDomain: string; - apiBasePath: string; - coreDomain: string; - tenantId: string; - appId: string; -}; - -type APIRequestEditParametersModalContextType = { - isOpen: boolean; - setIsOpen: (value: boolean) => void; -}; - -const APIRequestEditParametersModalContext = createContext( - {} as APIRequestEditParametersModalContextType, -); - -function APIRequestEditParametersModalContent({ onSuccess }: { onSuccess: (data: FormData) => void }) { - const { apiName } = useContext(APIRequestContext); - const { setIsOpen } = useContext(APIRequestEditParametersModalContext); - - const apiDomain = useDocPageData("apiDomain"); - const apiBasePath = useDocPageData("apiBasePath"); - const coreDomain = useDocPageData("coreDomain"); - const tenantId = useDocPageData("tenantId"); - const appId = useDocPageData("appId"); - - const [formValues, setFormValues] = useState({ - apiDomain: apiDomain === DOC_PAGE_STORE_DEFAULT_VALUES.apiDomain ? "" : apiDomain, - apiBasePath, - coreDomain: coreDomain === DOC_PAGE_STORE_DEFAULT_VALUES.coreDomain ? "" : coreDomain, - tenantId, - appId, - }); - - const onChangeInputValue = useCallback((field: string, value: string) => { - setFormValues((prev) => ({ ...prev, [field]: value })); - }, []); - - const handleSave = useCallback(() => { - docPageStore.updateValue("apiDomain", formValues.apiDomain); - docPageStore.updateValue("apiBasePath", formValues.apiBasePath); - docPageStore.updateValue("coreDomain", formValues.coreDomain); - docPageStore.updateValue("tenantId", formValues.tenantId); - docPageStore.updateValue("appId", formValues.appId); - - onSuccess(formValues); - }, [formValues, onSuccess]); - - const onKeyDown = useCallback( - (e) => { - if (e.key === "/") { - // Prevent triggering the search modal - e.stopPropagation(); - } - - if (e.key === "Enter") { - handleSave(); - setIsOpen(false); - } - }, - [handleSave], - ); - - const handleCancel = useCallback(() => { - setFormValues({ - apiDomain, - apiBasePath, - coreDomain, - tenantId, - appId, - }); - }, [apiDomain, apiBasePath, coreDomain, tenantId, appId]); - - const isSubmitDisabled = useMemo(() => { - if (apiName === "fdi") { - return !formValues.apiDomain || !formValues.apiBasePath || !formValues.tenantId || !formValues.appId; - } - return !formValues.coreDomain || !formValues.tenantId || !formValues.appId; - }, [formValues]); - - return ( - - - - - Edit Server Configuration - - - - - Setup the server parameters in order to test the API examples. - - - - - {apiName === "fdi" && ( - - - - - Backend API Domain - - - - onChangeInputValue("apiDomain", e.target.value)} - /> - - - - )} - - {apiName === "fdi" && ( - - - - - API Base Path - - - - onChangeInputValue("apiBasePath", e.target.value)} - /> - - - - )} - - {apiName === "cdi" && ( - - - - - Core Domain - - - - onChangeInputValue("coreDomain", e.target.value)} - /> - - - - )} - - - - - - Tenant ID - - - - onChangeInputValue("tenantId", e.target.value)} - /> - - - - - - - - - App ID - - - - onChangeInputValue("appId", e.target.value)} - /> - - - - - - - - - - - - - - - - - ); -} - -const APIRequestEditParametersModalRoot = ({ - children, - onSuccess, -}: { - children: ReactNode; - onSuccess: (data: FormData) => void; -}) => { - const [isOpen, setIsOpen] = useState(false); - return ( - - - {children} - - - - ); -}; - -const APIRequestEditParametersModalTrigger = function APIRequestEditParametersModalTrigger(props) { - const { children } = props; - const { setIsOpen } = useContext(APIRequestEditParametersModalContext); - - return setIsOpen(true)}>{children}; -}; - -export const APIRequestEditParametersModal = { - Root: APIRequestEditParametersModalRoot, - Trigger: APIRequestEditParametersModalTrigger, -}; diff --git a/src/components/APIRequest/APIRequestPage.tsx b/src/components/APIRequest/APIRequestPage.tsx deleted file mode 100644 index b9a3a3ec01..0000000000 --- a/src/components/APIRequest/APIRequestPage.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Box, Flex, Heading } from "@radix-ui/themes"; -import { APIRequestMethod } from "@site/src/types"; -import ReactDOM from "react-dom"; -import { - APIRequestApiTypeBadge, - APIRequestBody, - APIRequestContext, - APIRequestDeprecatedCallout, - APIRequestDescription, - APIRequestHeaderParameters, - APIRequestPath, - APIRequestPathParameters, - APIRequestProvider, - APIRequestQueryParameters, - APIRequestResponse, - APIRequestSecuritySection, - APIRequestSkeleton, -} from "./APIRequest"; -import { APIRequestResponsePreview } from "./APIRequestResponsePreview"; -import { APIRequestCodeSnippetSegmentedControl } from "./APIRequestCodeSnippet"; -import { useContext } from "react"; -import BrowserOnly from "@docusaurus/BrowserOnly"; - -export function APIRequestPage({ - method, - path, - title, - apiName, -}: { - path: string; - method: APIRequestMethod; - title: string; - apiName: "fdi" | "cdi"; -}) { - return ( - - - {() => } - - - - - - - - - - - - - - - - - - - - - ); -} - -function APIReferencePageTitle({ title }: { title: string }) { - // Access a value from the context to force a re-render - const { operation } = useContext(APIRequestContext); - const root = document.getElementById(API_REFERENCE_PAGE_TITLE_ID); - - if (!root) return null; - - return ReactDOM.createPortal( - - - {title} - - - - - - - {" "} - , - root, - ); -} - -export const API_REFERENCE_PAGE_TITLE_ID = "api-reference-page-title"; diff --git a/src/components/APIRequest/APIRequestParametersCard.tsx b/src/components/APIRequest/APIRequestParametersCard.tsx deleted file mode 100644 index f6e7daaa1a..0000000000 --- a/src/components/APIRequest/APIRequestParametersCard.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Box, Text, Card, Flex, Code } from "@radix-ui/themes"; -import { OpenAPIV3 } from "@scalar/openapi-types"; - -export function APIRequestParametersCard({ parameters }: { parameters: OpenAPIV3.ParameterObject[] }) { - return ( - - {parameters.map((param, index) => { - const propName = param.name; - return ( - - - - - {propName} - - {param.required && ( - - required - - )} - - {param.description && ( - - {param.description} - - )} - - - ); - })} - - ); -} diff --git a/src/components/APIRequest/APIRequestResponsePreview.tsx b/src/components/APIRequest/APIRequestResponsePreview.tsx deleted file mode 100644 index 936dcc50b6..0000000000 --- a/src/components/APIRequest/APIRequestResponsePreview.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { Tabs, Badge, Box, Card, Flex, Heading, Text, Select } from "@radix-ui/themes"; -import { getExampleFromSchema } from "@site/src/lib"; -import CodeBlock from "@site/src/theme/CodeBlock"; -import { useContext, useMemo, useState } from "react"; -import { APIRequestContext } from "./APIRequest"; -import type { OpenAPIV3 } from "@scalar/openapi-types"; - -export function APIRequestResponsePreview() { - const { operation } = useContext(APIRequestContext); - const normalizedResponses = useMemo(() => { - if (!operation || !operation.responses) return []; - const result: { id: string; statusCode: string; contentType: string; schema: OpenAPIV3.SchemaObject | null }[] = []; - for (const statusCode in operation.responses) { - const response = operation.responses[statusCode] as OpenAPIV3.ResponseObject; - if (!response.content) { - result.push({ - id: `statusCode-${statusCode}`, - statusCode, - contentType: "application/json", - schema: null, - }); - continue; - } - - const contentType = Object.keys(operation.responses[statusCode].content)[0]; - const currentSchema = operation.responses[statusCode].content[contentType].schema as OpenAPIV3.SchemaObject; - if (currentSchema.oneOf) { - // TODO: Figure out a proper way to show/inform that there are multiple schemas - result.push({ - id: `statusCode-${statusCode}`, - statusCode, - contentType, - schema: currentSchema.oneOf[0] as OpenAPIV3.SchemaObject, - }); - } else { - result.push({ - id: `statusCode-${statusCode}`, - statusCode, - contentType, - schema: currentSchema, - }); - } - } - return result; - }, [operation]); - - const [selectedResponseId, setSelectedResponseId] = useState(null); - - const jsonSnippet = useMemo(() => { - if (!normalizedResponses.length) return null; - let selectedResponse = normalizedResponses[0]; - if (selectedResponseId) { - selectedResponse = normalizedResponses.find((response) => response.id === selectedResponseId); - } - if (!selectedResponse) return null; - if (!selectedResponse.schema) return null; - return JSON.stringify(getExampleFromSchema(selectedResponse.schema), null, 2); - }, [normalizedResponses, selectedResponseId]); - - return ( - - - setSelectedResponseId(value)} - > - - {normalizedResponses.map((response) => ( - - {response.statusCode} - - ))} - - - - {/* setSelectedResponseId(value)} */} - {/* > */} - {/* */} - {/* */} - {/* {normalizedResponses.map((response) => ( */} - {/* */} - {/* */} - {/* */} - {/* {response.statusCode} */} - {/* */} - {/* {response?.schema?.title ? Success : null} */} - {/* */} - {/* */} - {/* ))} */} - {/* */} - {/* */} - {jsonSnippet ? ( - {jsonSnippet} - ) : ( - - - Empty Body - - - )} - - - ); -} diff --git a/src/components/APIRequest/APIRequestSchemaCard.tsx b/src/components/APIRequest/APIRequestSchemaCard.tsx deleted file mode 100644 index 40e7a730b5..0000000000 --- a/src/components/APIRequest/APIRequestSchemaCard.tsx +++ /dev/null @@ -1,340 +0,0 @@ -import { Box, HoverCard, Text, Flex, Code, Separator, Select, TextField, Card, Heading } from "@radix-ui/themes"; -import * as RadixAccordion from "@radix-ui/react-accordion"; -import ChevronDownIcon from "/img/icons/chevron-down.svg"; -import CopyIcon from "/img/icons/copy.svg"; -import CheckIcon from "/img/icons/check.svg"; -import CodeBlock from "@site/src/theme/CodeBlock"; -import type { OpenAPIV3 } from "@scalar/openapi-types"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { getExampleFromSchema } from "@site/src/lib"; -import { normalizeOpenAPIObject } from "@site/src/lib/normalizeOpenAPIObject"; - -export function APIRequestSchemaCard({ - schema, - name = "", - nestingLevel = 0, -}: { - schema: OpenAPIV3.SchemaObject; - name?: string; - nestingLevel?: number; -}) { - if (nestingLevel > 9) { - throw new Error("Nesting level too deep. Use a different UI element for this."); - } - - const parsedSchema = useMemo(() => { - return normalizeOpenAPIObject(schema); - }, [schema]); - - if (parsedSchema.oneOf || parsedSchema.anyOf) { - const oneOfSchemas = parsedSchema.oneOf || parsedSchema.anyOf; - - const label = parsedSchema.oneOf - ? "One of the following schemas can be used:" - : "Any of the following schemas can be used:"; - - if (parsedSchema.name) { - return ( - - - - - - - - - - - - {parsedSchema.name} - - - - - - - - - {label} - - - - - - {oneOfSchemas.map((itemSchema, index) => { - const typedSchema = itemSchema as OpenAPIV3.SchemaObject; - return ( - - - {index !== oneOfSchemas.length - 1 && ( - - - - OR - - - - )} - - ); - })} - - - - - - - - ); - } - - return ( - <> - - {label} - - - - {oneOfSchemas.map((itemSchema, index) => { - const typedSchema = itemSchema as OpenAPIV3.SchemaObject; - return ( - - - {index !== oneOfSchemas.length - 1 && ( - - - - OR - - - - )} - - ); - })} - - - ); - } - - if (name && nestingLevel > 0) { - return ( - - - - - - - - - - - - {name} - - - - - - - - - - - - - - ); - } - - return ; -} - -function SchemaPropertiesList({ schema, nestingLevel }: { schema: OpenAPIV3.SchemaObject; nestingLevel: number }) { - if (!schema.properties) return null; - const properties = schema.properties as { [name: string]: OpenAPIV3.SchemaObject }; - - const propertiesNames = Object.keys(schema.properties); - - return ( - <> - {propertiesNames.map((propName, index) => { - return ( - <> - - 0 ? "3" : "0"} gap="1"> - - - - {propName} - - - {properties[propName].type} - - {isRequired(schema, propName) ? ( - - required - - ) : null} - - - - {properties[propName].description && ( - - {properties[propName].description} - - )} - {properties[propName].type === "object" && properties[propName].properties ? ( - - ) : null} - {properties[propName].type === "array" && - properties[propName].items.type === "object" && - properties[propName].items.properties ? ( - - ) : null} - {properties[propName].type === "array" && properties[propName].items.anyOf ? ( - - ) : null} - {properties[propName].type === "array" && properties[propName].items.oneOf ? ( - - ) : null} - - - {index + 1 < propertiesNames.length ? : null} - - ); - })} - - ); -} - -function PropertyExample({ schema, propName }: { schema: OpenAPIV3.SchemaObject; propName: string }) { - const inputRef = useRef(null); - const [hoverCardIsEnabled, setHoverCardIsEnabled] = useState(false); - const [hoverCardIsVisible, setHoverCardIsVisible] = useState(false); - const [hasCopied, setHasCopied] = useState(false); - - const IconComponent = hasCopied ? CheckIcon : CopyIcon; - - const parsedPropertySchema = useMemo<{ value: string; formattedValue: string; options: string[] }>(() => { - if (!schema.properties) return null; - - const propertySchema = schema.properties[propName] as OpenAPIV3.SchemaObject; - - if (propertySchema.enum && propertySchema.enum.length > 1) { - return { value: propertySchema.enum[0], formattedValue: propertySchema.enum[0], options: propertySchema.enum }; - } - - let value = propertySchema.example || propertySchema.default || ""; - let formattedValue = propertySchema.example || propertySchema.default || ""; - if (propertySchema.type === "object" || propertySchema.type === "array") { - value = JSON.stringify(getExampleFromSchema(propertySchema)); - formattedValue = JSON.stringify(getExampleFromSchema(propertySchema), null, 2); - } - - if (propertySchema.enum) { - value = propertySchema.enum[0]; - formattedValue = propertySchema.enum[0]; - } - - return { value, formattedValue, options: [] }; - }, [schema, propName]); - - const onOpenChange = useCallback( - (isOpen: boolean) => { - if (!hoverCardIsEnabled) return; - setHoverCardIsVisible(isOpen); - }, - [hoverCardIsEnabled], - ); - - const copyToClipboard = useCallback(() => { - if (!parsedPropertySchema) return; - navigator.clipboard.writeText(parsedPropertySchema.value); - setHasCopied(true); - }, [parsedPropertySchema]); - - const onSelect = useCallback((selectedValue) => { - if (!selectedValue) return; - navigator.clipboard.writeText(selectedValue); - }, []); - - useEffect(() => { - if (inputRef.current) { - setHoverCardIsEnabled(inputRef.current.scrollWidth > inputRef.current.clientWidth); - } - }, []); - - if (!parsedPropertySchema || !parsedPropertySchema.value) return null; - - if (parsedPropertySchema.options.length > 1) { - return ( - - - - - {parsedPropertySchema.options.map((value, index) => ( - - {value} - - ))} - - - - ); - } - - return ( - - - - setHasCopied(false)} - onClick={copyToClipboard} - readOnly - defaultValue={parsedPropertySchema.value} - className="api-request-property-example__input" - /> - - - - {parsedPropertySchema.formattedValue} - - - - - - ); -} - -function isRequired(schema: OpenAPIV3.SchemaObject, propName: string) { - if (schema.required && schema.required.includes(propName)) return true; - return schema.properties[propName].required; -} diff --git a/src/components/APIRequest/ApiRequestApiTypeCallout.tsx b/src/components/APIRequest/ApiRequestApiTypeCallout.tsx deleted file mode 100644 index 52c6037b18..0000000000 --- a/src/components/APIRequest/ApiRequestApiTypeCallout.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { Callout, Text, Flex, Heading } from "@radix-ui/themes"; -import { useContext } from "react"; -import { APIRequestContext } from "./APIRequest"; - -import InfoCircledIcon from "/img/icons/info-circled.svg"; - -export function APIRequestApiTypeCallout() { - const { apiName } = useContext(APIRequestContext); - - if (apiName === "cdi") { - return ( - - - - - - - - CDI Endpoint - - - The endpoint is part of the Core Driver Interface API. It's exposed by the SuperTokens Core service - and you should only use it from your backend applications. - - - - - ); - } - - return ( - - - - - - - - FDI Endpoint - - - This endpoint is part of the Frontend Driver Interface API. It's exposed by the SuperTokens Backend - SDKs and you should only use it from your frontend applications. - - - - - ); -} diff --git a/src/components/APIRequest/index.ts b/src/components/APIRequest/index.ts deleted file mode 100644 index b86e6dc05f..0000000000 --- a/src/components/APIRequest/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./APIRequestPage"; diff --git a/src/components/Accordion.scss b/src/components/Accordion.scss deleted file mode 100644 index b68fe13bbf..0000000000 --- a/src/components/Accordion.scss +++ /dev/null @@ -1,83 +0,0 @@ -button { - all: unset; -} - -.accordion { - border-radius: 6px; - width: 100%; - background-color: var(--mauve-6); - box-shadow: 0 2px 10px var(--black-a4); - - p, - h3 { - margin: 0; - } - - &__item { - border-bottom: 1px solid var(--gray-6); - - &:last-child { - border-bottom: none; - } - } - - &__trigger { - display: flex; - &[data-state="open"] > .accordion__icon { - transform: rotate(180deg); - } - } - - &__icon { - transition: transform 300ms cubic-bezier(0.87, 0, 0.13, 1); - svg { - width: 20px; - height: 20px; - } - } - - &__content { - &[data-state="open"] { - animation: slideDown 300ms cubic-bezier(0.87, 0, 0.13, 1); - } - - &[data-state="closed"] { - animation: slideUp 300ms cubic-bezier(0.87, 0, 0.13, 1); - } - - .rt-BaseTabList, - .rt-TabsList { - border-radius: 0 !important; - &::before { - border-radius: 0 !important; - } - } - .rt-TabsRoot { - // There's an additional spacing that gets created - // probably because of the hidden content - margin-bottom: -15px !important; - } - } -} - -@keyframes slideDown { - from { - height: 0; - opacity: 0; - } - to { - height: var(--radix-accordion-content-height); - opacity: 1; - } -} - -@keyframes slideUp { - from { - height: var(--radix-accordion-content-height); - opacity: 1; - } - to { - opacity: 0; - height: 0; - } -} diff --git a/src/components/Accordion.tsx b/src/components/Accordion.tsx deleted file mode 100644 index 7db7d62c92..0000000000 --- a/src/components/Accordion.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import React, { Children, createContext } from "react"; -import * as RadixAccordion from "@radix-ui/react-accordion"; -import ChevronDownIcon from "/img/icons/chevron-down.svg"; - -import { Card, Box, Flex, Heading } from "@radix-ui/themes"; - -import "./Accordion.scss"; - -type AccordionContextType = { - mode: "jsx" | "mdx"; - px: string; -}; - -const AccordionContext = createContext({} as AccordionContextType); - -function AccordionRoot({ - children, - mode = "jsx", - px = "0", -}: React.PropsWithChildren<{ mode?: "jsx" | "mdx"; px?: string }>) { - const childrenArray = Children.toArray(children); - - if (mode === "jsx") { - return ( - - - - - {children} - - - - - ); - } - - const items: { title: React.ReactNode; content: React.ReactNode }[] = []; - let currentItem: { title: React.ReactNode; content: React.ReactNode } = null; - - for (const child of childrenArray) { - // @ts-expect-error The array should always include elements as children - if (child.type.name === "h2") { - if (currentItem) { - items.push(currentItem); - } - // @ts-expect-error - currentItem = { title: child.props.children, content: [] }; - } else { - // @ts-expect-error - currentItem.content.push(child); - } - } - items.push(currentItem); - - return ( - - - - - {items.map(({ title, content }, index) => ( - - {title} - {content} - - ))} - - - - - ); -} - -function AccordionItem({ children, value }: React.PropsWithChildren<{ value: string }>) { - return ( - - {children} - - ); -} - -function AccordionItemHeader({ children }: React.PropsWithChildren) { - const { mode } = React.useContext(AccordionContext); - return ( - - - - - - - {mode === "mdx" ?
{children}
: children} - -
-
-
-
-
-
- ); -} - -function AccordionItemContent({ children }: React.PropsWithChildren) { - const { px } = React.useContext(AccordionContext); - - return ( - - -
{children}
-
-
- ); -} - -export const Accordion = Object.assign(AccordionRoot, { - Item: AccordionItem, - ItemHeader: AccordionItemHeader, - ItemContent: AccordionItemContent, -}); diff --git a/src/components/BetaBadge.tsx b/src/components/BetaBadge.tsx deleted file mode 100644 index 6c8f7de30e..0000000000 --- a/src/components/BetaBadge.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import { Badge } from "@radix-ui/themes"; - -const BetaPages = ["/docs/authentication/ai-authentication"]; -const BetaCategories = []; - -type BetaBadgeProps = - | { - label: string; - className?: string; - } - | { - href: string; - className?: string; - }; - -export function BetaBadge(props: BetaBadgeProps) { - const href = "href" in props ? props.href : undefined; - const label = "label" in props ? props.label : undefined; - - const shouldShow = href ? BetaPages.includes(href) : BetaCategories.includes(label); - - if (!shouldShow) { - return null; - } - - return ( - - - Beta - - - ); -} - -export default BetaBadge; diff --git a/src/components/Callouts/OAuthCallouts.tsx b/src/components/Callouts/OAuthCallouts.tsx deleted file mode 100644 index c5a1199efd..0000000000 --- a/src/components/Callouts/OAuthCallouts.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import React from "react"; - -import { Box } from "@radix-ui/themes"; - -function OAuthVerifyTokensCallout() { - return ( - -
-
-
CAUTION
-
-
-

- This guide only applies to scenarios which involve SuperTokens Session Access Tokens. -

-

- If you are implementing either,{" "} - - Unified Login - {" "} - or{" "} - - Microservice Authentication - - , features that make use of OAuth2 Access Tokens, please check the{" "} - separate page that shows you how to verify - those types of tokens. -

-
-
-
- ); -} - -function OAuthEmailVerificationCallout() { - return ( - -
-
-
CAUTION
-
-
-

- This information only applies to scenarios in which you are using{" "} - SuperTokens Session Access Tokens. -

-

- If you are implementing{" "} - - Unified Login - {" "} - you will have to manually check the email_verified claim on the{" "} - OAuth2 Access Tokens. Please read the{" "} - separate page that shows you how to verify - the token. -

-
-
-
- ); -} - -function OAuthFrontendVerificationCallout() { - return ( - -
-
-
CAUTION
-
-
-

- This information only applies to scenarios in which you are using{" "} - SuperTokens Session Access Tokens. -

-

- If you are implementing{" "} - - Unified Login - {" "} - you will have to manually check authentication state based the OAuth2/OIDC library that you - are using. Please explore the{" "} - dedicated documentation to find - out more. -

-
-
-
- ); -} - -export { OAuthVerifyTokensCallout, OAuthEmailVerificationCallout, OAuthFrontendVerificationCallout }; diff --git a/src/components/Callouts/PaidFeatureCallouts.tsx b/src/components/Callouts/PaidFeatureCallouts.tsx deleted file mode 100644 index 8329fdcb02..0000000000 --- a/src/components/Callouts/PaidFeatureCallouts.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from "react"; - -import { Box } from "@radix-ui/themes"; - -export function MFAPaidFeatureCallout() { - return ( - -
-
-
This is a paid feature
-
-
-

- For self hosted users,{" "} - - Sign up - {" "} - to get a license key and follow the instructions sent to you by email. Using the dev license key is free. We - only start charging you once you enable the feature in production using the provided production license key. -

-

- For managed service users, open our{" "} - - SaaS Dashboard - - , select the relevant Managed deployment, and enable the feature from Features. Changes are saved - automatically. Once enabled, this feature is free on the provided development environment. -

-
-
-
- ); -} - -export function MultiTenancyPaidFeatureCallout() { - return ( - -
-
-
This is a paid feature
-
-
-

- For self hosted users,{" "} - - Sign up - {" "} - to get a license key and follow the instructions sent to you by email. Creation of tenants is free on the - dev license key. -

-

- This feature is already enabled for managed service users. Creation of additional tenant is free on the - provided development environment. -

-
-
-
- ); -} - -export function AccountLinkingFeatureCallout() { - return ( - -
-
-
This is a paid feature
-
-
-

- For self hosted users,{" "} - - Sign up - {" "} - to get a license key and follow the instructions sent to you by email. Using the dev license key is free. We - only start charging you once you enable the feature in production using the provided production license key. -

-

- For managed service users, open our{" "} - - SaaS Dashboard - - , select the relevant Managed deployment, and enable the feature from Features. Changes are saved - automatically. Once enabled, this feature is free on the provided development environment. -

-
-
-
- ); -} diff --git a/src/components/Callouts/TokensCallout.tsx b/src/components/Callouts/TokensCallout.tsx deleted file mode 100644 index c0bd907e6c..0000000000 --- a/src/components/Callouts/TokensCallout.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { Callout, Separator, Heading, Text, Button, Flex, Box } from "@radix-ui/themes"; - -import Link from "@docusaurus/Link"; -import InfoCircleIcon from "/img/icons/info-circled.svg"; - -import { SideModal } from "../Modal"; - -export function TokensCallout({ children }: React.PropsWithChildren<{}>): JSX.Element { - return ( - - - - - - - - - - - This guide only applies to scenarios which involve SuperTokens Session Access Tokens. - - - - - - - - - - - Token Types - - - - - SuperTokens uses a special set of tokens for most of the authentication flows. Only the{" "} - - Unified Login - {" "} - and{" "} - - M2M - {" "} - features work with standard OAuth2 tokens.{" "} - - Read more on each token type in the next section. - - - - SuperTokens Tokens - - - The standard tokens implemented in SuperTokens. They are used in the authentication methods - that do not follow OAuth2 flows. - - - - - OAuth2 Tokens - - - These tokens adhere to the OAuth2 specifications. They are used in the Client Credentials{" "} - (M2M) and in the Authorization Code (Unified Login) flows to authenticate clients and access - protected resources. - - - - - - - - - - - - {children ?
{children}
: null} -
-
-
- ); -} diff --git a/src/components/Callouts/index.ts b/src/components/Callouts/index.ts deleted file mode 100644 index d263392425..0000000000 --- a/src/components/Callouts/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./OAuthCallouts"; -export * from "./PaidFeatureCallouts"; -export * from "./TokensCallout"; diff --git a/src/components/Cards/APIRequestCard.scss b/src/components/Cards/APIRequestCard.scss deleted file mode 100644 index 9725745023..0000000000 --- a/src/components/Cards/APIRequestCard.scss +++ /dev/null @@ -1,17 +0,0 @@ -.api-request-card { - &__accordion-trigger { - &[data-state="open"] > .api-request-card__accordion-trigger-icon { - transform: rotate(180deg); - } - cursor: pointer; - - &[data-state="open"] { - border-bottom: 1px solid var(--gray-a6); - } - } - - &__accordion-trigger-icon { - height: 20px; - width: 20px; - } -} diff --git a/src/components/Cards/AccountTypeCard.tsx b/src/components/Cards/AccountTypeCard.tsx deleted file mode 100644 index b5992927ae..0000000000 --- a/src/components/Cards/AccountTypeCard.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Flex, Box, Card, Separator } from "@radix-ui/themes"; - -import { AccountTypeSelect, SelfHostedDeploymentTypeSelect } from "../Select"; -import { useDocPageData } from "@site/src/hooks"; - -function AccountTypeCardRoot({ children }: React.PropsWithChildren<{}>) { - const accountType = useDocPageData("accountType"); - return ( - - - - {accountType === "self-hosted" ? : null} - - - {children} - - ); -} - -function AccountTypeCardSection({ - children, - px = "2", - py = "4", -}: React.PropsWithChildren<{ - px?: React.ComponentProps["px"]; - py?: React.ComponentProps["py"]; -}>) { - return ( - - {children} - - ); -} - -function AccountTypeManagedContent({ children }: React.PropsWithChildren<{}>) { - const accountType = useDocPageData("accountType"); - if (accountType === "self-hosted") return null; - return {children}; -} - -function AccountTypeSelfHostedContent({ - children, - value, -}: React.PropsWithChildren<{ value: "with-docker" | "without-docker" }>) { - const accountType = useDocPageData("accountType"); - const selfHostedDeploymentType = useDocPageData("selfHostedDeploymentType"); - if (accountType !== "self-hosted") return null; - if (selfHostedDeploymentType !== value) return null; - return children; -} - -export const AccountTypeCard = Object.assign(AccountTypeCardRoot, { - ManagedContent: AccountTypeManagedContent, - SelfHostedContent: AccountTypeSelfHostedContent, - Section: AccountTypeCardSection, -}); diff --git a/src/components/Cards/CodeSampleCard.tsx b/src/components/Cards/CodeSampleCard.tsx deleted file mode 100644 index 9dcfb13dda..0000000000 --- a/src/components/Cards/CodeSampleCard.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Flex, Box, Card, Separator } from "@radix-ui/themes"; - -import "./styles.scss"; - -/* - * Card abstraction used to render code samples sections - * where you might need to change the content based on - * different types of selections (npm/scripts, npm versions, node frameworks, etc) - * - * The component allows you to place two types of selections/inputs - * in the card header. - * This component should not be used directly in MDX files, but rather - * in intermediate components that can be imported and used easily in - * the final files. - * - */ -function CodeSampleCardRoot({ children }: React.PropsWithChildren<{}>) { - return ( - - {children} - - ); -} - -function CodeSampleCardHeader({ children }: React.PropsWithChildren<{}>) { - return ( - <> - - {children} - - - - ); -} - -const CodeSampleCardContent = - (useGetValue: () => [string, (value: string) => void]) => - ({ children, value }: React.PropsWithChildren<{ value: string }>) => { - const [selectionValue] = useGetValue(); - - if (selectionValue !== value) return null; - - return children; - }; - -// Wrap anything that's not a code snippet inside this component -// It provides a standardized way -// to place the content inside a padded container -function CodeSampleCardSection({ - children, - px = "4", - py = "4", -}: React.PropsWithChildren<{ - px?: React.ComponentProps["px"]; - py?: React.ComponentProps["py"]; -}>) { - return ( - - {children} - - ); -} - -export const CodeSampleCard = Object.assign(CodeSampleCardRoot, { - Content: CodeSampleCardContent, - Header: CodeSampleCardHeader, - Section: CodeSampleCardSection, -}); diff --git a/src/components/Cards/GoFrameworksCard.tsx b/src/components/Cards/GoFrameworksCard.tsx deleted file mode 100644 index 5debb4806b..0000000000 --- a/src/components/Cards/GoFrameworksCard.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { AppTypeSelect } from "../Select"; -import { GoFrameworksSelect, useGoFrameworksSelection } from "../Select/GoFrameworksSelect"; - -import { CodeSampleCard } from "./CodeSampleCard"; - -import "./styles.scss"; - -function GoFrameworksCardRoot({ - children, - showAppTypeSelect = false, -}: React.PropsWithChildren<{ showAppTypeSelect?: boolean }>) { - return ( - - - - {showAppTypeSelect && } - - {children} - - ); -} - -export const GoFrameworksCard = Object.assign(GoFrameworksCardRoot, { - Content: CodeSampleCard.Content(useGoFrameworksSelection), - Section: CodeSampleCard.Section, -}); diff --git a/src/components/Cards/HTTPRequestCard.scss b/src/components/Cards/HTTPRequestCard.scss deleted file mode 100644 index a5271ec6c4..0000000000 --- a/src/components/Cards/HTTPRequestCard.scss +++ /dev/null @@ -1,16 +0,0 @@ -.http-request-card-details-modal { - &__description-text { - p { - margin-bottom: 0; - } - } -} - -.http-request-card { - &__heading-anchor { - display: block; - visibility: hidden; - position: relative; - top: -160px; - } -} diff --git a/src/components/Cards/HTTPRequestCard.tsx b/src/components/Cards/HTTPRequestCard.tsx deleted file mode 100644 index db4a570ddf..0000000000 --- a/src/components/Cards/HTTPRequestCard.tsx +++ /dev/null @@ -1,305 +0,0 @@ -import { - Flex, - Select, - Box, - Heading, - SegmentedControl, - Code, - Card, - Button, - Text, - Separator, - ScrollArea, -} from "@radix-ui/themes"; -import CodeBlock from "@theme/CodeBlock"; - -import useBrokenLinks from "@docusaurus/useBrokenLinks"; -import { AppTypeSelect } from "/src/components/Select"; -import { createContext, useContext, useMemo, useState } from "react"; -import { SideModal } from "../Modal"; - -import InfoIcon from "/img/icons/info.svg"; - -import "./HTTPRequestCard.scss"; - -type HTTPRequestContextType = { - environment: "shell" | "nodejs" | "python" | "go"; - path: string; - method: "post" | "get" | "put" | "delete" | "patch" | "head" | "options"; - title: string; - isDetailsModalOpen: boolean; -}; - -const HTTPRequestCardContext = createContext({} as HTTPRequestContextType); - -function HTTPRequestCardRoot({ - path, - method, - title, - children, -}: { - path: string; - method: HTTPRequestContextType["method"]; - title: string; - children: React.ReactNode; -}) { - const [selectedEnvironment, setSelectedEnvironment] = useState("shell"); - const [showRequestDetails, setShowRequestDetails] = useState(false); - - const titleId = useMemo(() => { - return `${title.replace(/\s/g, "-").toLowerCase()}-http-request`; - }, [title]); - const brokenLinks = useBrokenLinks(); - brokenLinks.collectAnchor(titleId); - - // if (!Requests.paths[path] || !Requests.paths[path][method]) { - // throw new Error( - // `Could not find request for path ${path} and method ${method}`, - // ); - // } - // - return ( - - - - - - - - {title} - {/* Use a custom anchor point so that the browser scroll snaps to the correct position */} - - - - - {method.toUpperCase()} {path} - - - - - - - - - - - setSelectedEnvironment(value as unknown as HTTPRequestContextType["environment"]) - } - > - Shell - NodeJS - Python - Go - - {children} - - - - - - ); -} - -function ShellExample({ - children, - showTenatSelection = true, -}: { - children: React.ReactNode; - showTenatSelection?: boolean; -}) { - const { environment } = useContext(HTTPRequestCardContext); - - if (environment !== "shell") return null; - - return ( - <> - - - Curl Example - - {showTenatSelection && } - - {/* */} - {children} - {/* */} - - ); -} - -function NodeJSExample({ - children, - showTenatSelection = true, -}: { - children: React.ReactNode; - showTenatSelection?: boolean; -}) { - const { environment } = useContext(HTTPRequestCardContext); - - if (environment !== "nodejs") return null; - - return ( - <> - - - Fetch Example - - {showTenatSelection && } - - {/* */} - {children} - {/* */} - - ); -} - -function PythonExample({ - children, - showTenatSelection = true, -}: { - children: React.ReactNode; - showTenatSelection?: boolean; -}) { - const { environment } = useContext(HTTPRequestCardContext); - - if (environment !== "python") return null; - - return ( - <> - - - Requests Example - - {showTenatSelection && } - - {/* */} - {children} - {/* */} - - ); -} - -function GoExample({ - children, - showTenatSelection = true, -}: { - children: React.ReactNode; - showTenatSelection?: boolean; -}) { - const { environment } = useContext(HTTPRequestCardContext); - - if (environment !== "go") return null; - - return ( - <> - - - HTTP Example - - {showTenatSelection && } - - {/* */} - {children} - {/* */} - - ); -} - -function DetailsModal({ children }) { - return ( - - - {children} - - - - - - - - ); -} - -function DetailsModalHeader({ children }: { children: React.ReactNode }) { - const { title, method, path } = useContext(HTTPRequestCardContext); - - return ( - - - {title} - - - - {method.toUpperCase()} {path} - - - - {children} - - - - ); -} - -function DetailsModalBody({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); -} - -function RequestDescriptionText({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); -} - -export const HTTPRequestCard = Object.assign(HTTPRequestCardRoot, { - ShellExample, - NodeJSExample, - PythonExample, - GoExample, - DetailsModal, - DetailsModalDescription: RequestDescriptionText, - DetailsModalBody: DetailsModalBody, - DetailsModalHeader: DetailsModalHeader, -}); diff --git a/src/components/Cards/JavascriptHttpLibraryCard.tsx b/src/components/Cards/JavascriptHttpLibraryCard.tsx deleted file mode 100644 index 9ccc8a664f..0000000000 --- a/src/components/Cards/JavascriptHttpLibraryCard.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { JavascriptHttpLibrarySelect, useJavascriptHttpLibrarySelection } from "../Select/JavascriptHttpLibrarySelect"; - -import { CodeSampleCard } from "./CodeSampleCard"; - -import "./styles.scss"; - -function JavascriptHttpLibraryCardRoot({ children }: React.PropsWithChildren<{}>) { - return ( - - - - - {children} - - ); -} - -export const JavascriptHttpLibraryCard = Object.assign(JavascriptHttpLibraryCardRoot, { - Content: CodeSampleCard.Content(useJavascriptHttpLibrarySelection), - Section: CodeSampleCard.Section, -}); diff --git a/src/components/Cards/ManagedOrSelfHostedCard.tsx b/src/components/Cards/ManagedOrSelfHostedCard.tsx deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/components/Cards/MobileFrameworksCard.tsx b/src/components/Cards/MobileFrameworksCard.tsx deleted file mode 100644 index 7081846a9c..0000000000 --- a/src/components/Cards/MobileFrameworksCard.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { MobileFrameworksSelect, useMobileFrameworksSelection } from "../Select/MobileFrameworksSelect"; - -import { CodeSampleCard } from "./CodeSampleCard"; - -import "./styles.scss"; - -function MobileFrameworksCardRoot({ children }: React.PropsWithChildren<{}>) { - return ( - - - - - {children} - - ); -} - -export const MobileFrameworksCard = Object.assign(MobileFrameworksCardRoot, { - Content: CodeSampleCard.Content(useMobileFrameworksSelection), - Section: CodeSampleCard.Section, -}); diff --git a/src/components/Cards/NodeFrameworksCard.tsx b/src/components/Cards/NodeFrameworksCard.tsx deleted file mode 100644 index 00956ce980..0000000000 --- a/src/components/Cards/NodeFrameworksCard.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { MutableRefObject, createContext, useContext, useRef } from "react"; -import { AppTypeSelect } from "../Select"; -import { NodeFrameworksSelect, useNodeFrameworksSelection } from "../Select/NodeFrameworksSelect"; -import ReactDOM from "react-dom"; - -import { CodeSampleCard } from "./CodeSampleCard"; -import { Flex } from "@radix-ui/themes"; - -import "./styles.scss"; - -type NodeFrameworksCardContextType = { cardHeaderPortalRightSideContentRef: MutableRefObject }; -const NodeFrameworksCardContext = createContext({} as NodeFrameworksCardContextType); - -function NodeFrameworksCardRoot({ - children, - showAppTypeSelect = false, - exclude = [], -}: React.PropsWithChildren<{ showAppTypeSelect?: boolean; exclude?: string[] }>) { - const cardHeaderPortalRightSideContentRef = useRef(null); - return ( - - - - - - {showAppTypeSelect && } - - - {children} - - - ); -} - -function HeaderCustomActions({ children }: React.PropsWithChildren) { - const { cardHeaderPortalRightSideContentRef } = useContext(NodeFrameworksCardContext); - - if (!cardHeaderPortalRightSideContentRef.current) return null; - return ReactDOM.createPortal(children, cardHeaderPortalRightSideContentRef.current); -} - -export const NodeFrameworksCard = Object.assign(NodeFrameworksCardRoot, { - Content: CodeSampleCard.Content(useNodeFrameworksSelection), - Section: CodeSampleCard.Section, - HeaderCustomActions, -}); diff --git a/src/components/Cards/NodePackageManagerCard.tsx b/src/components/Cards/NodePackageManagerCard.tsx deleted file mode 100644 index 20fe5f704f..0000000000 --- a/src/components/Cards/NodePackageManagerCard.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { NodePackageManagerSelect, useNodePackageManagerSelection } from "../Select/NodePackageManagerSelect"; - -import { CodeSampleCard } from "./CodeSampleCard"; - -import "./styles.scss"; - -function NodePackageManagerCardRoot({ children }: React.PropsWithChildren<{}>) { - return ( - - - - - {children} - - ); -} - -export const NodePackageManagerCard = Object.assign(NodePackageManagerCardRoot, { - Content: CodeSampleCard.Content(useNodePackageManagerSelection), -}); diff --git a/src/components/Cards/NpmOrScriptsCard.tsx b/src/components/Cards/NpmOrScriptsCard.tsx deleted file mode 100644 index a867ccf8cc..0000000000 --- a/src/components/Cards/NpmOrScriptsCard.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { NpmOrScriptsSelect, useNpmOrScriptsSelection } from "../Select/NpmOrScriptsSelect"; - -import { CodeSampleCard } from "./CodeSampleCard"; - -import "./styles.scss"; - -function NpmOrScriptsCardRoot({ children }: React.PropsWithChildren<{}>) { - return ( - - - - - {children} - - ); -} - -export const NpmOrScriptsCard = Object.assign(NpmOrScriptsCardRoot, { - Content: CodeSampleCard.Content(useNpmOrScriptsSelection), - Section: CodeSampleCard.Section, -}); diff --git a/src/components/Cards/PasswordlessConfigCard.tsx b/src/components/Cards/PasswordlessConfigCard.tsx deleted file mode 100644 index 7fce98ba51..0000000000 --- a/src/components/Cards/PasswordlessConfigCard.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { PasswordlessFlowTypeSelect, PasswordlessContactMethodSelect } from "../Select"; - -import { CodeSampleCard } from "./CodeSampleCard"; -import { Tooltip } from "@radix-ui/themes"; - -import "./styles.scss"; - -function PasswordlessConfigCardRoot({ - children, - showFlowType = false, -}: React.PropsWithChildren<{ showFlowType?: boolean }>) { - return ( - - - - - - {showFlowType && } - - {children} - - ); -} - -export const PasswordlessConfigCard = Object.assign(PasswordlessConfigCardRoot, { - Section: CodeSampleCard.Section, -}); diff --git a/src/components/Cards/PythonFrameworksCard.tsx b/src/components/Cards/PythonFrameworksCard.tsx deleted file mode 100644 index d5f7cf6053..0000000000 --- a/src/components/Cards/PythonFrameworksCard.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { AppTypeSelect } from "../Select"; -import { PythonFrameworksSelect, usePythonFrameworksSelection } from "../Select/PythonFrameworksSelect"; - -import { CodeSampleCard } from "./CodeSampleCard"; - -import "./styles.scss"; - -function PythonFrameworksCardRoot({ - children, - showAppTypeSelect = false, -}: React.PropsWithChildren<{ showAppTypeSelect?: boolean }>) { - return ( - - - - {showAppTypeSelect && } - - {children} - - ); -} - -export const PythonFrameworksCard = Object.assign(PythonFrameworksCardRoot, { - Content: CodeSampleCard.Content(usePythonFrameworksSelection), - Section: CodeSampleCard.Section, -}); diff --git a/src/components/Cards/PythonPackageManagerCard.tsx b/src/components/Cards/PythonPackageManagerCard.tsx deleted file mode 100644 index e70f7b7890..0000000000 --- a/src/components/Cards/PythonPackageManagerCard.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { PythonPackageManagerSelect, usePythonPackageManagerSelection } from "../Select/PythonPackageManagerSelect"; - -import { CodeSampleCard } from "./CodeSampleCard"; - -import "./styles.scss"; - -function PythonPackageManagerCardRoot({ children }: React.PropsWithChildren<{}>) { - return ( - - - - - {children} - - ); -} - -export const PythonPackageManagerCard = Object.assign(PythonPackageManagerCardRoot, { - Content: CodeSampleCard.Content(usePythonPackageManagerSelection), -}); diff --git a/src/components/Cards/PythonSyncAsyncCard.tsx b/src/components/Cards/PythonSyncAsyncCard.tsx deleted file mode 100644 index 92952d47de..0000000000 --- a/src/components/Cards/PythonSyncAsyncCard.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { PythonSyncAsyncSelect, usePythonSyncAsyncSelection } from "../Select/PythonSyncAsyncSelect"; - -import { CodeSampleCard } from "./CodeSampleCard"; - -import "./styles.scss"; - -function PythonSyncAsyncCardRoot({ children }: React.PropsWithChildren<{}>) { - return ( - - - - - {children} - - ); -} - -export const PythonSyncAsyncCard = Object.assign(PythonSyncAsyncCardRoot, { - Content: CodeSampleCard.Content(usePythonSyncAsyncSelection), -}); diff --git a/src/components/Cards/ReferenceCard/ReferenceCard.tsx b/src/components/Cards/ReferenceCard/ReferenceCard.tsx deleted file mode 100644 index e36e8bed55..0000000000 --- a/src/components/Cards/ReferenceCard/ReferenceCard.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import React, { createContext, useCallback, useContext } from "react"; -import { Card, Flex, Avatar, Grid, Box, Text } from "@radix-ui/themes"; -import * as Icon from "lucide-react"; -import Link from "@docusaurus/Link"; - -import "./styles.scss"; -import { AnalyticsEventNames, trackButtonClick } from "@site/src/lib/analytics"; - -function ReferenceCardRoot({ children, href, label }: React.PropsWithChildren<{ href: string; label?: string }>) { - const hasAvatarInChildren = React.Children.toArray(children).some((child) => { - if (React.isValidElement(child)) { - return child.type === ReferenceCardAvatar || child.type === ReferenceCardIcon; - } - return false; - }); - - const onClick = useCallback(() => { - trackButtonClick(AnalyticsEventNames.buttonReferenceCard, "v1", { - href, - }); - }, [href]); - - if (label) { - return ( - - - - {label} - - - - ); - } - - if (hasAvatarInChildren) { - return ( - - - - - {children} - - - - - ); - } - - return ( - - - - - {children} - - - - - ); -} - -function ReferenceCardAvatar({ - icon, - size = "3", - radius = "small", -}: { - icon: string; - size?: React.ComponentProps["size"]; - radius?: React.ComponentProps["radius"]; -}) { - return ( - - ); -} - -function ReferenceCardIcon({ icon }: { icon: string }) { - const IconCompoent = Icon[icon]; - if (!IconCompoent) { - throw new Error(`Invalid icon name: ${icon}`); - } - - return ( - - - - ); -} - -function ReferenceCardTitle({ children }: React.PropsWithChildren<{}>) { - const asChild = typeof children === "string" ? false : true; - - return ( - - {children} - - ); -} - -function ReferenceCardDescription({ children }: React.PropsWithChildren<{}>) { - const asChild = typeof children === "string" ? false : true; - return ( - - {children} - - ); -} - -type ReferenceCardGridProps = { - lg?: string; - xs?: string; - initial?: string; -}; - -function ReferenceCardGrid({ - children, - lg = "repeat(3, 1fr)", - xs = "repeat(2, 1fr)", - initial = "repeat(1, 1fr)", -}: React.PropsWithChildren) { - return ( - - {children} - - ); -} - -// In some cases we want to show a grid that has only two columns -// but in which children stretch over a 1/3 of the width of the grid -// It might be skill issue but I can't figure out anything other than this hacky solution. -// We use an additional empty div to ensure the width size. -// That div needs to work in responsive scenarios (dissapear when the grid changes to two columns) -function ReferenceCardGridHelper() { - return
; -} - -export const ReferenceCard = Object.assign(ReferenceCardRoot, { - Avatar: ReferenceCardAvatar, - Title: ReferenceCardTitle, - Description: ReferenceCardDescription, - Grid: ReferenceCardGrid, - GridHelper: ReferenceCardGridHelper, - Icon: ReferenceCardIcon, -}); diff --git a/src/components/Cards/ReferenceCard/styles.scss b/src/components/Cards/ReferenceCard/styles.scss deleted file mode 100644 index 38f90abf6b..0000000000 --- a/src/components/Cards/ReferenceCard/styles.scss +++ /dev/null @@ -1,49 +0,0 @@ -.reference-card { - --base-card-surface-hover-box-shadow: 0 0 0 1px var(--orange-a7); - --ifm-link-hover-decoration: none; - @supports (color: color-mix(in oklab, white, black)) { - --base-card-surface-hover-box-shadow: 0 0 0 1px color-mix(in oklab, var(--orange-a7), var(--orange-7) 25%); - } - - &:hover { - --card-background-color: rgba(255, 153, 51, 0.05); - - .reference-card__description { - color: var(--gray-12); - } - } - - a { - color: var(--gray-12); - } - - a:hover { - color: var(--orange-11); - } - - &__prefetch-link { - display: none; - } - - &__avatar { - img { - object-fit: contain; - color: var(--gray-11); - margin: 0; - } - } - - &__icon { - color: var(--accent-a11); - } - - p { - margin: 0; - } - - &__grid-helper { - @media (max-width: 1280px) { - display: none; - } - } -} diff --git a/src/components/Cards/ThirdPartyBuiltinProvidersCard.tsx b/src/components/Cards/ThirdPartyBuiltinProvidersCard.tsx deleted file mode 100644 index 38b62b6bd6..0000000000 --- a/src/components/Cards/ThirdPartyBuiltinProvidersCard.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { ThirdPartyBuiltinProvidersSelect, useThirdPartyBuiltinProvidersSelection } from "../Select"; - -import { CodeSampleCard } from "./CodeSampleCard"; - -import "./styles.scss"; - -function ThirdPartyBuiltinProvidersCardRoot({ children }: React.PropsWithChildren<{}>) { - return ( - - - - - {children} - - ); -} - -export const ThirdPartyBuiltinProvidersCard = Object.assign(ThirdPartyBuiltinProvidersCardRoot, { - Content: CodeSampleCard.Content(useThirdPartyBuiltinProvidersSelection), -}); diff --git a/src/components/Cards/index.ts b/src/components/Cards/index.ts deleted file mode 100644 index a367fcc368..0000000000 --- a/src/components/Cards/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -export * from "./NodePackageManagerCard"; -export * from "./NodeFrameworksCard"; -export * from "./PythonFrameworksCard"; -export * from "./GoFrameworksCard"; -export * from "./MobileFrameworksCard"; -export * from "./NpmOrScriptsCard"; -export * from "./JavascriptHttpLibraryCard"; -export * from "./ReferenceCard/ReferenceCard"; -export * from "./PythonSyncAsyncCard"; -export * from "./PythonPackageManagerCard"; -export * from "./ThirdPartyBuiltinProvidersCard"; -export * from "./CodeSampleCard"; -export * from "./PasswordlessConfigCard"; -export * from "./HTTPRequestCard"; -export * from "./AccountTypeCard"; diff --git a/src/components/Cards/styles.scss b/src/components/Cards/styles.scss deleted file mode 100644 index 4b778f835d..0000000000 --- a/src/components/Cards/styles.scss +++ /dev/null @@ -1,16 +0,0 @@ -.content-card { - padding: 0; - - // Remove the marings from mdx components - // and rely on the card content logic/styling - // for spacing - & > * { - margin-bottom: 0 !important; - } -} - -.content-card__section { - & > * { - margin-bottom: 0 !important; - } -} diff --git a/src/components/ColorModeToggle.scss b/src/components/ColorModeToggle.scss deleted file mode 100644 index 982d71fa62..0000000000 --- a/src/components/ColorModeToggle.scss +++ /dev/null @@ -1,89 +0,0 @@ -.color-mode-toggle { - position: relative; - display: inline-flex; - align-items: center; - justify-content: center; - width: 2.5rem; - height: 2.5rem; - border-radius: var(--radius-3); - background-color: transparent; - color: var(--gray-11); - transition: all 0.2s ease; - - &[data-state="on"] { - .color-mode-toggle__light-icon { - opacity: 0; - transform: scale(0) rotate(90deg); - } - - .color-mode-toggle__dark-icon { - opacity: 1; - transform: scale(1) rotate(0); - } - } - - &[data-state="off"] { - .color-mode-toggle__light-icon { - opacity: 1; - transform: scale(1) rotate(0); - } - - .color-mode-toggle__dark-icon { - opacity: 0; - transform: scale(0) rotate(90deg); - } - } - - &:hover { - background-color: var(--gray-a4); - color: var(--gray-12); - } - - &:focus-visible { - outline: none; - box-shadow: 0 0 0 2px var(--color-mode-toggle-focus-ring); - } - - &:disabled { - pointer-events: none; - opacity: 0.5; - cursor: not-allowed; - } - - &__icon { - position: absolute; - width: 1.2rem; - height: 1.2rem; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - } -} - -@media (max-width: 768px) { - .color-mode-toggle { - width: 2.25rem; - height: 2.25rem; - - &__icon { - width: 1.1rem; - height: 1.1rem; - } - } -} - -// High contrast mode support -// @media (prefers-contrast: high) { -// .color-mode-toggle { -// border-width: 2px; -// -// &:focus-visible { -// box-shadow: 0 0 0 3px var(--color-mode-toggle-focus-ring); -// } -// } -// } - -// @media (prefers-reduced-motion: reduce) { -// .color-mode-toggle__icon { -// transition-duration: 0.1s; -// transition-timing-function: ease; -// } -// } diff --git a/src/components/ColorModeToggle.tsx b/src/components/ColorModeToggle.tsx deleted file mode 100644 index 25fdfa1c22..0000000000 --- a/src/components/ColorModeToggle.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from "react"; -import { Moon, Sun } from "lucide-react"; -import { useTheme } from "../lib/themeStore"; -import * as TogglePrimitive from "@radix-ui/react-toggle"; - -import "./ColorModeToggle.scss"; - -export function ColorModeToggle() { - const { theme, setTheme } = useTheme(); - - return ( - setTheme(pressed ? "dark" : "light")} - className="color-mode-toggle" - aria-label="Toggle theme" - title={`Current: ${theme}`} - > - - - - ); -} diff --git a/src/components/ConditionalContent.tsx b/src/components/ConditionalContent.tsx deleted file mode 100644 index 5e4c664f51..0000000000 --- a/src/components/ConditionalContent.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useDocPageData } from "@site/src/hooks"; -import { InferDotNotationKeys, DocPageState } from "../lib"; - -export function ConditionalContent({ - propertyName, - condition, - children, -}: React.PropsWithChildren<{ propertyName: InferDotNotationKeys; condition: string }>) { - const value = useDocPageData(propertyName); - - const meetsCondition = value === condition; - if (!meetsCondition) return null; - return <>{children}; -} diff --git a/src/components/CopyPageContentButton.scss b/src/components/CopyPageContentButton.scss deleted file mode 100644 index 826eb04fd2..0000000000 --- a/src/components/CopyPageContentButton.scss +++ /dev/null @@ -1,43 +0,0 @@ -.copy-page-content-button { - &__icon { - width: 14px; - display: grid; - grid-template-columns: 1fr; - grid-template-rows: 1fr; - place-items: center; - } - - &__icon-check { - grid-column: 1; - grid-row: 1; - opacity: 0; - } - - &__icon-copy { - grid-column: 1; - grid-row: 1; - opacity: 1; - } - - &[data-state="idle"] { - .copy-page-content-button__icon-check { - opacity: 0; - transition: opacity 0.25s; - } - .copy-page-content-button__icon-copy { - opacity: 1; - transition: opacity 0.25s; - } - } - - &[data-state="copied"] { - .copy-page-content-button__icon-check { - opacity: 1; - transition: opacity 0.25s; - } - .copy-page-content-button__icon-copy { - opacity: 0; - transition: opacity 0.25s; - } - } -} diff --git a/src/components/CopyPageContentButton.tsx b/src/components/CopyPageContentButton.tsx deleted file mode 100644 index eb8a1add2c..0000000000 --- a/src/components/CopyPageContentButton.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { Button } from "@radix-ui/themes"; -import CopyIcon from "/img/icons/copy.svg"; -import CheckIcon from "/img/icons/check.svg"; - -import "./CopyPageContentButton.scss"; - -export function CopyPageContentButton() { - const [markdownContent, setMarkdownContent] = useState(""); - const [isCopied, setIsCopied] = useState(false); - - useEffect(() => { - const fetchMarkdownContent = async () => { - try { - const currentUrl = window.location.pathname; - const markdownUrl = `${currentUrl}.md`; - const response = await fetch(markdownUrl); - if (!response.ok) { - throw new Error(`Failed to fetch markdown content: ${response.status}`); - } - - const content = await response.text(); - setMarkdownContent(content); - } catch (err) { - console.error("Error fetching markdown content:", err); - } - }; - - fetchMarkdownContent(); - }, []); - - const handleCopyToClipboard = useCallback(async () => { - if (!markdownContent) return; - - try { - await navigator.clipboard.writeText(markdownContent); - setIsCopied(true); - setTimeout(() => { - setIsCopied(false); - }, 3000); - } catch (err) { - console.error("Failed to copy to clipboard:", err); - } - }, [markdownContent]); - - const onKeyDown = useCallback( - (event: KeyboardEvent) => { - const isApple = - navigator.platform.startsWith("Mac") || navigator.platform === "iPhone" || navigator.platform === "iPad"; - - const isKeyComboPressed = isApple - ? event.metaKey && event.altKey && event.code === "KeyC" - : event.ctrlKey && event.altKey && event.code === "KeyC"; - if (isKeyComboPressed) { - handleCopyToClipboard(); - } - }, - [handleCopyToClipboard], - ); - - useEffect(() => { - document.addEventListener("keydown", onKeyDown); - return () => { - document.removeEventListener("keydown", onKeyDown); - }; - }, [onKeyDown]); - - return ( - - ); -} diff --git a/src/components/DescriptionText.tsx b/src/components/DescriptionText.tsx deleted file mode 100644 index 80d85e3d4b..0000000000 --- a/src/components/DescriptionText.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Text } from "@radix-ui/themes"; -// import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; - -export function DescriptionText({ children }: React.PropsWithChildren<{}>) { - return ( - - {children} - - ); -} diff --git a/src/components/DocItemContextCondition.tsx b/src/components/DocItemContextCondition.tsx deleted file mode 100644 index f5cf8c49ac..0000000000 --- a/src/components/DocItemContextCondition.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { useContext } from "react"; -import { DocItemContext, getContextValue } from "@site/src/context"; -import { DocsItemStateType } from "@site/src/hooks"; - -export function ContextCondition({ - condition, - children, -}: { - condition: ((state: DocsItemStateType) => boolean) | Record; - children: React.ReactNode; -}) { - const state = useContext(DocItemContext); - let matches: boolean; - if (typeof condition === "function") { - matches = condition(state); - } else { - matches = Object.keys(condition).every((propertyKey) => { - return condition[propertyKey] === getContextValue(state, propertyKey); - }); - } - - if (!matches) return null; - return <>{children}; -} diff --git a/src/components/DocItemContextValue.tsx b/src/components/DocItemContextValue.tsx deleted file mode 100644 index 4f5ecbddea..0000000000 --- a/src/components/DocItemContextValue.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { useContext } from "react"; -import { DocItemContext, getContextValue } from "@site/src/context"; - -export function DocItemContextValue({ propertyPath }: { propertyPath: string }) { - const context = useContext(DocItemContext); - - return getContextValue(context, propertyPath); -} diff --git a/src/components/Forms/AppInfoForm.scss b/src/components/Forms/AppInfoForm.scss deleted file mode 100644 index a16a4582b2..0000000000 --- a/src/components/Forms/AppInfoForm.scss +++ /dev/null @@ -1,112 +0,0 @@ -.app-info-form { - display: flex; - flex-direction: column; - - box-shadow: grey; - padding: 16px; - // border: 0.0625rem solid #404040; - border: 1px solid #2e2e2e; - // border-radius: 6px; - border-radius: 13px; - // background: #2a2a2a; - // background: #232323; - - // padding: 1.5em; - - font-style: normal; - font-weight: 600; - font-size: 1rem; - - // color: rgb(255, 255, 255); - color: #b2b2b2; - - text-decoration: none !important; - - position: relative; - overflow: hidden; - - transition: all 0.2s ease-in-out; - - &:hover { - border: 1px solid rgba(255, 153, 51, 0.3); - color: #b2b2b2 !important; - } -} - -.app-info-form__content { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); - gap: 20px; - list-style-type: none; - padding: 0; - margin: 0; -} - -.app-info-form__input { - border: 1px solid rgb(69, 69, 69); - background-color: rgb(0, 0, 0); - color: rgb(255, 255, 255); - box-shadow: 0px 0px 0px 0px transparent; - outline: none; - transition: - border 0.15s, - box-shadow 0.15s; - padding: 8px 20px; - font-family: Roboto; - width: 100%; - height: 34px; - border-radius: 6px; - font-size: 14px; -} - -.app-info-form__field { - display: flex; - flex-direction: column; - gap: 5px; -} - -.app-info-form__field-help-text { - display: none; -} - -.app-info-form__field-label { - display: flex; - flex-direction: column; - gap: 5px; -} - -.app-info-form__input-error { -} - -.app-info-form__separator { - height: 1px; - width: 100%; - background-color: rgba(255, 255, 255, 0.2); - margin: 15px 0; -} - -.app-info-form__grid { - display: grid; - padding: 0; - grid-template-columns: repeat(2, 1fr); - gap: 15px; - margin: 0; -} - -.app-info-form__section { - display: flex; - flex-direction: column; - gap: 10px; -} - -.app-info-form__section-title { - font-weight: 600; - margin: 0 !important; - margin-bottom: 10px !important; -} - -@media (max-width: 700px) { - .app-info-form_grid { - grid-template-columns: 1fr; - } -} diff --git a/src/components/Forms/AppInfoForm.tsx b/src/components/Forms/AppInfoForm.tsx deleted file mode 100644 index 82611a9ac7..0000000000 --- a/src/components/Forms/AppInfoForm.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import { useCallback, useContext, useEffect, useMemo, useState } from "react"; -import { DocItemContext } from "@site/src/context"; -import * as Form from "@radix-ui/react-form"; -import { Grid, Text, Heading, Flex, Card, TextField, VisuallyHidden, Separator } from "@radix-ui/themes"; -import "./AppInfoForm.scss"; - -export function AppInfoForm() { - const { appInfo, onChangeAppInfoField } = useContext(DocItemContext); - - const [formErrors, setFormErrors] = useState>({ - appName: "", - apiBasePath: "", - apiDomain: "", - websiteDomain: "", - websiteBasePath: "", - }); - - const onChangeInputValue = useCallback( - (e) => { - onChangeAppInfoField(e.target.name, e.target.value); - }, - [onChangeAppInfoField], - ); - - const onKeyDown = useCallback((e) => { - if (e.key === "/") { - // Prevent triggering the search modal - e.stopPropagation(); - } - }, []); - - return ( - - - - - App Info - - - Adjust these values based on the application that you are trying to configure. To learn more about what each - field means check the references page. - - - - - - Application Name - - - This is the name of your application. - - - - - - - - - - - - - API Domain - - - This is the URL of your app's API server. - - - - - - - - - - API Base Path - - - SuperTokens will expose its APIs scoped by this base API path. - - - - - - - - - - Website Domain - - - This is the URL of your website. - - - - - - - - - - Website Base Path - - - The path where the login UI will be rendered - - - - - - - - - - - ); -} diff --git a/src/components/Forms/ExampleAppForm.scss b/src/components/Forms/ExampleAppForm.scss deleted file mode 100644 index d19583c4a8..0000000000 --- a/src/components/Forms/ExampleAppForm.scss +++ /dev/null @@ -1,3 +0,0 @@ -.example-app-form-code-block { - margin-bottom: 0; -} diff --git a/src/components/Forms/ExampleAppForm.tsx b/src/components/Forms/ExampleAppForm.tsx deleted file mode 100644 index f81e0b721d..0000000000 --- a/src/components/Forms/ExampleAppForm.tsx +++ /dev/null @@ -1,179 +0,0 @@ -import { useCallback, useContext, useMemo, useState } from "react"; -import { DocItemContext } from "@site/src/context"; -import * as Form from "@radix-ui/react-form"; -import { Select } from "@radix-ui/themes"; -import BrowserOnly from "@docusaurus/BrowserOnly"; -import { Grid, Text, Box, Heading, Flex, Card, TextField, VisuallyHidden, Separator } from "@radix-ui/themes"; -import CodeBlock from "@theme/CodeBlock"; -import { useLocation } from "@docusaurus/router"; - -import "./ExampleAppForm.scss"; - -function ExampleAppFormRoot() { - const { search } = useLocation(); - const queryRecipe = useMemo(() => { - const searchParams = new URLSearchParams(location.search); - return searchParams.get("recipe") || null; - }, [search]); - const { appInfo, onChangeAppInfoField } = useContext(DocItemContext); - const [frontendFramework, setFrontendFramework] = useState(null); - const [backendLanguage, setBackendLanguage] = useState(null); - const [recipe, setRecipe] = useState(queryRecipe); - - const onChangeInputValue = useCallback( - (e) => { - onChangeAppInfoField(e.target.name, e.target.value); - }, - [onChangeAppInfoField], - ); - const appName = appInfo.appName; - - const command = useMemo(() => { - let baseCommand = `npx create-supertokens-app`; - if (appName) { - baseCommand += ` --appname=${appName}`; - } - if (recipe) { - baseCommand += ` --recipe=${recipe}`; - } - if (frontendFramework) { - baseCommand += ` --frontend=${frontendFramework}`; - } - if (backendLanguage && frontendFramework !== "next") { - baseCommand += ` --backend=${backendLanguage}`; - } - - return baseCommand; - }, [recipe, frontendFramework, backendLanguage, appName]); - - return ( - - - - - Generate Example App - - - Update the form based on your tech stack and requirements. Once you're done, copy the command and run it in - your terminal. - - - - - - - Application Name - - - - This is the name of your application. - - - - - - - - - - - Authentication Recipe - - - - - - - Email/Password - Passwordless - Third Party - Multi-Factor Authentication - Multi-Tenancy - - - - - - - - - - - - Frontend Framework - - - - - - - React - Angular - Vue - NextJS - - - - - - - - - - Backend Language - - - - - - - NodeJS - Go - Python - - - - - - - - - - - {command} - - - ); -} - -export function ExampleAppForm(props) { - return ( - - {() => { - return ; - }} - - ); -} diff --git a/src/components/Forms/PasswordlessRecipeForm.tsx b/src/components/Forms/PasswordlessRecipeForm.tsx deleted file mode 100644 index 100db5f435..0000000000 --- a/src/components/Forms/PasswordlessRecipeForm.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useCallback, useContext } from "react"; -import { DocItemContext } from "@site/src/context"; -import { Flex, Text, Card, Heading, RadioCards } from "@radix-ui/themes"; - -export function PasswordlessRecipeForm() { - const { recipes, onChangeRecipeProperty } = useContext(DocItemContext); - - const { passwordless } = recipes; - const onChangeContactMethod = useCallback( - (e) => { - onChangeRecipeProperty("passwordless", "contactMethod", e.target.value); - }, - [onChangeRecipeProperty], - ); - - return ( - - - - How do you identify your users? - - - - - - Only Phone Number - - - - - Only Email - - - - - Email or Phone Number - - - - - - - ); -} diff --git a/src/components/Forms/index.ts b/src/components/Forms/index.ts deleted file mode 100644 index 463271f835..0000000000 --- a/src/components/Forms/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./PasswordlessRecipeForm"; -export * from "./AppInfoForm"; -export * from "./ExampleAppForm"; diff --git a/src/components/MenuItemIcon.tsx b/src/components/MenuItemIcon.tsx deleted file mode 100644 index 60c674e0b5..0000000000 --- a/src/components/MenuItemIcon.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import React from "react"; -import useBaseUrl from "@docusaurus/useBaseUrl"; -import { - Book, - Zap, - Plug, - HousePlus, - IdCard, - MonitorSmartphone, - UserSearch, - ShieldPlus, - BadgeCheck, - ShieldUser, - Braces, - Key, - LayoutDashboard, - Shield, - CircleUserRound, - UserPlus, - Brain, - FileTerminal, - FileCode, - HardDrive, - NotebookTabs, - Users, - ArrowRight, - Settings, - Server, - WandSparkles, - FileUser, - Smartphone, - Share2, - Building, - RectangleEllipsis, - Bot, - RotateCw, - Fingerprint, - ShieldCheck, - Clock, - UserCheck, - Puzzle, - Workflow, - Monitor, - Bug, - Palette, - Cpu, - Hash, - History, - Play, - MailCheck, -} from "lucide-react"; - -import VercelLogo from "/img/logos/vercel.svg"; -import SupabaseLogo from "/img/logos/supabase.svg"; -import HasuraLogo from "/img/logos/hasura.svg"; -import NextjsLogo from "/img/logos/nextjs.svg"; -import NestjsLogo from "/img/logos/nestjs.svg"; -import NetlifyLogo from "/img/logos/netlify.svg"; -import AwsLambdaLogo from "/img/logos/aws-lambda.svg"; -import GraphqlLogo from "/img/logos/graphql.svg"; -import CdiLogo from "/img/logos/cdi.svg"; -import FdiLogo from "/img/logos/fdi.svg"; -import SamlLogo from "/img/logos/saml.svg"; -import MCPLogo from "/img/logos/mcp.svg"; -import NodeSmallLogo from "/img/logos/nodejs-small.svg"; -import ReactLogo from "/img/logos/react.svg"; -import JavascriptLogo from "/img/logos/js.svg"; - -const categoryIcons = { - // Main categories - References: Book, - Quickstart: Zap, - Authentication: Key, - "Additional Verification": Shield, - "Post Authentication": Users, - Migration: ArrowRight, - "Platform Configuration": Settings, - Deployment: Server, - - // Authentication methods - "Email Password": RectangleEllipsis, - Passwordless: WandSparkles, - "Social Login": CircleUserRound, - "Enterprise Login": Building, - "Unified Login": Share2, - "Machine to Machine": Bot, - Passkeys: Fingerprint, - - // Quickstart integrations - Integrations: Puzzle, - // "AWS Lambda": AwsLambdaLogo, - // NextJS: NextjsLogo, - // GraphQL: GraphqlLogo, - // Hasura: HasuraLogo, - // NestJS: NestjsLogo, - // Netlify: NetlifyLogo, - // Supabase: SupabaseLogo, - // Vercel: VercelLogo, - - // References and SDK sections - "Frontend SDKs": Monitor, - "Backend SDKs": Server, - "User Interface": Palette, - "Frontend Driver Interface": FileCode, - "Core Driver Interface": FileTerminal, - "Testing and Debugging": Bug, - "SuperTokens Core": Cpu, - Plugins: Plug, - - // Authentication reference subcategories - "Email/Password": RectangleEllipsis, - ThirdParty: Share2, - WebAuthn: Fingerprint, - "Passkeys/WebAuthn": Fingerprint, - OAuth: Key, - MFA: ShieldCheck, - Session: Clock, - TOTP: Hash, - OTP: Smartphone, - SAML: SamlLogo, - - // CDI/FDI - "Email Verification": MailCheck, - "Account Linking": FileUser, - "Bulk Import": UserPlus, - Core: Cpu, - Dashboard: LayoutDashboard, - "User Metadata": Braces, - "User Roles": ShieldUser, - Multitenancy: HousePlus, - - // Quickstart guides and workflows - "Quickstart Guides": Zap, - "Advanced Workflows": Workflow, - "Legacy Method": History, - "Legacy method": History, - "Using prebuilt UI": Palette, - "Step 1: Account Creation": UserCheck, - "5. Checking Sessions in API Routes": Shield, - "Checking Sessions in API Routes": Shield, - - // Main quickstart menu items - "/docs/quickstart/backend-setup": HardDrive, - "/docs/quickstart/frontend-setup": Monitor, - "/docs/quickstart/introduction": Book, - "/docs/quickstart/next-steps": NotebookTabs, - "/docs/quickstart/example-applications": Play, - "/docs/quickstart/build-with-ai-tools": Brain, - - "/docs/authentication/ai-authentication": MCPLogo, - - "/docs/additional-verification/captcha": RotateCw, - "/docs/references/plugins/captcha-reference": RotateCw, - "/docs/additional-verification/mfa/webauthn-setup": Fingerprint, - - // Other - "Session Verification": BadgeCheck, - "Attack Protection Suite": ShieldPlus, - "Multi Factor Authentication": MonitorSmartphone, - "User Management": UserSearch, - "Session Management": IdCard, - - // References - "React SDK Reference": ReactLogo, - "Javascript SDK Reference": JavascriptLogo, - "Node.js SDK Reference": NodeSmallLogo, -}; - -// Brand logo mappings for integration platforms -const brandLogos: { [key: string]: string } = {}; - -type MenuItemIconProps = - | { - label: string; - className?: string; - } - | { - href: string; - className?: string; - }; - -export function MenuItemIcon(props: MenuItemIconProps) { - const IconComponent = "label" in props ? categoryIcons[props.label] : categoryIcons[props.href]; - - if (!IconComponent) { - return null; - } - - // Handle SVG logos differently from Lucide icons - if (typeof IconComponent === "string") { - return ; - } - - return ; -} - -export default MenuItemIcon; diff --git a/src/components/Modal/SideModal.scss b/src/components/Modal/SideModal.scss deleted file mode 100644 index 425b59ce22..0000000000 --- a/src/components/Modal/SideModal.scss +++ /dev/null @@ -1,69 +0,0 @@ -/* Variables (Adjust these according to your design system) */ -$z-index-overlay: 50; -$z-index-side-modal: 60; - -@keyframes slide-in-right { - from { - transform: translateX(100%); - } - to { - transform: translateX(0); - } -} - -@keyframes slide-out-right { - from { - transform: translateX(0); - } - to { - transform: translateX(100%); - } -} - -.side-modal-content { - position: fixed; - z-index: $z-index-side-modal; - display: flex; - flex-direction: column; - gap: 1rem; - max-width: 100vw; - // background-color: $background-color; - padding: 1.5rem; - // box-shadow: - // 0 10px 38px -10px rgba(0, 0, 0, 0.35), - // 0 10px 20px -15px rgba(0, 0, 0, 0.2); - transition: - transform 0.3s ease-in-out, - opacity 0.3s ease-in-out; - - top: 0; - right: 0; - bottom: 0; - animation: slide-in-right 0.3s forwards; - border-radius: 0; - - &[data-size="s"] { - width: 500px; - } - - &[data-size="m"] { - width: calc(100% - var(--doc-sidebar-width)); - } - - &[data-size="l"] { - width: 100%; - } - - @media (max-width: 996px) { - max-width: 100%; - &[data-size="s"], - &[data-size="m"], - &[data-size="l"] { - width: 100%; - } - } - - &[data-state="closed"] { - animation: slide-out-right 0.2s forwards; - } -} diff --git a/src/components/Modal/SideModal.tsx b/src/components/Modal/SideModal.tsx deleted file mode 100644 index c62ef2ce5d..0000000000 --- a/src/components/Modal/SideModal.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from "react"; - -import { Dialog } from "@radix-ui/themes"; - -import "./SideModal.scss"; - -const SideModalContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { size?: "s" | "m" | "l" } ->(({ className, size = "m", children, ...props }, ref) => ( - - {children} - -)); -SideModalContent.displayName = Dialog.Content.displayName; - -export const SideModal = { - Root: Dialog.Root, - Trigger: Dialog.Trigger, - Close: Dialog.Close, - Title: Dialog.Title, - Description: Dialog.Description, - Content: SideModalContent, -}; diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx deleted file mode 100644 index 9e9c3fdabf..0000000000 --- a/src/components/Modal/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from "./SideModal"; diff --git a/src/components/NewBadge.tsx b/src/components/NewBadge.tsx deleted file mode 100644 index 3666bf73ff..0000000000 --- a/src/components/NewBadge.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from "react"; -import { Badge } from "@radix-ui/themes"; - -const NewPages = [ - "/docs/quickstart/build-with-ai-tools", - "/docs/additional-verification/captcha", - "/docs/post-authentication/user-management/user-banning", - "/docs/authentication/enterprise/tenant-discovery", - "/docs/authentication/enterprise/tenant-management-plugin", - "/docs/deployment/telemetry", - "/docs/authentication/enterprise/saml", - "/docs/post-authentication/user-management/progressive-profiling", - "/docs/post-authentication/user-management/profiling", -]; -const NewCategories = ["Plugins"]; - -type NewBadgeProps = - | { - label: string; - className?: string; - } - | { - href: string; - className?: string; - }; - -export function NewBadge(props: NewBadgeProps) { - const href = "href" in props ? props.href : undefined; - const label = "label" in props ? props.label : undefined; - - const shouldShow = href ? NewPages.includes(href) : NewCategories.includes(label); - - if (!shouldShow) { - return null; - } - - return ( - - - New - - - ); -} - -export default NewBadge; diff --git a/src/components/PageOptionsDropdownMenu.tsx b/src/components/PageOptionsDropdownMenu.tsx deleted file mode 100644 index e8af60402c..0000000000 --- a/src/components/PageOptionsDropdownMenu.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React, { useCallback, useMemo, useState } from "react"; -import { Flex, DropdownMenu, Button } from "@radix-ui/themes"; -import { useDoc } from "@docusaurus/plugin-content-docs/client"; - -import ExternalLinkIcon from "/img/icons/external-link.svg"; -import T3ChatIcon from "/img/logos/t3-chat.svg"; -import ChatGPTIcon from "/img/logos/chatgpt.svg"; -import AnthropicIcon from "/img/logos/anthropic.svg"; -import GitHubIcon from "/img/logos/github.svg"; - -export function PageOptionsDropdownMenu() { - const { metadata } = useDoc(); - const { editUrl } = metadata; - - const searchQuery = useMemo(() => { - const currentUrl = window.location.href; - return `Read the following documentation page "${currentUrl}.md". I want to ask questions about it. If the content is too long use the \`offset\` and \`limit\` query parameters. With them you can paginate the number of characters returned by the server.`; - }, []); - - const chatGPTUrl = useMemo(() => { - return `https://chatgpt.com/?hints=search&q=${encodeURIComponent(searchQuery)}`; - }, [searchQuery]); - const claudeUrl = useMemo(() => { - return `https://claude.ai/new?q=${encodeURIComponent(searchQuery)}`; - }, [searchQuery]); - const t3ChatUrl = useMemo(() => { - return `https://t3.chat/new?q=${encodeURIComponent(searchQuery)}`; - }, [searchQuery]); - - return ( - - - - - - - - - Open in Github - - - - - - - - - Open in ChatGPT - - - - - - - - - Open in Claude - - - - - - - - - Open in T3 Chat - - - - - - - - ); -} diff --git a/src/components/PaidFeatureCallout.tsx b/src/components/PaidFeatureCallout.tsx deleted file mode 100644 index 2855935dc2..0000000000 --- a/src/components/PaidFeatureCallout.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { Callout, Separator, Heading, Text, Button, Flex, Box } from "@radix-ui/themes"; - -import Link from "@docusaurus/Link"; -import CreditCardIcon from "/img/icons/credit-card.svg"; -import InfoCircleIcon from "/img/icons/info-circled.svg"; - -import { SideModal } from "./Modal"; -import { Steps } from "./Steps"; - -export function PaidFeatureCallout(): JSX.Element { - return ( - - - - - - - - - This feature is only available to paid users. - - - - - - - - - - Enable paid features - - - - - This feature is only available to paid users. Enable it using the provided instructions. - - - - - - - - You can test the feature in a development environment for free. We only start charging once you - use it production. - - - - - - Managed Service - - - - - - Login into the{" "} - - SaaS dashboard - - . - - - - - - - Select the Managed tab and open the deployment that you are working with. - - - - - - - After the page loads click on the Features tab. - - - - - - - Open Features and toggle the features you want to enable. Changes are saved - automatically. - - - - - - - Self Hosted - - - - - - Login into the{" "} - - SaaS dashboard - - . - - - - - - - Select the Self-hosted tab and create a new license key. - - - - - - - Open the license key and toggle the features you want to use. Changes are saved automatically. - - - - - - - Add the newly created license key to{" "} - your Core Service. - - - - - - - - - - - - - - - - - ); -} diff --git a/src/components/Question.tsx b/src/components/Question.tsx deleted file mode 100644 index a7a70c78bf..0000000000 --- a/src/components/Question.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import React, { createContext, Children, PropsWithChildren, useState, useContext, useCallback, useEffect } from "react"; -import { Card, Flex, Heading, RadioCards, Text } from "@radix-ui/themes"; - -import "./RadioCard.scss"; - -type QuestionContextType = { - answer?: string; - setAnswer: (answer: string) => void; -}; - -const QuestionContext = createContext({} as QuestionContextType); - -const LOCAL_STORAGE_KEY_PREFIX = "supertokens-question-answer:"; - -export function Question( - props: PropsWithChildren<{ - question: string | (() => JSX.Element); - defaultAnswer?: string; - cardVariant?: React.ComponentProps["variant"]; - questionSize?: React.ComponentProps["size"]; - px?: React.ComponentProps["px"]; - py?: React.ComponentProps["py"]; - mb?: React.ComponentProps["mb"]; - }>, -) { - const { - defaultAnswer, - question: _question, - children, - cardVariant: variant, - questionSize = "5", - px = "5", - py = "4", - mb = "4", - } = props; - const [selectedAnswer, setSelectedAnswer] = useState(defaultAnswer); - const question = typeof _question === "string" ? _question : _question(); - - const onSelectAnswer = useCallback((answer: string) => { - setSelectedAnswer(answer); - localStorage.setItem(`${LOCAL_STORAGE_KEY_PREFIX}:${question}`, answer); - }, []); - - useEffect(() => { - const storedAnswer = localStorage.getItem(`${LOCAL_STORAGE_KEY_PREFIX}:${question}`); - if (storedAnswer !== null) { - setSelectedAnswer(storedAnswer); - } - }, []); - - const selectedAnswerChildren = Children.map(props.children, (child) => { - if (!React.isValidElement(child)) return child; - const childTitle = child.props.title; - const childChildren = child.props.children; - if (childTitle === selectedAnswer) { - return childChildren; - } - }); - - return ( - - - - - {question} - - - - {children} - - - - - {selectedAnswerChildren} - - ); -} - -type AnswerProps = { - title: string; - onClick?: () => void; -}; - -export function Answer(props: PropsWithChildren) { - const { onClick: _onClick } = props; - const { setAnswer } = useContext(QuestionContext); - const onClick = useCallback(() => { - if (_onClick !== undefined) { - _onClick(); - } - setAnswer(props.title); - }, []); - - return ( - - - {props.title} - - - ); -} diff --git a/src/components/RadioCard.scss b/src/components/RadioCard.scss deleted file mode 100644 index c142acf4c8..0000000000 --- a/src/components/RadioCard.scss +++ /dev/null @@ -1,11 +0,0 @@ -.radio-card-item { - --radio-cards-item-background-color: rgba(170, 202, 255, 0.04); - &[data-state="checked"] { - --radio-cards-item-background-color: rgba(255, 153, 51, 0.05); - color: var(--orange-11); - - &::after { - outline-color: var(--orange-7); - } - } -} diff --git a/src/components/RemoveForLLMs.tsx b/src/components/RemoveForLLMs.tsx deleted file mode 100644 index 9fa54ca56a..0000000000 --- a/src/components/RemoveForLLMs.tsx +++ /dev/null @@ -1,5 +0,0 @@ -// This component exists only to mark blocks of content that -// should not be included in the llms.txt or plain markdown files -export function RemoveForLLMs({ children }) { - return <>{children}; -} diff --git a/src/components/SDKCompatibilityTable.tsx b/src/components/SDKCompatibilityTable.tsx deleted file mode 100644 index 6296137d02..0000000000 --- a/src/components/SDKCompatibilityTable.tsx +++ /dev/null @@ -1,358 +0,0 @@ -import React, { useEffect, useMemo, useState } from "react"; -import { getCompatibility, getSupportedDrivers, getSupportedFrontends } from "../lib/api"; -import { Text, ScrollArea, Skeleton, Badge, Card, Flex, Separator, Grid, Select, Heading, Box } from "@radix-ui/themes"; -import * as Form from "@radix-ui/react-form"; - -export function SDKCompatibilityTable() { - const [selectedFrontendSDK, setSelectedFrontendSDK] = useState(""); - const [selectedBackendSDK, setSelectedBackendSDK] = useState(""); - const [selectedCoreVersion, setSelectedCoreVersion] = useState(""); - const [selectedBackendSDKVersion, setSelectedBackendSDKVersion] = useState(""); - const { - data: supportedFrontends, - isLoading: isFetchSupportedFrontendsLoading, - error: fetchSupportedFrontendsError, - } = useFetchSupportedFrontends(); - const { - data: supportedBackends, - isLoading: isFetchSupportedBackendsLoading, - error: fetchSupportedBackendsError, - } = useFetchSupportedBackends(); - const { - data: sdkCompatibility, - isLoading: isFetchSdkCompatibilityLoading, - error: fetchSdkCompatibilityError, - } = useFetchSdkCompatibility(selectedFrontendSDK, selectedBackendSDK); - - const coreVersions = useMemo(() => { - if (!sdkCompatibility) return []; - return Object.keys(sdkCompatibility.coreToDriver).map((version) => { - return { - id: version, - displayName: `${version}.X`, - }; - }); - }, [sdkCompatibility]); - - const backendVersions = useMemo(() => { - if (!sdkCompatibility) return []; - return Object.keys(sdkCompatibility.driverToFrontend).map((version) => { - return { - id: version, - displayName: `${version}.X`, - }; - }); - }, [sdkCompatibility]); - - const supportedFrontendVersions = useMemo(() => { - if (!sdkCompatibility || !selectedBackendSDKVersion) return null; - return sdkCompatibility.driverToFrontend[selectedBackendSDKVersion]; - }, [sdkCompatibility, selectedBackendSDKVersion]); - - const supportedBackendVersions = useMemo(() => { - if (!sdkCompatibility || !selectedCoreVersion) return null; - return sdkCompatibility.coreToDriver[selectedCoreVersion]; - }, [selectedCoreVersion, sdkCompatibility]); - - return ( - <> - - - - - - - SDK Compatibility - - - Select the SDKs that you are using in order to load the available versions. - - - - - - - Backend SDK - - - - - - - {supportedBackends?.drivers?.map((option) => ( - - {option.displayName} - - ))} - - - - - - - - - - Frontend SDK - - - - - - - {supportedFrontends?.frontends?.map((option) => ( - - {option.displayName} - - ))} - - - - - - - - - - - - - - - - - - - - Compatible Backend SDK Versions - - - - - - - SuperTokens Core Version - - - - - - - {coreVersions?.map((option) => ( - - {option.displayName} - - ))} - - - - - - - {supportedBackendVersions && supportedBackendVersions.length > 0 ? ( - - {supportedBackendVersions.map((version) => ( - - {version} - - ))} - - ) : null} - {supportedBackendVersions && supportedBackendVersions.length === 0 ? ( - - - No compatible versions found - - - ) : null} - {sdkCompatibility && !selectedCoreVersion ? ( - - - Select a supertokens-core version - - - ) : null} - {!sdkCompatibility && isFetchSdkCompatibilityLoading ? ( - - - - ) : null} - - - - - - - - - - - - - - Compatible Frontend SDK Versions - - - - - - - Backend SDK Version - - - - - - - {backendVersions?.map((option) => ( - - {option.displayName} - - ))} - - - - - - - {supportedFrontendVersions && supportedFrontendVersions.length > 0 ? ( - - {supportedFrontendVersions.map((version) => ( - - {version} - - ))} - - ) : null} - {supportedFrontendVersions && supportedFrontendVersions.length === 0 ? ( - - - No compatible versions found - - - ) : null} - {sdkCompatibility && !selectedBackendSDKVersion ? ( - - - Select a backend SDK version - - - ) : null} - {!sdkCompatibility && isFetchSdkCompatibilityLoading ? ( - - - - ) : null} - - - - - - - - ); -} - -function useFetchSupportedFrontends() { - const [data, setData] = useState> | null>(null); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - - useEffect(() => { - const fetchData = async () => { - setIsLoading(true); - try { - const response = await getSupportedFrontends(); - setData(response); - } catch (err) { - setError(err); - } finally { - setIsLoading(false); - } - }; - - fetchData(); - }, []); - - return { isLoading, error, data }; -} - -function useFetchSupportedBackends() { - const [data, setData] = useState> | null>(null); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - - useEffect(() => { - const fetchData = async () => { - setIsLoading(true); - try { - const response = await getSupportedDrivers(); - setData(response); - } catch (err) { - setError(err); - } finally { - setIsLoading(false); - } - }; - - fetchData(); - }, []); - - return { data, isLoading, error }; -} - -function useFetchSdkCompatibility(selectedFrontend: string, selectedBackend: string) { - const [data, setData] = useState> | null>(null); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - - useEffect(() => { - const fetchData = async () => { - setIsLoading(true); - try { - const response = await getCompatibility(selectedBackend, selectedFrontend); - setData(response); - } catch (err) { - setError(err); - } finally { - setIsLoading(false); - } - }; - - if (!selectedFrontend || !selectedBackend) return; - - fetchData(); - }, [selectedFrontend, selectedBackend]); - - return { data, isLoading, error }; -} diff --git a/src/components/SDKReference/SDKReference.scss b/src/components/SDKReference/SDKReference.scss deleted file mode 100644 index 52d8573e12..0000000000 --- a/src/components/SDKReference/SDKReference.scss +++ /dev/null @@ -1,17 +0,0 @@ -.sdk-reference-section { - &__tooltip-icon { - color: var(--gray-11); - width: 16px; - } - &__title-container { - h3 { - margin: 0; - } - } - - &__tooltip { - p { - margin: 0; - } - } -} diff --git a/src/components/SDKReference/SDKReference.tsx b/src/components/SDKReference/SDKReference.tsx deleted file mode 100644 index 90bc6bf96a..0000000000 --- a/src/components/SDKReference/SDKReference.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import React, { useMemo } from "react"; -import { Info } from "lucide-react"; -import Link from "@docusaurus/Link"; -import { - Card, - Flex, - Heading, - Text, - Badge, - Separator, - Table, - Box, - Code, - Tooltip, - Link as RLink, -} from "@radix-ui/themes"; - -import "./SDKReference.scss"; - -type Props = { - type: string; - description: string; - name: string; - namespace: string; - filePath: string; - line: number; - repository: string; - properties: { - name: string; - description?: string; - required: boolean; - defaultValue?: string; - type: string | [string, string]; - }[]; - children: React.ReactNode; -}; - -export function SDKReference(reference: Props) { - const anchorId = useMemo(() => { - return `${slugify(reference.namespace)}-${slugify(reference.name)}}`; - }, [reference]); - - const tableDescription = useMemo(() => { - if (reference.type === "function") { - return "PARAMETERS"; - } else if (reference.type === "class") { - return "PROPERTIES"; - } else if (reference.type === "interface") { - return "PROPERTIES"; - } else if (reference.type === "type") { - return "PROPERTIES"; - } - - return ""; - }, [reference]); - - return ( -
- - - - - {reference.children} - - - {capitalize(reference.type)} - - - - - - {reference.description} - - - - - - {tableDescription} - - - - - - Name - Type - Required - - - - {reference.properties.map((row, idx) => ( - - - - - - {row.name} - - - {row.description ? ( - - - - ) : null} - - - - - {Array.isArray(row.type) ? ( - - {row.type[0]} - - ) : ( - {row.type} - )} - - - - {row.required ? ( - - - Yes - - - ) : ( - - - - - )} - - - ))} - - - - - - -
- ); -} - -function slugify(s: string) { - return s - .toLowerCase() - .replace(/[^a-z0-9]+/g, "-") - .replace(/^-+|-+$/g, ""); -} - -function capitalize(s: string) { - return s.charAt(0).toUpperCase() + s.slice(1); -} diff --git a/src/components/SDKReference/index.ts b/src/components/SDKReference/index.ts deleted file mode 100644 index 0cfd72bbbe..0000000000 --- a/src/components/SDKReference/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./SDKReference"; diff --git a/src/components/ScrollOffsetFix.tsx b/src/components/ScrollOffsetFix.tsx deleted file mode 100644 index 4eb043f8a0..0000000000 --- a/src/components/ScrollOffsetFix.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { useEffect } from "react"; -import { initScrollOffset } from "../lib/scrollOffset"; - -export function ScrollOffsetFix() { - useEffect(() => { - initScrollOffset(); - }, []); - - return null; // This component doesn't render anything -} - -export default ScrollOffsetFix; diff --git a/src/components/Search.scss b/src/components/Search.scss deleted file mode 100644 index b5fc06846a..0000000000 --- a/src/components/Search.scss +++ /dev/null @@ -1,160 +0,0 @@ -.search-button { - min-width: 300px; - color: var(--gray-11); - - &__shortcut-indicator { - @media screen and (max-width: 996px) { - display: none; - } - } - - @media screen and (max-width: 996px) { - justify-content: flex-start; - min-width: unset; - flex: 1; - } - &:hover { - color: var(--gray-12); - } -} - -.search-modal { - margin-top: 150px; - padding: 0; - width: 700px; - - animation: fadeIn 0.2s ease-in-out; - - @keyframes fadeIn { - 0% { - opacity: 0; - } - 100% { - opacity: 1; - } - } - - @media screen and (max-width: 996px) { - width: 100%; - max-width: calc(100vw - 2rem); - } - - &__input { - color: var(--gray-11); - border-radius: var(--radius-4); - --text-field-height: var(--space-8); - } - - &__results { - overflow-y: auto; - max-height: 400px; - position: relative; - } - - &__close-button { - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - width: 36px; - span { - display: block; - animation: fadeIn 0.15s ease-in-out; - @media screen and (max-width: 996px) { - display: none; - } - } - svg { - display: none; - animation: fadeIn 0.15s ease-in-out; - @media screen and (max-width: 996px) { - display: block; - } - } - &:hover { - span { - display: none; - } - svg { - display: block; - } - } - } - - &__results-list { - list-style: none; - padding: 0; - margin: 0; - } - - &__no-results { - text-align: center; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - min-height: 100px; - } - - &__tabs-list { - @media screen and (max-width: 996px) { - display: none; - } - } - - &__item { - padding: var(--space-1) var(--space-3); - border-bottom: 1px solid var(--gray-6); - min-width: 0; - - a { - display: block; - width: 100%; - min-width: 0; - } - - &[data-active="true"] { - background-color: var(--gray-a4); - - mark { - background-color: unset; - text-decoration: underline; - color: var(--gray-12); - } - } - - mark { - background-color: unset; - color: var(--orange-10); - } - } - - &__item-content { - overflow: hidden; - min-width: 0; - flex: 1; - } - - &__item-highlight { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - max-width: 100%; - min-width: 0; - } - - &__item-icon { - color: var(--gray-11); - flex-shrink: 0; - } - - @media screen and (max-width: 480px) { - &__item { - padding: var(--space-1) var(--space-2); - } - - &__item-highlight { - font-size: 0.9rem; - } - } -} diff --git a/src/components/Search.tsx b/src/components/Search.tsx deleted file mode 100644 index a06eb1b12b..0000000000 --- a/src/components/Search.tsx +++ /dev/null @@ -1,617 +0,0 @@ -import { Badge, Box, Button, Dialog, VisuallyHidden, Flex, Tabs, Text, TextField } from "@radix-ui/themes"; -import Link from "@docusaurus/Link"; -import SearchIcon from "/img/icons/search.svg"; -import CloseIcon from "/img/icons/x.svg"; -import HashIcon from "/img/icons/hash.svg"; -import GithubIcon from "/img/icons/github.svg"; -import FileIcon from "/img/icons/file.svg"; -import TerminalIcon from "/img/icons/terminal.svg"; -import CodeIcon from "/img/icons/code.svg"; -import PythonIcon from "/img/icons/python.svg"; -import GoIcon from "/img/icons/go.svg"; -import TypeScriptIcon from "/img/icons/typescript.svg"; -import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"; -import { search, ParsedSearchResult } from "../lib"; - -import "./Search.scss"; -import { APIRequestMethodBadge } from "./APIRequest/APIRequest"; - -type SearchButtonContextType = { - isModalOpen: boolean; - setIsModalOpen: (open: boolean) => void; -}; - -const SearchButtonContext = createContext({ - isModalOpen: false, - setIsModalOpen: () => {}, -}); - -const SearchButton = () => { - const [isModalOpen, setIsModalOpen] = useState(false); - - const onKeyDown = useCallback( - (event: KeyboardEvent) => { - if (event.key === "/" && !isModalOpen) { - event.preventDefault(); - setIsModalOpen((open) => !open); - } - }, - [isModalOpen], - ); - - useEffect(() => { - document.addEventListener("keydown", onKeyDown); - return () => { - document.removeEventListener("keydown", onKeyDown); - }; - }, [onKeyDown]); - - return ( - - - - - - - - - - - ); -}; - -type SearchModalContextType = { - onCloseModal: () => void; - query: string; -}; - -const SearchModalContext = createContext({} as SearchModalContextType); - -function SearchModal() { - const [searchQuery, setSearchQuery] = useState(""); - const { setIsModalOpen } = useContext(SearchButtonContext); - const [selectedTab, setSelectedTab] = useState("all"); - const tabsRef = useRef([]); - - const onKeyDown = useCallback((event: KeyboardEvent) => { - if (!tabsRef.current) return; - if (!event.ctrlKey) return; - - const numericKeys = tabsRef.current.map((_, index) => `${index + 1}`); - if (numericKeys.includes(event.key)) { - const tabElement = tabsRef.current[Number(event.key) - 1]; - if (!tabElement) return; - const tabValue = tabElement.getAttribute("data-value"); - if (!tabValue) return; - setSelectedTab(tabValue); - return; - } - - if (event.key === "]") { - const activeTabElementIndex = tabsRef.current.findIndex((el) => el.getAttribute("data-state") === "active"); - if (activeTabElementIndex === -1) return; - const nextTabElement = tabsRef.current[(activeTabElementIndex + 1) % tabsRef.current.length]; - if (!nextTabElement) return; - const nextTabValue = nextTabElement.getAttribute("data-value"); - if (!nextTabValue) return; - setSelectedTab(nextTabValue); - return; - } - - if (event.key === "[") { - const activeTabElementIndex = tabsRef.current.findIndex((el) => el.getAttribute("data-state") === "active"); - if (activeTabElementIndex === -1) return; - const previousTabElement = - tabsRef.current[(activeTabElementIndex + tabsRef.current.length - 1) % tabsRef.current.length]; - if (!previousTabElement) return; - const previousTabValue = previousTabElement.getAttribute("data-value"); - if (!previousTabValue) return; - setSelectedTab(previousTabValue); - return; - } - }, []); - - const onCloseModal = useCallback(() => { - setSearchQuery(""); - setIsModalOpen(false); - }, []); - - useEffect(() => { - document.addEventListener("keydown", onKeyDown); - return () => { - document.removeEventListener("keydown", onKeyDown); - }; - }, [onKeyDown]); - - return ( - - - Search - - - - { - setSearchQuery(e.target.value); - }} - size="3" - > - - - - - - - - - ESC - - - - - - - - - - {[ - { name: "all", label: "All" }, - { name: "documentation", label: "Documentation" }, - { name: "sdk-reference", label: "SDK References" }, - { name: "api-reference", label: "API References" }, - ].map((tab, index) => ( - { - tabsRef.current[index] = el; - }} - > - {tab.label} - - ))} - - - - - - - - - ); -} - -function AllSearchResultsTabContent() { - const searchFn = useCallback(async (searchQuery: string) => { - return search(searchQuery); - }, []); - - return ( - - - - - - ); -} - -function DocumentationSearchResultsTabContent() { - const searchFn = useCallback(async (searchQuery: string) => { - return search(searchQuery, [ - { indexName: "supertokens_documentation", facetFilters: [["type:guide", "type:tutorial"]] }, - ]); - }, []); - - return ( - - - - - - ); -} - -function SDKReferencesSearchResultsTabContent() { - const searchFn = useCallback(async (searchQuery: string) => { - return search(searchQuery, [ - { - indexName: "supertokens_sdk_references", - }, - { indexName: "supertokens_documentation", facetFilters: ["type:sdk-reference"] }, - ]); - }, []); - - return ( - - - - - - ); -} - -function APIReferencesSearchResultsTabContent() { - const searchFn = useCallback(async (searchQuery: string) => { - return search(searchQuery, [ - { - indexName: "supertokens_api_references", - }, - { indexName: "supertokens_documentation", facetFilters: ["type:api-reference"] }, - ]); - }, []); - - return ( - - - - - - ); -} - -type SearchContextType = { - searchResults: ParsedSearchResult[] | null; - searchState: "idle" | "loading" | "error" | "fetched"; -}; - -const SearchContext = createContext({} as SearchContextType); - -function SearchProvider({ - searchFn, - children, -}: { - searchFn: (query: string) => Promise; - children: React.ReactNode; -}) { - const { query } = useContext(SearchModalContext); - const [results, setResults] = useState(null); - const [searchState, setSearchState] = useState<"idle" | "loading" | "error" | "fetched">("idle"); - - const performSearch = useCallback( - async (searchQuery: string) => { - if (!searchQuery) { - setResults(null); - setSearchState("idle"); - return; - } - - setSearchState("loading"); - const searchResults = await searchFn(searchQuery); - setResults(searchResults); - setSearchState("fetched"); - }, - [searchFn], - ); - - const debouncedSearch = useCallback(debounce(performSearch, 200), [performSearch]); - - useEffect(() => { - debouncedSearch(query); - }, [query, debouncedSearch]); - - return {children}; -} - -export const Search = { - Button: SearchButton, -}; - -type SearchResultListContextType = { - interactionMode: "keyboard" | "mouse" | "none"; - setInteractionMode: (mode: "keyboard" | "mouse" | "none") => void; -}; - -const SearchResultListContext = createContext({} as SearchResultListContextType); - -function SearchResultsList() { - const ref = useRef(null); - const { searchResults, searchState } = useContext(SearchContext); - const { onCloseModal } = useContext(SearchModalContext); - const [interactionMode, setInteractionMode] = useState<"keyboard" | "mouse" | "none">("none"); - - const onNavigateToNextItem = useCallback(() => { - if (!ref.current) return; - setInteractionMode("keyboard"); - const searchResultItems = ref.current.querySelectorAll("li"); - const searchResultItemsArray = Array.from(searchResultItems); - const activeItemIndex = searchResultItemsArray.findIndex((item) => item.getAttribute("data-active") === "true"); - let nextItemIndex = activeItemIndex === -1 ? 0 : activeItemIndex + 1; - if (nextItemIndex >= searchResultItemsArray.length) nextItemIndex = 0; - - if (activeItemIndex !== -1 && searchResultItemsArray[activeItemIndex]) { - searchResultItemsArray[activeItemIndex].setAttribute("data-active", "false"); - } - searchResultItemsArray[nextItemIndex].setAttribute("data-active", "true"); - searchResultItemsArray[nextItemIndex].scrollIntoView({ - behavior: "instant", - block: "nearest", - }); - }, []); - - const onNavigateToPrevItem = useCallback(() => { - if (!ref.current) return; - setInteractionMode("keyboard"); - const searchResultItems = ref.current.querySelectorAll("li"); - const searchResultItemsArray = Array.from(searchResultItems); - const activeItemIndex = searchResultItemsArray.findIndex((item) => item.getAttribute("data-active") === "true"); - let nextItemIndex = activeItemIndex === -1 ? searchResultItemsArray.length - 1 : activeItemIndex - 1; - if (nextItemIndex === -1) nextItemIndex = searchResultItemsArray.length - 1; - - if (activeItemIndex !== -1 && searchResultItemsArray[activeItemIndex]) { - searchResultItemsArray[activeItemIndex].setAttribute("data-active", "false"); - } - searchResultItemsArray[nextItemIndex].setAttribute("data-active", "true"); - searchResultItemsArray[nextItemIndex].scrollIntoView({ - behavior: "instant", - block: "nearest", - }); - }, []); - - const onSelectItem = useCallback(() => { - if (!ref.current) return; - const activeItem = ref.current.querySelector("li[data-active='true']"); - if (!activeItem) return; - const link = activeItem.querySelector("a"); - if (!link) return; - link.click(); - setInteractionMode("none"); - onCloseModal(); - }, []); - - useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if (event.key === "ArrowDown") { - event.preventDefault(); - onNavigateToNextItem(); - } else if (event.key === "ArrowUp") { - event.preventDefault(); - onNavigateToPrevItem(); - } else if (event.key === "Enter") { - event.preventDefault(); - onSelectItem(); - } - }; - - document.addEventListener("keydown", handleKeyDown); - return () => { - document.removeEventListener("keydown", handleKeyDown); - }; - }, []); - - return ( - - - {(searchState === "idle" || (searchState === "loading" && !searchResults)) && ( - - - Start typing to search - - - )} - {searchState === "fetched" && searchResults?.length === 0 && ( - - - No results found - - - )} - {(searchState === "fetched" || searchState === "loading") && searchResults?.length > 0 && ( -
    - {searchResults.map((result) => ( - - ))} -
- )} -
-
- ); -} - -type SearchResultItemType = "page-title" | "page-heading" | "api-reference" | "sdk-reference" | "github-page"; - -const SearchResultItemTypeIcons: Record>> = { - "page-title": FileIcon, - "page-heading": HashIcon, - "api-reference": TerminalIcon, - "sdk-reference": CodeIcon, - "github-page": GithubIcon, -}; - -const LanguageIcons: Record<"typescript" | "go" | "python", React.ComponentType>> = { - typescript: TypeScriptIcon, - go: GoIcon, - python: PythonIcon, -}; - -function isDocumentationResult( - result: ParsedSearchResult, -): result is ParsedSearchResult & { index: "supertokens_documentation" } { - return result.index === "supertokens_documentation"; -} - -function isApiResult( - result: ParsedSearchResult, -): result is ParsedSearchResult & { index: "supertokens_api_references" } { - return result.index === "supertokens_api_references"; -} - -function isSdkResult( - result: ParsedSearchResult, -): result is ParsedSearchResult & { index: "supertokens_sdk_references" } { - return result.index === "supertokens_sdk_references"; -} - -function SearchResultListItem({ result }: { result: ParsedSearchResult }) { - const ref = useRef(null); - const { interactionMode, setInteractionMode } = useContext(SearchResultListContext); - const { onCloseModal } = useContext(SearchModalContext); - const searchResultItemType = useMemo(() => { - if (isSdkResult(result)) return "sdk-reference"; - if (isApiResult(result)) return "api-reference"; - if (isDocumentationResult(result) && result.meta.hierarchy?.length === 1) return "page-title"; - return "page-heading"; - }, [result]); - const breadcrumbs = useMemo(() => { - if (isDocumentationResult(result)) { - return result.meta.hierarchy.join(" › "); - } - return undefined; - }, [result]); - - const onMouseEnter = useCallback(() => { - if (!ref.current) return; - if (interactionMode === "keyboard") return; - const searchResultItems = ref.current.parentNode.querySelectorAll("li"); - const searchResultItemsArray = Array.from(searchResultItems); - const activeItemIndex = searchResultItemsArray.findIndex((item) => item.getAttribute("data-active") === "true"); - if (activeItemIndex !== -1) { - searchResultItemsArray[activeItemIndex].setAttribute("data-active", "false"); - } - ref.current.setAttribute("data-active", "true"); - }, [interactionMode]); - - const onMouseMove = useCallback(() => { - if (!ref.current) return; - if (interactionMode === "keyboard") { - setInteractionMode("mouse"); - ref.current.setAttribute("data-active", "false"); - } - }, [interactionMode]); - - const onMouseLeave = useCallback(() => { - if (!ref.current) return; - if (interactionMode === "mouse") { - setInteractionMode("none"); - } - ref.current.setAttribute("data-active", "false"); - }, []); - - const onClick = useCallback(() => { - onCloseModal(); - setInteractionMode("none"); - }, []); - - const urlOrPath = useMemo(() => { - const url = new URL(result.url); - if (url.hostname.includes("supertokens")) { - return url.pathname; - } - return result.url; - }, [result]); - - const Icon = SearchResultItemTypeIcons[searchResultItemType]; - - const renderContent = () => { - if (isDocumentationResult(result)) { - return ( - <> - - - {breadcrumbs} - - - ); - } - - if (isApiResult(result)) { - return ( - <> - - - {result.meta.apiType.toUpperCase()} - - - - {result.meta.path} - - - - {result.meta.summary} - - - ); - } - - if (isSdkResult(result)) { - const LanguageIcon = LanguageIcons[result.meta.language]; - return ( - <> - - - - {result.meta.name} - - - - {result.meta.namespace} • {result.meta.type} - - - ); - } - - return null; - }; - - return ( -
  • - - - - - - - {renderContent()} - - - -
  • - ); -} - -function debounce any>(func: F, waitFor: number) { - let timeout: ReturnType | null = null; - - const debounced = (...args: Parameters) => { - if (timeout !== null) { - clearTimeout(timeout); - } - timeout = setTimeout(() => func(...args), waitFor); - }; - - return debounced; -} diff --git a/src/components/Select/AccountTypeSelect.tsx b/src/components/Select/AccountTypeSelect.tsx deleted file mode 100644 index 5d4f5fb846..0000000000 --- a/src/components/Select/AccountTypeSelect.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useDocPageData } from "@site/src/hooks"; -import { docPageStore } from "@site/src/lib"; - -export function AccountTypeSelect() { - const accountType = useDocPageData("accountType"); - return ( - docPageStore.updateValue("accountType", value as "managed" | "self-hosted")} - > - - - Managed Service - Self-hosted - - - ); -} diff --git a/src/components/Select/AppTypeSelect.tsx b/src/components/Select/AppTypeSelect.tsx deleted file mode 100644 index 09bdc6579b..0000000000 --- a/src/components/Select/AppTypeSelect.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Select } from "@radix-ui/themes"; -import { useContext } from "react"; - -import { DocItemContext } from "@site/src/context"; - -export const AppTypeSelect = () => { - const { appType, onChangeAppType } = useContext(DocItemContext); - - return ( - - - - Single App Setup - Multi App Setup - - - ); -}; diff --git a/src/components/Select/GoFrameworksSelect.tsx b/src/components/Select/GoFrameworksSelect.tsx deleted file mode 100644 index 4a94e894b7..0000000000 --- a/src/components/Select/GoFrameworksSelect.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useSelectionStore } from "@site/src/hooks"; -import { useMemo } from "react"; - -const GoFrameworksSelectionName = "go-framework"; -const GoFrameworksDefaultValue = "chi"; - -const GoFrameworkOptions = [ - { label: "Chi", value: "chi" }, - { label: "net/http", value: "http" }, - { label: "Gin", value: "gin" }, - { label: "Mux", value: "mux" }, -]; - -export function useGoFrameworksSelection() { - return useSelectionStore(GoFrameworksSelectionName, GoFrameworksDefaultValue); -} - -export function GoFrameworksSelect({ exclude }: { exclude?: string[] }) { - const [value, setValue] = useGoFrameworksSelection(); - const selectOptions = useMemo(() => { - if (exclude) return GoFrameworkOptions.filter((tabItem) => !exclude.includes(tabItem.value)); - return GoFrameworkOptions; - }, [exclude]); - - return ( - - - - {selectOptions.map((option) => ( - - {option.label} - - ))} - - - ); -} diff --git a/src/components/Select/JavascriptHttpLibrarySelect.tsx b/src/components/Select/JavascriptHttpLibrarySelect.tsx deleted file mode 100644 index 814a7a9e9a..0000000000 --- a/src/components/Select/JavascriptHttpLibrarySelect.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useSelectionStore } from "@site/src/hooks"; - -const JavascriptHttpLibrarySelectionName = "javascript-http-library"; -const JavascriptHttpLibraryDefaultValue = "fetch"; - -export function useJavascriptHttpLibrarySelection() { - return useSelectionStore(JavascriptHttpLibrarySelectionName, JavascriptHttpLibraryDefaultValue); -} - -export function JavascriptHttpLibrarySelect() { - const [value, setValue] = useJavascriptHttpLibrarySelection(); - - return ( - - - - fetch - axios - - - ); -} diff --git a/src/components/Select/MobileFrameworksSelect.tsx b/src/components/Select/MobileFrameworksSelect.tsx deleted file mode 100644 index f6646d914b..0000000000 --- a/src/components/Select/MobileFrameworksSelect.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useSelectionStore } from "@site/src/hooks"; -import { useMemo } from "react"; - -const MobileFrameworksSelectionName = "mobile-frameworks"; -const MobileFrameworksDefaultValue = "reactnative"; - -const MobileFrameworksOptions = [ - { label: "React Native", value: "reactnative" }, - { label: "Android", value: "android" }, - { label: "iOS", value: "ios" }, - { label: "Flutter", value: "flutter" }, -]; - -export function useMobileFrameworksSelection() { - return useSelectionStore(MobileFrameworksSelectionName, MobileFrameworksDefaultValue); -} - -export function MobileFrameworksSelect({ exclude }: { exclude?: string[] }) { - const [value, setValue] = useMobileFrameworksSelection(); - const selectOptions = useMemo(() => { - if (exclude) return MobileFrameworksOptions.filter((tabItem) => !exclude.includes(tabItem.value)); - return MobileFrameworksOptions; - }, [exclude]); - - return ( - - - - {selectOptions.map((option) => ( - - {option.label} - - ))} - - - ); -} diff --git a/src/components/Select/NextjsRouterTypeSelect.tsx b/src/components/Select/NextjsRouterTypeSelect.tsx deleted file mode 100644 index 63fb540109..0000000000 --- a/src/components/Select/NextjsRouterTypeSelect.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useDocPageData } from "@site/src/hooks"; -import { docPageStore } from "@site/src/lib"; - -export function NextjsRouterTypeSelect() { - const nextjsRouterType = useDocPageData("nextjsRouterType"); - return ( - docPageStore.updateValue("nextjsRouterType", value as "app-router" | "pages-router")} - > - - - App Router - Pages Router - - - ); -} diff --git a/src/components/Select/NodeFrameworksSelect.tsx b/src/components/Select/NodeFrameworksSelect.tsx deleted file mode 100644 index a07d85d1b4..0000000000 --- a/src/components/Select/NodeFrameworksSelect.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useSelectionStore } from "@site/src/hooks"; -import { useMemo } from "react"; - -const NodeFrameworksSelectionName = "node-frameworks"; -const NodeFrameworksDefaultValue = "express"; - -const NodeFrameworksOptions = [ - { label: "Express", value: "express" }, - { label: "Hapi", value: "hapi" }, - { label: "Fastify", value: "fastify" }, - { label: "Koa", value: "koa" }, - { label: "Loopback", value: "loopback" }, - { label: "AWS Lambda / Netlify", value: "awsLambda" }, - { label: "Next.js", value: "nextjs" }, - { label: "NestJS", value: "nestjs" }, -]; - -export function useNodeFrameworksSelection() { - return useSelectionStore(NodeFrameworksSelectionName, NodeFrameworksDefaultValue); -} - -export function NodeFrameworksSelect({ exclude }: { exclude?: string[] }) { - const [value, setValue] = useNodeFrameworksSelection(); - const selectOptions = useMemo(() => { - if (exclude) return NodeFrameworksOptions.filter((tabItem) => !exclude.includes(tabItem.value)); - return NodeFrameworksOptions; - }, [exclude]); - - return ( - - - - {selectOptions.map((option) => ( - - {option.label} - - ))} - - - ); -} diff --git a/src/components/Select/NodePackageManagerSelect.tsx b/src/components/Select/NodePackageManagerSelect.tsx deleted file mode 100644 index a63ee3823a..0000000000 --- a/src/components/Select/NodePackageManagerSelect.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useSelectionStore } from "@site/src/hooks"; - -const NodePackageManagerSelectioName = "node-package-manager"; -const NodePackageManagerDefaultValue = "npm"; - -export function useNodePackageManagerSelection() { - return useSelectionStore(NodePackageManagerSelectioName, NodePackageManagerDefaultValue); -} - -export function NodePackageManagerSelect() { - const [value, setValue] = useNodePackageManagerSelection(); - return ( - - - - npm - yarn - pnpm - bun - - - ); -} diff --git a/src/components/Select/NpmOrScriptsSelect.tsx b/src/components/Select/NpmOrScriptsSelect.tsx deleted file mode 100644 index 78905bbd06..0000000000 --- a/src/components/Select/NpmOrScriptsSelect.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useSelectionStore } from "@site/src/hooks"; - -const NpmOrScriptsSelectionName = "npm-or-scripts"; -const NpmOrScriptsDefaultValue = "npm"; - -export function useNpmOrScriptsSelection() { - return useSelectionStore(NpmOrScriptsSelectionName, NpmOrScriptsDefaultValue); -} - -export function NpmOrScriptsSelect() { - const [value, setValue] = useNpmOrScriptsSelection(); - - return ( - - - - Via NPM - Via Scripts - - - ); -} diff --git a/src/components/Select/PasswordlessContactMethodSelect.tsx b/src/components/Select/PasswordlessContactMethodSelect.tsx deleted file mode 100644 index 0cb43f2184..0000000000 --- a/src/components/Select/PasswordlessContactMethodSelect.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Select } from "@radix-ui/themes"; -import { useCallback, useContext } from "react"; - -import { DocItemContext } from "@site/src/context"; - -const SelectOptions = [ - { value: "EMAIL", label: "Email" }, - { value: "PHONE", label: "Phone" }, - { value: "EMAIL_OR_PHONE", label: "Email or Phone" }, -]; - -export const PasswordlessContactMethodSelect = () => { - const { recipes, onChangeRecipeProperty } = useContext(DocItemContext); - - const contactMethod = recipes.passwordless.contactMethod; - const onChange = useCallback( - (value) => { - onChangeRecipeProperty("passwordless", "contactMethod", value); - }, - [onChangeRecipeProperty], - ); - - const valueLabel = SelectOptions.find((option) => option.value === contactMethod)?.label; - - return ( - - Contact Method: {valueLabel} - - {SelectOptions.map((option) => ( - - {option.label} - - ))} - - - ); -}; diff --git a/src/components/Select/PasswordlessFlowTypeSelect.tsx b/src/components/Select/PasswordlessFlowTypeSelect.tsx deleted file mode 100644 index f5be1d88de..0000000000 --- a/src/components/Select/PasswordlessFlowTypeSelect.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Select } from "@radix-ui/themes"; -import { useCallback, useContext } from "react"; - -import { DocItemContext } from "@site/src/context"; - -const SelectOptions = [ - { value: "MAGIC_LINK", label: "Magic Link" }, - { value: "USER_INPUT_CODE", label: "OTP" }, - { value: "USER_INPUT_CODE_AND_MAGIC_LINK", label: "Magic Link and OTP" }, -]; - -export const PasswordlessFlowTypeSelect = () => { - const { recipes, onChangeRecipeProperty } = useContext(DocItemContext); - - const flowType = recipes.passwordless.flowType; - const onChange = useCallback( - (value) => { - onChangeRecipeProperty("passwordless", "flowType", value); - }, - [onChangeRecipeProperty], - ); - - const valueLabel = SelectOptions.find((option) => option.value === flowType)?.label; - - return ( - - Flow Type: {valueLabel} - - {SelectOptions.map((option) => ( - - {option.label} - - ))} - - - ); -}; diff --git a/src/components/Select/PythonFrameworksSelect.tsx b/src/components/Select/PythonFrameworksSelect.tsx deleted file mode 100644 index 9ba6a40bf9..0000000000 --- a/src/components/Select/PythonFrameworksSelect.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useSelectionStore } from "@site/src/hooks"; -import { useMemo } from "react"; - -const PythonFrameworksSelectionName = "python-framework"; -const PythonFrameworksDefaultValue = "fastapi"; -const PythonFrameworksOptions = [ - { label: "FastAPI", value: "fastapi" }, - { label: "Flask", value: "flask" }, - { label: "Django", value: "django" }, -]; - -export function usePythonFrameworksSelection() { - return useSelectionStore(PythonFrameworksSelectionName, PythonFrameworksDefaultValue); -} - -export function PythonFrameworksSelect({ exclude }: { exclude?: string[] }) { - const [value, setValue] = usePythonFrameworksSelection(); - - const selectOptions = useMemo(() => { - if (exclude) return PythonFrameworksOptions.filter((tabItem) => !exclude.includes(tabItem.value)); - return PythonFrameworksOptions; - }, [exclude]); - - return ( - - - - {selectOptions.map((option) => ( - - {option.label} - - ))} - - - ); -} diff --git a/src/components/Select/PythonPackageManagerSelect.tsx b/src/components/Select/PythonPackageManagerSelect.tsx deleted file mode 100644 index 7bedcbabaf..0000000000 --- a/src/components/Select/PythonPackageManagerSelect.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useSelectionStore } from "@site/src/hooks"; - -const PythonPackageManagerSelectionName = "python-package-manager"; -const PythonPackageManagerDefaultValue = "pip"; - -export function usePythonPackageManagerSelection() { - return useSelectionStore(PythonPackageManagerSelectionName, PythonPackageManagerDefaultValue); -} - -export function PythonPackageManagerSelect() { - const [value, setValue] = usePythonPackageManagerSelection(); - - return ( - - - - pip - uv - - - ); -} diff --git a/src/components/Select/PythonSyncAsyncSelect.tsx b/src/components/Select/PythonSyncAsyncSelect.tsx deleted file mode 100644 index 89e19adf95..0000000000 --- a/src/components/Select/PythonSyncAsyncSelect.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useSelectionStore } from "@site/src/hooks"; -import { useMemo } from "react"; - -const PythonSyncAsyncSelectionName = "python-sync-async"; -const PythonSyncAsyncDefaultValue = "syncio"; -const PythonFrameworksOptions = [ - { label: "asyncio", value: "asyncio" }, - { label: "syncio", value: "syncio" }, -]; - -export function usePythonSyncAsyncSelection() { - return useSelectionStore(PythonSyncAsyncSelectionName, PythonSyncAsyncDefaultValue); -} - -export function PythonSyncAsyncSelect({ exclude }: { exclude?: string[] }) { - const [value, setValue] = usePythonSyncAsyncSelection(); - const selectOptions = useMemo(() => { - if (exclude) return PythonFrameworksOptions.filter((tabItem) => !exclude.includes(tabItem.value)); - return PythonFrameworksOptions; - }, [exclude]); - - return ( - - - - {selectOptions.map((option) => ( - - {option.label} - - ))} - - - ); -} diff --git a/src/components/Select/SelfHostedDeploymentTypeSelect.tsx b/src/components/Select/SelfHostedDeploymentTypeSelect.tsx deleted file mode 100644 index 47430764f0..0000000000 --- a/src/components/Select/SelfHostedDeploymentTypeSelect.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useDocPageData } from "@site/src/hooks"; -import { docPageStore } from "@site/src/lib"; - -export function SelfHostedDeploymentTypeSelect() { - const selfHostedDeploymentType = useDocPageData("selfHostedDeploymentType"); - return ( - - docPageStore.updateValue("selfHostedDeploymentType", value as "with-docker" | "without-docker") - } - > - - - With Docker - Without Docker - - - ); -} diff --git a/src/components/Select/TenantTypeSelect.tsx b/src/components/Select/TenantTypeSelect.tsx deleted file mode 100644 index 135d379e97..0000000000 --- a/src/components/Select/TenantTypeSelect.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useDocPageData } from "@site/src/hooks"; -import { docPageStore } from "@site/src/lib"; - -export function TenantTypeSelect() { - const tenantType = useDocPageData("tenantType"); - return ( - docPageStore.updateValue("tenantType", value as "single-tenant" | "multi-tenant")} - > - - - Single Tenant - Multi Tenant - - - ); -} diff --git a/src/components/Select/ThirdpartyBuiltinProvidersSelect.tsx b/src/components/Select/ThirdpartyBuiltinProvidersSelect.tsx deleted file mode 100644 index 9a6dfc5aa5..0000000000 --- a/src/components/Select/ThirdpartyBuiltinProvidersSelect.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Select } from "@radix-ui/themes"; - -import { useSelectionStore } from "@site/src/hooks"; -import { useMemo } from "react"; - -const ThirdPartyBuiltinProvidersSelectionName = "thirdparty-builtin-providers"; -const ThirdPartyBuiltinProvidersDefaultValue = "chi"; - -const ThirdPartyBuiltinProviderOptions = [ - { label: "Google", value: "google" }, - { label: "Google Workspace", value: "google-workspace" }, - { label: "Apple", value: "apple" }, - { label: "Discord", value: "discord" }, - { label: "Facebook", value: "facebook" }, - { label: "GitHub", value: "github" }, - { label: "Linkedin", value: "linkedin" }, - { label: "Twitter", value: "twitter" }, - { label: "Active Directory", value: "active-directory" }, - { label: "OKTA", value: "okta" }, - { label: "Bitbucket", value: "bitbucket" }, - { label: "GitLab", value: "gitlab" }, - { label: "SAML Login", value: "saml" }, -]; - -export function useThirdPartyBuiltinProvidersSelection() { - return useSelectionStore(ThirdPartyBuiltinProvidersSelectionName, ThirdPartyBuiltinProvidersDefaultValue); -} - -export function ThirdPartyBuiltinProvidersSelect({ exclude }: { exclude?: string[] }) { - const [value, setValue] = useThirdPartyBuiltinProvidersSelection(); - const selectOptions = useMemo(() => { - if (exclude) return ThirdPartyBuiltinProviderOptions.filter((tabItem) => !exclude.includes(tabItem.value)); - return ThirdPartyBuiltinProviderOptions; - }, [exclude]); - - return ( - - - - {selectOptions.map((option) => ( - - {option.label} - - ))} - - - ); -} diff --git a/src/components/Select/index.ts b/src/components/Select/index.ts deleted file mode 100644 index 717efb6969..0000000000 --- a/src/components/Select/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -export * from "./NpmOrScriptsSelect"; -export * from "./NodePackageManagerSelect"; -export * from "./MobileFrameworksSelect"; -export * from "./NodeFrameworksSelect"; -export * from "./GoFrameworksSelect"; -export * from "./PythonFrameworksSelect"; -export * from "./JavascriptHttpLibrarySelect"; -export * from "./PythonSyncAsyncSelect"; -export * from "./PythonPackageManagerSelect"; -export * from "./ThirdpartyBuiltinProvidersSelect"; -export * from "./AppTypeSelect"; -export * from "./PasswordlessFlowTypeSelect"; -export * from "./PasswordlessContactMethodSelect"; -export * from "./NextjsRouterTypeSelect"; -export * from "./AccountTypeSelect"; -export * from "./SelfHostedDeploymentTypeSelect"; -export * from "./TenantTypeSelect"; diff --git a/src/components/Separator.tsx b/src/components/Separator.tsx deleted file mode 100644 index 84cb1a7495..0000000000 --- a/src/components/Separator.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { Separator as RadixSeparator } from "@radix-ui/themes"; - -type MarginProp = "1" | "2" | "3" | "5" | "6"; - -export function Separator({ mt = "5", mb = "3" }: { mt: MarginProp; mb: MarginProp }) { - return ; -} diff --git a/src/components/Steps.tsx b/src/components/Steps.tsx deleted file mode 100644 index afdc72ca33..0000000000 --- a/src/components/Steps.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { Flex, Badge, Text, Heading, Separator, Box } from "@radix-ui/themes"; -import { Children, cloneElement, createContext, isValidElement, useContext } from "react"; -import { ParagraphStripper } from "./StripParagraph"; - -const StepContext = createContext({} as { position: number; isLast: boolean }); - -function Step({ - isLast = false, - position = 1, - children, -}: React.PropsWithChildren<{ isLast?: boolean; position?: number }>) { - return ( - - - {children} - - - - ); -} - -function StepHeader({ children }: React.PropsWithChildren<{}>) { - return ( - - - - {children} - - - ); -} - -function StepDescription({ children }: React.PropsWithChildren<{}>) { - return ( - - {children} - - ); -} - -function StepBadge() { - const { position } = useContext(StepContext); - - return ( - - - {position} - - - ); -} - -function StepSeparator() { - const { isLast } = useContext(StepContext); - if (isLast) return null; - - return ( - - - - ); -} - -// The component works in two modes -// 1. jsx - you define the content explicitly -// by using the Step components , , -// -// 2. mdx - the component parses mdx content -// and transforms it into components -// -// ## Step Name -// Content -// ## Step Name -// Content -// -function StepsRoot({ children, mode = "jsx" }: React.PropsWithChildren<{ mode?: "jsx" | "mdx" }>) { - const childrenArray = Children.toArray(children); - - if (mode === "jsx") { - return ( - - {childrenArray.map((child, index) => { - if (!isValidElement(child)) return child; - return cloneElement(child, { - // @ts-expect-error - isLast: index === childrenArray.length - 1, - position: index + 1, - key: child.key || index, - }); - })} - - ); - } - - const steps: { title: React.ReactNode; description: React.ReactNode }[] = []; - let currentStep: { title: React.ReactNode; description: React.ReactNode } = null; - - for (const child of childrenArray) { - // @ts-expect-error The array should always include elements as children - if (["h2", "h3", "h4", "h5", "h6"].includes(child.type.name)) { - if (currentStep) { - steps.push(currentStep); - } - // @ts-expect-error - currentStep = { title: child.props.children, description: [] }; - } else { - // @ts-expect-error - currentStep.description.push(child); - } - } - steps.push(currentStep); - - return ( - - {steps.map(({ title, description }, index) => ( - - {title} - {description} - - ))} - - ); -} - -export const Steps = Object.assign(StepsRoot, { - Step, - StepHeader, - StepDescription, - StepBadge, - StepSeparator, -}); diff --git a/src/components/StripParagraph.tsx b/src/components/StripParagraph.tsx deleted file mode 100644 index a7c6c47e4e..0000000000 --- a/src/components/StripParagraph.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React, { isValidElement } from "react"; - -interface ParagraphStripperProps { - children: React.ReactNode; -} - -export const ParagraphStripper: React.FC = ({ children }) => { - if (isValidElement(children) && children.type === "p") { - return children.props.children; - } - - return children; -}; diff --git a/src/components/Tabs/BackendTabs.tsx b/src/components/Tabs/BackendTabs.tsx deleted file mode 100644 index bb9b3c0f6c..0000000000 --- a/src/components/Tabs/BackendTabs.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import Tabs, { Props as TabsProps } from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; -import { useMemo } from "react"; - -const BackendLanguagesTabOptions = [ - { label: "NodeJS", value: "nodejs" }, - { label: "GoLang", value: "go" }, - { label: "Python", value: "python" }, -]; - -const BackendTabsGroupId = "backend-language"; - -type BackendTabsProps = Omit & { - exclude?: string[]; - // TODO: Remove this. - // Temporary solution for places where we show stuff like "Dashboard" and "cURL" - additionalValues?: { label: string; value: string }[]; -}; - -function BackendTabsRoot(props: BackendTabsProps) { - const { children, exclude, additionalValues, ...rest } = props; - - const tabOptions = useMemo(() => { - const allOptions = additionalValues - ? [...BackendLanguagesTabOptions, ...additionalValues] - : BackendLanguagesTabOptions; - if (exclude) return allOptions.filter((tabItem) => !exclude.includes(tabItem.value)); - return allOptions; - }, [BackendLanguagesTabOptions, exclude, additionalValues]); - - return ( - - {children} - - ); -} - -export const BackendTabs = Object.assign(BackendTabsRoot, { - Tab: TabItem, - TabItem, -}); diff --git a/src/components/Tabs/DatabaseTabs.tsx b/src/components/Tabs/DatabaseTabs.tsx deleted file mode 100644 index 7791edcbfb..0000000000 --- a/src/components/Tabs/DatabaseTabs.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import Tabs, { Props as TabsProps } from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; -import { useMemo } from "react"; - -const DatabaseTabsOptions = [ - { label: "MySQL", value: "mysql" }, - { label: "PostgreSQL", value: "postgresql" }, -]; - -const DatabaseTabsGroupId = "database"; - -type DatabaseTabsProps = Omit & { - exclude?: string[]; -}; - -function DatabaseTabsRoot(props: DatabaseTabsProps) { - const { children, exclude, ...rest } = props; - - const tabOptions = useMemo(() => { - if (exclude) return DatabaseTabsOptions.filter((v) => !exclude.includes(v.value)); - return DatabaseTabsOptions; - }, [exclude]); - - return ( - - {children} - - ); -} - -export const DatabaseTabs = Object.assign(DatabaseTabsRoot, { - Tab: TabItem, - TabItem, -}); diff --git a/src/components/Tabs/FrontendCustomUITabs.tsx b/src/components/Tabs/FrontendCustomUITabs.tsx deleted file mode 100644 index 3a82b4d199..0000000000 --- a/src/components/Tabs/FrontendCustomUITabs.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import Tabs, { Props as TabsProps } from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - -const FrontendCustomUITabOptions = [ - { label: "Web", value: "web" }, - { label: "Mobile", value: "mobile" }, -]; - -const FrontendCustomUIGroupId = "frontend-custom-ui"; - -type FrontendCustomUIProps = Omit; - -function FrontendCustomUIRoot(props: FrontendCustomUIProps) { - const { children, ...rest } = props; - - return ( - - {children} - - ); -} - -export const FrontendCustomUITabs = Object.assign(FrontendCustomUIRoot, { - TabItem, -}); diff --git a/src/components/Tabs/FrontendPrebuiltUITabs.tsx b/src/components/Tabs/FrontendPrebuiltUITabs.tsx deleted file mode 100644 index 2eb5e3f55c..0000000000 --- a/src/components/Tabs/FrontendPrebuiltUITabs.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import Tabs, { Props as TabsProps } from "@theme/Tabs"; -import { Children, cloneElement, isValidElement, ReactElement, useMemo } from "react"; -import type { Props as TabItemProps } from "@theme/TabItem"; -import TabItem from "@theme/TabItem"; - -const FrontendPrebuiltUITabOptions = [ - { label: "ReactJS", value: "reactjs" }, - { label: "Angular", value: "angular" }, - { label: "Vue", value: "vue" }, -]; - -const FrontendPrebuiltUIGroupId = "frontend-prebuilt-ui"; - -type FrontendPrebuiltUIProps = Omit & { - additionalValues?: { label: string; value: string }[]; - exclude?: string[]; -}; - -function FrontendPrebuiltUIRoot(props: FrontendPrebuiltUIProps) { - const { children, exclude, additionalValues, ...rest } = props; - let parsedChildren = children; - const childrenArray = Children.toArray(children); - const vueTabItem = childrenArray.find( - (child): child is ReactElement => isValidElement(child) && child.props.value === "vue", - ); - const angularTabItem = childrenArray.find( - (child): child is ReactElement => isValidElement(child) && child.props.value === "angular", - ); - - const tabOptions = useMemo(() => { - const allOptions = additionalValues - ? [...FrontendPrebuiltUITabOptions, ...additionalValues] - : FrontendPrebuiltUITabOptions; - if (exclude) return allOptions.filter((tabItem) => !exclude.includes(tabItem.value)); - return allOptions; - }, [FrontendPrebuiltUITabOptions, exclude, additionalValues]); - - if (!vueTabItem && angularTabItem) { - parsedChildren = [ - // @ts-expect-error - TODO: Can't figure out the proper type here - ...childrenArray, - // @ts-expect-error - cloneElement(angularTabItem, { key: `vue-tab-item`, value: "vue" }), - ]; - } - - return ( - - {parsedChildren} - - ); -} - -export const FrontendPrebuiltUITabs = Object.assign(FrontendPrebuiltUIRoot, { - TabItem, -}); diff --git a/src/components/Tabs/FrontendTabs.tsx b/src/components/Tabs/FrontendTabs.tsx deleted file mode 100644 index 0116023cf1..0000000000 --- a/src/components/Tabs/FrontendTabs.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import Tabs, { Props as TabsProps } from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; -import { useContext, useMemo } from "react"; -import { DocItemContext } from "@site/src/context"; -import { useUIType } from "@site/src/hooks"; - -// TODO: Rename values to items -const PrebuiltUITabValues = [ - { label: "ReactJS", value: "reactjs" }, - { label: "Angular", value: "angular" }, - { label: "Vue", value: "vue" }, - { label: "Mobile", value: "mobile" }, -]; - -const CustomUITabValues = [ - { label: "Web", value: "web" }, - { label: "Mobile", value: "mobile" }, -]; - -const FrontendTabsGroupIdPrefix = "frontend-tabs"; - -type FrontendTabsProps = Omit & { - exclude?: string[]; - uiType?: string; -}; - -function FrontendTabsRoot(props: FrontendTabsProps) { - const { children, exclude, uiType: propsUiType, ...rest } = props; - const { uiType: contextUiType } = useUIType(); - const uiType = propsUiType || contextUiType; - const groupId = useMemo(() => { - return `${FrontendTabsGroupIdPrefix}-${uiType}`; - }, [uiType]); - const baseTabValues = useMemo(() => { - if (uiType === "prebuilt") return PrebuiltUITabValues; - return CustomUITabValues; - }, [uiType]); - - const values = useMemo(() => { - if (!exclude) return baseTabValues; - return baseTabValues.filter((tabValue) => !exclude.includes(tabValue.value)); - }, [exclude, baseTabValues]); - - return ( - - {children} - - ); -} - -export const FrontendTabs = Object.assign(FrontendTabsRoot, { - Tab: TabItem, -}); diff --git a/src/components/Tabs/OSTabs.tsx b/src/components/Tabs/OSTabs.tsx deleted file mode 100644 index 9f3e4c84bc..0000000000 --- a/src/components/Tabs/OSTabs.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import Tabs, { Props as TabsProps } from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; -import { useMemo } from "react"; - -const OSTabsOptions = [ - { value: "linux", label: "Linux" }, - { value: "mac", label: "macOS" }, - { value: "windows", label: "Windows" }, -]; - -const OSTabsGroupId = "os"; - -type OSTabsProps = Omit & { - exclude?: string[]; -}; - -function OSTabsRoot(props: OSTabsProps) { - const { children, exclude, ...rest } = props; - - const tabOptions = useMemo(() => { - if (exclude) return OSTabsOptions.filter((v) => !exclude.includes(v.value)); - return OSTabsOptions; - }, [exclude]); - - return ( - - {children} - - ); -} - -export const OSTabs = Object.assign(OSTabsRoot, { - Tab: TabItem, - TabItem, -}); diff --git a/src/components/Tabs/ReactRouterVersionsTabs.tsx b/src/components/Tabs/ReactRouterVersionsTabs.tsx deleted file mode 100644 index 05dbaeda42..0000000000 --- a/src/components/Tabs/ReactRouterVersionsTabs.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import Tabs, { Props as TabsProps } from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - -const ReactRouterVersionTabItems = [ - { label: "react-router-dom >= v6", value: "v6" }, - { label: "react-router-dom <= v5", value: "v5" }, -]; - -const ReactRouterVersionTabsGroupId = "react-router-version"; - -type ReactRouterVersionTabsProps = Omit; - -function ReactRouterVersionTabsRoot(props: ReactRouterVersionTabsProps) { - const { children, ...rest } = props; - - return ( - - {children} - - ); -} - -export const ReactRouterVersionTabs = Object.assign(ReactRouterVersionTabsRoot, { - Tab: TabItem, - TabItem, -}); diff --git a/src/components/Tabs/RowndFrontendTabs.tsx b/src/components/Tabs/RowndFrontendTabs.tsx deleted file mode 100644 index 7daf0e13d6..0000000000 --- a/src/components/Tabs/RowndFrontendTabs.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import Tabs, { Props as TabsProps } from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - -const RowndFrontendTabOptions = [ - { label: "React", value: "react" }, - { label: "WebJS", value: "webjs" }, - { label: "Android", value: "android" }, - { label: "iOS", value: "ios" }, - { label: "Flutter", value: "flutter" }, - { label: "React Native", value: "react-native" }, -]; - -const RowndFrontendTabsGroupId = "rownd-frontend"; - -type RowndFrontendTabsProps = Omit; - -function RowndFrontendTabsRoot(props: RowndFrontendTabsProps) { - const { children, ...rest } = props; - - return ( - - {children} - - ); -} - -export const RowndFrontendTabs = Object.assign(RowndFrontendTabsRoot, { - TabItem, -}); diff --git a/src/components/Tabs/SelfHostingTabs.tsx b/src/components/Tabs/SelfHostingTabs.tsx deleted file mode 100644 index 6ab0b75497..0000000000 --- a/src/components/Tabs/SelfHostingTabs.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import Tabs, { Props as TabsProps } from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; -import { useMemo } from "react"; - -const SelfHostingTabsOptions = [ - { label: "With Docker", value: "with-docker" }, - { label: "Without Docker", value: "without-docker" }, -]; - -const SelfHostingTabsGroupId = "self-hosting"; - -type SelfHostingTabsProps = Omit & { - exclude?: string[]; -}; - -function SelfHostingTabsRoot(props: SelfHostingTabsProps) { - const { children, exclude, ...rest } = props; - - const tabOptions = useMemo(() => { - if (exclude) return SelfHostingTabsOptions.filter((v) => !exclude.includes(v.value)); - return SelfHostingTabsOptions; - }, [exclude]); - - return ( - - {children} - - ); -} - -export const SelfHostingTabs = Object.assign(SelfHostingTabsRoot, { - Tab: TabItem, - TabItem, -}); diff --git a/src/components/Tabs/index.ts b/src/components/Tabs/index.ts deleted file mode 100644 index 5c86ea5b0c..0000000000 --- a/src/components/Tabs/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from "./FrontendTabs"; -export * from "./BackendTabs"; -export * from "./SelfHostingTabs"; -export * from "./FrontendCustomUITabs"; -export * from "./FrontendPrebuiltUITabs"; -export * from "./ReactRouterVersionsTabs"; -export * from "./DatabaseTabs"; -export * from "./OSTabs"; -export * from "./RowndFrontendTabs"; diff --git a/src/components/TenantTypeSwitch.tsx b/src/components/TenantTypeSwitch.tsx deleted file mode 100644 index 840a2c67f3..0000000000 --- a/src/components/TenantTypeSwitch.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React, { useContext } from "react"; -import { DocItemContext } from "@site/src/context"; -import { Card, Flex, Heading, RadioCards, Text } from "@radix-ui/themes"; -import { useIsVisible } from "../hooks"; - -function TenantTypeSwitch({}) { - const { tenantType, onChangeTenantType } = useContext(DocItemContext); - const { visibilityRef, isVisible } = useIsVisible(); - - return ( - - - - What is your setup type? - - - - onChangeTenantType("single")}> - - Single Tenant - One common user pool for your entire application - - - onChangeTenantType("multi")}> - - Multi Tenant - Different users pools grouped by tenant - - - - - - - ); -} - -function HeadingFilter({ children, name }: React.PropsWithChildren<{ name: string }>) { - return
    {children}
    ; -} - -function SingleTenantContent({ children }: React.PropsWithChildren<{}>) { - const state = useContext(DocItemContext); - - return {state.tenantType === "single" ? children : null}; -} - -function MultiTenantContent({ children }: React.PropsWithChildren<{}>) { - const state = useContext(DocItemContext); - - return {state.tenantType === "multi" ? children : null}; -} - -export const TenantType = { - Switch: TenantTypeSwitch, - SingleTenantContent, - MultiTenantContent, -}; diff --git a/src/components/Typography.tsx b/src/components/Typography.tsx deleted file mode 100644 index 624ed7dc0f..0000000000 --- a/src/components/Typography.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { Heading } from "@radix-ui/themes"; -import { forwardRef } from "react"; - -/** - * This allows use to prevent headings from being - * collected by the remark-toc plugin - * and then placed in the page TOC. - * Example: we don't want to show headings that - * are used in a modal inside the TOC. - * - */ - -export const H1 = forwardRef< - React.ElementRef, - Omit, "as"> ->(({ className, children, ...props }, ref) => ( - - {children} - -)); -H1.displayName = "H1"; - -export const H2 = forwardRef< - React.ElementRef, - Omit, "as"> ->(({ className, children, ...props }, ref) => ( - - {children} - -)); -H2.displayName = "H2"; - -export const H3 = forwardRef< - React.ElementRef, - Omit, "as"> ->(({ className, children, ...props }, ref) => ( - - {children} - -)); - -H3.displayName = "H3"; - -export const H4 = forwardRef< - React.ElementRef, - Omit, "as"> ->(({ className, children, ...props }, ref) => ( - - {children} - -)); - -H4.displayName = "H4"; - -export const H5 = forwardRef< - React.ElementRef, - Omit, "as"> ->(({ className, children, ...props }, ref) => ( - - {children} - -)); - -H5.displayName = "H5"; - -export const H6 = forwardRef< - React.ElementRef, - Omit, "as"> ->(({ className, children, ...props }, ref) => ( - - {children} - -)); - -H6.displayName = "H6"; diff --git a/src/components/UITypeSwitch.tsx b/src/components/UITypeSwitch.tsx deleted file mode 100644 index b8b83feade..0000000000 --- a/src/components/UITypeSwitch.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, { useCallback, useContext, useEffect, useRef } from "react"; -import ReactDOM from "react-dom"; -import { DocItemContext } from "@site/src/context"; -import { Card, Flex, Heading, RadioCards, Text } from "@radix-ui/themes"; -import BrowserOnly from "@docusaurus/BrowserOnly"; -import { AnimatePresence, motion } from "motion/react"; -import { TOC_UI_TYPE_SWITCH_ID } from "../lib"; -import { useIsVisible, useUIType } from "../hooks"; - -import "./RadioCard.scss"; - -function UITypeSwitch({}) { - const { uiType, onChangeUIType } = useUIType(); - const { visibilityRef, isVisible } = useIsVisible(); - - return ( - - - - What type of UI are you using? - - - - onChangeUIType("prebuilt")}> - - Pre-Built UI - Authentication UI provided by SuperTokens - - - onChangeUIType("custom")}> - - Custom UI - Authentication UI created by you - - - - - {() => } - - - ); -} - -function TOCSwitch({ isParentVisible }: { isParentVisible: boolean }) { - const { uiType, onChangeUIType } = useUIType(); - const root = document.getElementById(TOC_UI_TYPE_SWITCH_ID); - const elementRef = useRef(null); - if (!root) return null; - return ReactDOM.createPortal( - - {!isParentVisible && ( - - - - - UI Type - - - onChangeUIType("prebuilt")} - > - - Pre-Built - - - onChangeUIType("custom")}> - - Custom - - - - - - - )} - , - root, - ); -} - -function HeadingFilter({ children, name }: React.PropsWithChildren<{ name: string }>) { - return
    {children}
    ; -} - -function PrebuiltUIContent({ children }: React.PropsWithChildren<{}>) { - const { uiType } = useUIType(); - - return {uiType === "prebuilt" ? children : null}; -} - -function CustomUIContent({ children }: React.PropsWithChildren<{}>) { - const { uiType } = useUIType(); - - return {uiType === "custom" ? children : null}; -} - -export const UIType = { - Switch: UITypeSwitch, - PrebuiltUIContent, - CustomUIContent, -}; diff --git a/src/components/index.ts b/src/components/index.ts deleted file mode 100644 index bdb4abf676..0000000000 --- a/src/components/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -export * from "./Separator"; -export * from "./TenantTypeSwitch"; -export * from "./UITypeSwitch"; -export * from "./Cards"; -export * from "./SDKCompatibilityTable"; -export * from "./Callouts"; -export * from "./Forms"; -export * from "./Select"; -export * from "./Tabs"; -export * from "./DescriptionText"; -export * from "./DocItemContextValue"; -export * from "./DocItemContextCondition"; -export * from "./ConditionalContent"; -export * from "./Steps"; -export * from "./Accordion"; -export * from "./PaidFeatureCallout"; -export * from "./APIRequest"; -export * from "./RemoveForLLMs"; -export * from "./Question"; -export * from "./TenantTypeSwitch"; -export * from "./Typography"; -export * from "./CopyPageContentButton"; -export * from "./PageOptionsDropdownMenu"; -export * from "./Search"; -export * from "./ColorModeToggle"; -export * from "./SDKReference"; diff --git a/src/context/DocItemContext.tsx b/src/context/DocItemContext.tsx deleted file mode 100644 index ffc62ea7cc..0000000000 --- a/src/context/DocItemContext.tsx +++ /dev/null @@ -1,154 +0,0 @@ -import React, { createContext, useCallback, useEffect, useMemo } from "react"; -import { DocsItemStateType, useDocsItemStore } from "@site/src/hooks"; -import { getAuthReactURI, getWebJsURI } from "@site/src/lib/api"; - -type DocItemContextType = DocsItemStateType & { - derived: Record; - webJsVersions: Record; - prebuiltUIVersion: string; - onChangeTenantType: (type: DocsItemStateType["tenantType"]) => void; - onChangeAppType: (type: DocsItemStateType["tenantType"]) => void; - onChangeRecipeProperty: ( - recipeName: keyof DocsItemStateType["recipes"], - propertyName: string, - propertyValue: unknown, - ) => void; - onChangeAppInfoField: (fieldName: string, value: string) => void; -}; - -export const DocItemContext = createContext({} as DocItemContextType); - -export function DocItemContextProvider({ children }: { children: React.ReactNode }) { - const [state, setState] = useDocsItemStore(); - const [webJsVersions, setWebJsVersions] = React.useState>({}); - const [prebuiltUIVersion, setPrebuiltUIVersion] = React.useState(""); - - const onLoadWebJsVersions = useCallback(async () => { - const result = await getWebJsURI(); - setWebJsVersions(result.uri); - }, []); - - const onLoadPrebuiltUIVersion = useCallback(async () => { - const result = await getAuthReactURI(); - setPrebuiltUIVersion(result.uri); - }, []); - - useEffect(() => { - onLoadWebJsVersions(); - onLoadPrebuiltUIVersion(); - }, []); - - const onChangeTenantType = useCallback( - (type: DocsItemStateType["tenantType"]) => { - setState({ - ...state, - tenantType: type, - }); - }, - [state], - ); - - const onChangeAppType = useCallback( - (type: DocsItemStateType["appType"]) => { - setState({ - ...state, - appType: type, - }); - }, - [state], - ); - - const onChangeAppInfoField = useCallback( - (fieldName: string, value: string) => { - setState({ - ...state, - appInfo: { - ...state.appInfo, - [fieldName]: value, - }, - }); - }, - [state], - ); - - const onChangeRecipeProperty = useCallback( - (recipeName: keyof DocsItemStateType["recipes"], propertyName: string, propertyValue: unknown) => { - setState({ - ...state, - recipes: { - ...state.recipes, - [recipeName]: { - ...state.recipes[recipeName], - [propertyName]: propertyValue, - }, - }, - }); - }, - [state], - ); - - const derivedState = useMemo(() => { - let pythonContactMethodImport = "from supertokens_python.recipe.passwordless import ContactEmailOnlyConfig"; - let pythonContactMethodMethod = "ContactEmailOnlyConfig"; - let goPasswordlessContactMethodMethod = "ContactMethodEmailConfig"; - if (state.recipes?.passwordless?.contactMethod === "PHONE") { - pythonContactMethodImport = "from supertokens_python.recipe.passwordless import ContactPhoneOnlyConfig"; - pythonContactMethodMethod = "ContactPhoneOnlyConfig"; - goPasswordlessContactMethodMethod = "ContactMethodPhoneConfig"; - } else if (state.recipes?.passwordless?.contactMethod === "EMAIL_OR_PHONE") { - pythonContactMethodImport = "from supertokens_python.recipe.passwordless import ContactEmailOrPhoneConfig"; - pythonContactMethodMethod = "ContactEmailOrPhoneConfig"; - goPasswordlessContactMethodMethod = "ContactMethodEmailOrPhoneConfig"; - } - return { - appIdPathname: state.appType === "single" ? "" : `/appid-`, - pythonContactMethodImport, - pythonContactMethodMethod, - goPasswordlessContactMethodMethod, - }; - }, [state]); - - const coreUri = useMemo(() => { - return state.appType === "single" ? state.coreInfo.uri : `${state.coreInfo.uri}/appid-`; - }, [state]); - - return ( - - {children} - - ); -} - -export function getContextValue(obj: Record, key: string, defaultValue?: unknown): unknown { - if (!key) return ""; - if (!obj) { - if (defaultValue) return defaultValue; - return ""; - } - const keys = key.split("."); - let current = obj; - - if (keys.length === 1) { - const value = obj[keys[0]]; - return value || defaultValue; - } - - // @ts-expect-error - current = current[keys[0]]; - return getContextValue(current, keys.slice(1).join("."), defaultValue); -} diff --git a/src/context/TabsContex.tsx b/src/context/TabsContex.tsx deleted file mode 100644 index 6132751265..0000000000 --- a/src/context/TabsContex.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { createContext } from "react"; - -/** - * Utility context used to trigger an error if an incorrect tab value is passed to TabItem components - */ -type TabItem = { value: string; label: string }; -type TabsContextType = { - tabValues: TabItem[]; -}; - -export const TabsContext = createContext({} as TabsContextType); - -export const TabsContextProvider = ({ tabValues, children }: React.PropsWithChildren<{ tabValues: TabItem[] }>) => { - return {children}; -}; diff --git a/src/context/index.ts b/src/context/index.ts deleted file mode 100644 index 1bc8545019..0000000000 --- a/src/context/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./TabsContex"; -export * from "./DocItemContext"; diff --git a/src/css/custom.scss b/src/css/custom.scss deleted file mode 100644 index fd975f388d..0000000000 --- a/src/css/custom.scss +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Any CSS included here will be global. The classic template - * bundles Infima by default. Infima is a CSS framework designed to - * work well for content-centric websites. - */ - -@import "@scalar/api-client-react/style.css"; - -/* You can override the default Infima variables here. */ -:root { - --ifm-color-primary: #ff9933; - --ifm-color-primary-dark: #ff8a14; - --ifm-color-primary-darker: #ff8205; - --ifm-color-primary-darkest: #d66b00; - --ifm-color-primary-light: #ffa852; - --ifm-color-primary-lighter: #ffb061; - --ifm-color-primary-lightest: #ffc78f; - --ifm-code-font-size: 95%; - --ui-selector-background: rgba(0, 98, 255, 0.2); - --ui-selector-active: rgb(0, 98, 255); - --ui-selector-active-border: rgb(75, 143, 250); - --ui-selector-inactive: rgb(95, 95, 95); - --ui-selector-inactive-border: rgb(116, 116, 116); - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); - - // Heading sizes - --ifm-h4-font-size: 1.1rem; - - // Spacing - --ifm-container-width-xl: 1200px; - --ifm-container-max-width: 1000px; - - // Navbar customization - --ifm-navbar-height: 122px; - // Total navbar height including tabs and padding for accurate scroll positioning - --navbar-total-height: 140px; - - @media (max-width: 996px) { - --ifm-navbar-height: 80px; - --navbar-total-height: 80px; // No tabs on mobile - } - - // Doc Sidebar - --doc-sidebar-width: 308px; - - // Light mode colors (default) - --ifm-background-color: #ffffff; - --ifm-font-color-base: #1a1a1a; - --ifm-heading-color: #333333; - --ifm-toc-border-color: #e5e5e5; - --ifm-navbar-background-color: #ffffff; - --ifm-menu-color-active: #ff9933; - --ifm-menu-color-background-active: #fff5e6; - --ifm-menu-color-background-hover: #fafafa; - --ifm-menu-color: #666666; - - // Light mode admonitions - --ifm-color-success-contrast-background: #e8f5e8 !important; - --ifm-color-success-dark: rgba(38, 147, 71, 1); - --ifm-color-info-contrast-background: #e6f3ff !important; - --ifm-color-info-dark: rgba(0, 98, 225, 1); - --ifm-color-not-contrast-background: #f5f5f5 !important; - --ifm-color-note-dark: rgba(95, 95, 95, 1); - --ifm-color-warning-contrast-background: #fff8e1 !important; - --ifm-color-warning-dark: rgba(255, 152, 0, 1); - - // Reset table styles (we use the radix-ui table component) - table { - display: table; - border: none; - margin-bottom: 0; - - thead { - background-color: unset; - border: none; - - tr { - border-bottom: none; - } - } - - tr { - background-color: unset; - border-top: none; - } - - th { - color: unset; - border: unset; - } - - td { - border: none; - color: unset; - } - } -} - -// Dark mode colors -[data-theme="dark"] { - --ifm-background-color: #0a0a0a; - --ifm-font-color-base: #fff; - --ifm-heading-color: #ddd; - --ifm-toc-border-color: #ffffff1a; - --ifm-navbar-background-color: #0a0a0a; - --ifm-toc-border-color: #484848; - --ifm-menu-color-active: #5f616b; - --ifm-menu-color-background-active: #202123; - --ifm-menu-color-background-hover: #202123; - --ifm-menu-color: #a5a5a5; - - // Dark mode admonitions - --ifm-color-success-contrast-background: #1c3225 !important; - --ifm-color-success-dark: rgba(38, 147, 71, 1); - --ifm-color-info-contrast-background: #142843 !important; - --ifm-color-info-dark: rgba(0, 98, 225, 1); - --ifm-color-not-contrast-background: #373739 !important; - --ifm-color-note-dark: rgba(173, 173, 173, 1); - --ifm-color-warning-contrast-background: #483e15 !important; - --ifm-color-warning-dark: rgba(255, 204, 0, 1); - - // * { - // border-color: var(--border); - // } - - // body { - // font-family: Inter, sans-serif; - // -webkit-font-smoothing: antialiased; - // -moz-osx-font-smoothing: grayscale; - // background-color: hsl(var(--background)); - // color: hsl(var(--foreground)); - // } - - // Reset table styles (we use the radix-ui table component) - table { - display: table; - border: none; - margin-bottom: 0; - - thead { - background-color: unset; - border: none; - - tr { - border-bottom: none; - } - } - - tr { - background-color: unset; - border-top: none; - } - - th { - color: unset; - border: unset; - } - - td { - border: none; - color: unset; - } - } -} - -// The description that renders after the page title -.page-subtitle { - margin-top: -15px; -} - -.reset-link { - color: inherit; - text-decoration: none; - &:hover { - text-decoration: none; - color: inherit; - } -} diff --git a/src/css/fonts.css b/src/css/fonts.css deleted file mode 100644 index c5dd0948e8..0000000000 --- a/src/css/fonts.css +++ /dev/null @@ -1,17 +0,0 @@ -@font-face { - font-family: "IBM Plex Mono"; - src: url("/static/fonts/IBMPlexMono-Regular.ttf") format("truetype"); - font-weight: 400; - font-style: normal; -} - -@font-face { - font-family: "IBM Plex Mono"; - src: url("/static/fonts/IBMPlexMono-Thin.ttf") format("truetype"); - font-weight: 100; - font-style: normal; -} - -:root { - --code-font-family: "IBM Plex Mono", monospace; -} diff --git a/src/css/radix.css b/src/css/radix.css deleted file mode 100644 index 6a1f684a2e..0000000000 --- a/src/css/radix.css +++ /dev/null @@ -1,777 +0,0 @@ -@import "@radix-ui/themes/tokens/base.css"; - -:root { - --color-background: #ffffff; - --code-font-family: "IBM Plex Mono", monospace; - - --orange-1: #fefcfb; - --orange-2: #fff7ee; - --orange-3: #ffedd5; - --orange-4: #ffdeb5; - --orange-5: #ffd19d; - --orange-6: #ffc58f; - --orange-7: #f1b47d; - --orange-8: #e39d5a; - --orange-9: #f79934; - --orange-10: #ea8e28; - --orange-11: #b66300; - --orange-12: #4e341c; - --orange-a1: #c0400004; - --orange-a2: #ff870011; - --orange-a3: #ff92002a; - --orange-a4: #ff8e014a; - --orange-a5: #ff880062; - --orange-a6: #ff7b0070; - --orange-a7: #e46c0082; - --orange-a8: #d46800a5; - --orange-a9: #f57f00cb; - --orange-a10: #e67900d7; - --orange-a11: #b66300; - --orange-a12: #381b00e3; - --orange-contrast: #fff; - --orange-surface: #fff5eacc; - --orange-indicator: #f79934; - --orange-track: #f79934; - - --gray-1: #fcfcfd; - --gray-2: #f9f9fb; - --gray-3: #eff0f3; - --gray-4: #e7e8ec; - --gray-5: #e0e1e6; - --gray-6: #d8d9e0; - --gray-7: #cdced7; - --gray-8: #b9bbc6; - --gray-9: #8b8d98; - --gray-10: #80828d; - --gray-11: #62636c; - --gray-12: #1e1f24; - - --gray-a1: #00005503; - --gray-a2: #00005506; - --gray-a3: #00104010; - --gray-a4: #000b3618; - --gray-a5: #0009321f; - --gray-a6: #00073527; - --gray-a7: #00063332; - --gray-a8: #00083046; - --gray-a9: #00051d74; - --gray-a10: #00051b7f; - --gray-a11: #0002119d; - --gray-a12: #000107e1; - - --gray-contrast: #ffffff; - --gray-surface: #ffffffcc; - --gray-indicator: #8b8d98; - --gray-track: #8b8d98; - - --green-1: #fbfefb; - --green-2: #f5fbf6; - --green-3: #e7f7e9; - --green-4: #d8f1db; - --green-5: #c6e9cb; - --green-6: #afdfb6; - --green-7: #8fcf9a; - --green-8: #5fbb73; - --green-9: #269347; - --green-10: #22843f; - --green-11: #1c803b; - --green-12: #1e3c24; - - --green-a1: #00c00004; - --green-a2: #00991a0a; - --green-a3: #00aa1618; - --green-a4: #00a41427; - --green-a5: #009d1739; - --green-a6: #00991750; - --green-a7: #00921a70; - --green-a8: #009320a0; - --green-a9: #008027d9; - --green-a10: #007122dd; - --green-a11: #007023e3; - --green-a12: #002207e1; - - --green-contrast: #fff; - --green-surface: #f3faf4cc; - --green-indicator: #269347; - --green-track: #269347; - - --blue-1: #fcfdff; - --blue-2: #f5faff; - --blue-3: #eaf3ff; - --blue-4: #daebff; - --blue-5: #c8e1ff; - --blue-6: #b3d4ff; - --blue-7: #9ac2ff; - --blue-8: #75a9fb; - --blue-9: #0062e1; - --blue-10: #0052d1; - --blue-11: #0062e1; - --blue-12: #0b2f66; - - --blue-a1: #0055ff03; - --blue-a2: #0080ff0a; - --blue-a3: #006eff15; - --blue-a4: #0076ff25; - --blue-a5: #0074ff37; - --blue-a6: #006fff4c; - --blue-a7: #0065ff65; - --blue-a8: #0061f88a; - --blue-a9: #0062e1; - --blue-a10: #0052d1; - --blue-a11: #0062e1; - --blue-a12: #00265ff4; - - --blue-contrast: #fff; - --blue-surface: #f3f9ffcc; - --blue-indicator: #0062e1; - --blue-track: #0062e1; - - --yellow-1: #fefdfa; - --yellow-2: #fffbe8; - --yellow-3: #fff4bb; - --yellow-4: #ffeb94; - --yellow-5: #ffe16e; - --yellow-6: #f9d46b; - --yellow-7: #e6c461; - --yellow-8: #d4ad2f; - --yellow-9: #ffd000; - --yellow-10: #fac700; - --yellow-11: #967200; - --yellow-12: #453b1d; - - --yellow-a1: #cc990005; - --yellow-a2: #ffd30017; - --yellow-a3: #ffd60044; - --yellow-a4: #ffd0016b; - --yellow-a5: #ffcb0091; - --yellow-a6: #f5b50094; - --yellow-a7: #d7a0009e; - --yellow-a8: #ca9b00d0; - --yellow-a9: #ffd000; - --yellow-a10: #fac700; - --yellow-a11: #967200; - --yellow-a12: #2d2200e2; - - --yellow-contrast: #292109; - --yellow-surface: #fffae2cc; - --yellow-indicator: #ffd000; - --yellow-track: #ffd000; - - --red-1: #fffcfc; - --red-2: #fff7f7; - --red-3: #feebea; - --red-4: #ffdcd9; - --red-5: #ffceca; - --red-6: #fdbeba; - --red-7: #f4aaa5; - --red-8: #eb8f8b; - --red-9: #d63941; - --red-10: #c72533; - --red-11: #cc2e39; - --red-12: #64181b; - - --red-a1: #ff000003; - --red-a2: #ff000008; - --red-a3: #f30d0015; - --red-a4: #ff150026; - --red-a5: #ff140035; - --red-a6: #f80f0045; - --red-a7: #e00f015a; - --red-a8: #d4090074; - --red-a9: #ca000ac6; - --red-a10: #be0010da; - --red-a11: #c1000ed1; - --red-a12: #540003e7; - - --red-contrast: #fff; - --red-surface: #fff5f5cc; - --red-indicator: #d63941; - --red-track: #d63941; -} - -[data-theme="dark"] { - --color-background: #0a0a0a; - - --orange-1: #0e0906; - --orange-2: #1d150e; - --orange-3: #311e0b; - --orange-4: #452100; - --orange-5: #532a00; - --orange-6: #633808; - --orange-7: #794917; - --orange-8: #9c5e1c; - --orange-9: #f79934; - --orange-10: #eb8e24; - --orange-11: #ffa442; - --orange-12: #ffe0c5; - - --orange-a1: #d7000005; - --orange-a2: #fd973d14; - --orange-a3: #fd871129; - --orange-a4: #fc68003e; - --orange-a5: #ff76004c; - --orange-a6: #ff89055d; - --orange-a7: #ff952774; - --orange-a8: #ff972998; - --orange-a9: #ff9e36f7; - --orange-a10: #fe9926eb; - --orange-a11: #ffa442; - --orange-a12: #ffe0c5; - - --orange-contrast: #fff; - --orange-surface: #30201280; - --orange-indicator: #f79934; - --orange-track: #f79934; - - --gray-1: #0a0a0a; - --gray-2: #171717; - --gray-3: #212121; - --gray-4: #292929; - --gray-5: #303030; - --gray-6: #3a3a3a; - --gray-7: #474747; - --gray-8: #606060; - --gray-9: #6c6c6c; - --gray-10: #7a7a7a; - --gray-11: #b3b3b3; - --gray-12: #ededed; - - --gray-a1: #00000000; - --gray-a2: #ffffff0e; - --gray-a3: #ffffff18; - --gray-a4: #ffffff20; - --gray-a5: #ffffff28; - --gray-a6: #ffffff32; - --gray-a7: #ffffff3f; - --gray-a8: #ffffff5a; - --gray-a9: #ffffff66; - --gray-a10: #ffffff75; - --gray-a11: #ffffffb0; - --gray-a12: #ffffffec; - - --gray-contrast: #ffffff; - --gray-surface: rgba(0, 0, 0, 0.05); - --gray-indicator: #6c6c6c; - --gray-track: #6c6c6c; - - --green-1: #060c07; - --green-2: #121a13; - --green-3: #162c1a; - --green-4: #183b1f; - --green-5: #1f4928; - --green-6: #275732; - --green-7: #30683d; - --green-8: #387c47; - --green-9: #269347; - --green-10: #3d804c; - --green-11: #6bd181; - --green-12: #b6f1bf; - - --green-a1: #00b40003; - --green-a2: #82fa9111; - --green-a3: #5ffb7b24; - --green-a4: #50ff7333; - --green-a5: #5cfe7e42; - --green-a6: #66fd8851; - --green-a7: #6dff8f62; - --green-a8: #6dff8d77; - --green-a9: #3cff778f; - --green-a10: #74ff937b; - --green-a11: #81fe9cd0; - --green-a12: #c0fec9f1; - - --green-contrast: #fff; - --green-surface: #1a2a1c80; - --green-indicator: #269347; - --green-track: #269347; - - --blue-1: #040a15; - --blue-2: #0d1625; - --blue-3: #0d254a; - --blue-4: #0d2f65; - --blue-5: #133a78; - --blue-6: #1c4688; - --blue-7: #24539d; - --blue-8: #2961b8; - --blue-9: #0062e1; - --blue-10: #235bb1; - --blue-11: #82b7ff; - --blue-12: #d0e3ff; - - --blue-a1: #000af40c; - --blue-a2: #2574f81d; - --blue-a3: #1671fe43; - --blue-a4: #136eff5f; - --blue-a5: #1e75fe73; - --blue-a6: #2d7efe84; - --blue-a7: #3684ff99; - --blue-a8: #3584feb6; - --blue-a9: #006effe0; - --blue-a10: #2f81ffae; - --blue-a11: #82b7ff; - --blue-a12: #d0e3ff; - - --blue-contrast: #fff; - --blue-surface: #10224080; - --blue-indicator: #0062e1; - --blue-track: #0062e1; - - --yellow-1: #0c0a05; - --yellow-2: #1a170e; - --yellow-3: #2b2206; - --yellow-4: #3a2a00; - --yellow-5: #473400; - --yellow-6: #544200; - --yellow-7: #685415; - --yellow-8: #836a1d; - --yellow-9: #fc0; - --yellow-10: #f5c200; - --yellow-11: #ffcf0f; - --yellow-12: #fce9b2; - - --yellow-a1: #b40a0003; - --yellow-a2: #facd4611; - --yellow-a3: #fbb90023; - --yellow-a4: #ffae0032; - --yellow-a5: #feb20040; - --yellow-a6: #fcc2004e; - --yellow-a7: #ffcb2762; - --yellow-a8: #ffcd317e; - --yellow-a9: #ffcc00; - --yellow-a10: #ffca00f5; - --yellow-a11: #ffcf0f; - --yellow-a12: #ffecb4fc; - - --yellow-contrast: #292109; - --yellow-surface: #2a241280; - --yellow-indicator: #fc0; - --yellow-track: #fc0; - - --red-1: #0f0808; - --red-2: #1e1211; - --red-3: #3a1212; - --red-4: #500f12; - --red-5: #61171a; - --red-6: #732425; - --red-7: #8c3434; - --red-8: #b54546; - --red-9: #d63941; - --red-10: #b44445; - --red-11: #ff8f8b; - --red-12: #ffd2ce; - - --red-a1: #df000006; - --red-a2: #fd6c6015; - --red-a3: #ff333332; - --red-a4: #ff1c2649; - --red-a5: #fe2f375b; - --red-a6: #fd46496e; - --red-a7: #fe595988; - --red-a8: #ff5f60b2; - --red-a9: #fe424cd5; - --red-a10: #ff5e5fb1; - --red-a11: #ff8f8b; - --red-a12: #ffd2ce; - - --red-contrast: #fff; - --red-surface: #321a1880; - --red-indicator: #d63941; - --red-track: #d63941; -} - -@supports (color: color(display-p3 1 1 1)) { - --orange-1: oklch(99.3% 0.0022 62.61); - --orange-2: oklch(98.2% 0.0162 62.61); - --orange-3: oklch(96.2% 0.0434 62.61); - --orange-4: oklch(93% 0.0785 62.61); - --orange-5: oklch(90.2% 0.1012 62.61); - --orange-6: oklch(86.7% 0.0992 62.61); - --orange-7: oklch(81.4% 0.1005 62.61); - --orange-8: oklch(75.1% 0.1181 62.61); - --orange-9: oklch(76.4% 0.1562 62.61); - --orange-10: oklch(72.9% 0.1543 62.61); - --orange-11: oklch(58.3% 0.1473 62.61); - --orange-12: oklch(35.1% 0.0532 62.61); - - --orange-a1: color(display-p3 0.7569 0.2667 0.0235 / 0.016); - --orange-a2: color(display-p3 0.9412 0.5059 0.0078 / 0.063); - --orange-a3: color(display-p3 0.9255 0.5647 0.0039 / 0.153); - --orange-a4: color(display-p3 0.9294 0.5373 0.0039 / 0.271); - --orange-a5: color(display-p3 0.9255 0.5176 0.0039 / 0.357); - --orange-a6: color(display-p3 0.9137 0.4627 0.0039 / 0.408); - --orange-a7: color(display-p3 0.8118 0.4039 0.0039 / 0.479); - --orange-a8: color(display-p3 0.7529 0.3843 0 / 0.604); - --orange-a9: color(display-p3 0.8824 0.4549 0 / 0.706); - --orange-a10: color(display-p3 0.8196 0.4275 0 / 0.746); - --orange-a11: color(display-p3 0.6196 0.3098 0 / 0.863); - --orange-a12: color(display-p3 0.1882 0.0941 0 / 0.875); - - --orange-contrast: #fff; - --orange-surface: color(display-p3 1 0.9608 0.9216 / 0.8); - --orange-indicator: oklch(76.4% 0.1562 62.61); - --orange-track: oklch(76.4% 0.1562 62.61); - - --gray-1: oklch(99.1% 0.0015 277.7); - --gray-2: oklch(98.2% 0.003 277.7); - --gray-3: oklch(95.6% 0.0045 277.7); - --gray-4: oklch(93.1% 0.0061 277.7); - --gray-5: oklch(91% 0.0077 277.7); - --gray-6: oklch(88.8% 0.0093 277.7); - --gray-7: oklch(85.3% 0.0117 277.7); - --gray-8: oklch(79.4% 0.016 277.7); - --gray-9: oklch(64.6% 0.0165 277.7); - --gray-10: oklch(61% 0.0161 277.7); - --gray-11: oklch(50.3% 0.0139 277.7); - --gray-12: oklch(24.1% 0.0099 277.7); - - --gray-a1: color(display-p3 0.0235 0.0235 0.349 / 0.012); - --gray-a2: color(display-p3 0.0235 0.0235 0.349 / 0.024); - --gray-a3: color(display-p3 0.0078 0.0667 0.2549 / 0.063); - --gray-a4: color(display-p3 0.0118 0.051 0.2157 / 0.095); - --gray-a5: color(display-p3 0.0039 0.0392 0.2 / 0.122); - --gray-a6: color(display-p3 0.0039 0.0275 0.1804 / 0.153); - --gray-a7: color(display-p3 0.0078 0.0275 0.1843 / 0.197); - --gray-a8: color(display-p3 0.0039 0.0314 0.1765 / 0.275); - --gray-a9: color(display-p3 0.0039 0.0196 0.1059 / 0.455); - --gray-a10: color(display-p3 0.0039 0.0196 0.098 / 0.499); - --gray-a11: color(display-p3 0 0.0078 0.0588 / 0.616); - --gray-a12: color(display-p3 0 0.0039 0.0275 / 0.883); - - --gray-contrast: #ffffff; - --gray-surface: color(display-p3 1 1 1 / 80%); - --gray-indicator: oklch(64.6% 0.0165 277.7); - --gray-track: oklch(64.6% 0.0165 277.7); - - --green-1: oklch(99.4% 0.0056 149); - --green-2: oklch(98.2% 0.0097 149); - --green-3: oklch(96.1% 0.0243 149); - --green-4: oklch(93.4% 0.0388 149); - --green-5: oklch(90.1% 0.0555 149); - --green-6: oklch(85.8% 0.0748 149); - --green-7: oklch(79.8% 0.0994 149); - --green-8: oklch(71.6% 0.136 149); - --green-9: oklch(58.5% 0.1482 149); - --green-10: oklch(54.2% 0.1364 149); - --green-11: oklch(52.7% 0.1364 149); - --green-12: oklch(32.7% 0.0559 149); - - --green-a1: color(display-p3 0.2667 0.7569 0.0235 / 0.016); - --green-a2: color(display-p3 0.0235 0.5647 0.0235 / 0.036); - --green-a3: color(display-p3 0.0078 0.5765 0.0078 / 0.083); - --green-a4: color(display-p3 0.0078 0.5647 0.0078 / 0.134); - --green-a5: color(display-p3 0.0078 0.5451 0.0078 / 0.197); - --green-a6: color(display-p3 0.0039 0.5294 0.0039 / 0.275); - --green-a7: color(display-p3 0.0039 0.4902 0.0118 / 0.385); - --green-a8: color(display-p3 0 0.4902 0.0314 / 0.538); - --green-a9: color(display-p3 0 0.3922 0.0275 / 0.71); - --green-a10: color(display-p3 0 0.3373 0.0275 / 0.742); - --green-a11: color(display-p3 0 0.3333 0.0275 / 0.757); - --green-a12: color(display-p3 0 0.102 0.0039 / 0.855); - - --green-contrast: #fff; - --green-surface: color(display-p3 0.9569 0.9804 0.9569 / 0.8); - --green-indicator: oklch(58.5% 0.1482 149); - --green-track: oklch(58.5% 0.1482 149); - - --blue-1: oklch(99.4% 0.0025 259.3); - --blue-2: oklch(98.2% 0.0098 259.3); - --blue-3: oklch(96% 0.0206 259.3); - --blue-4: oklch(93.6% 0.0398 259.3); - --blue-5: oklch(90.4% 0.0593 259.3); - --blue-6: oklch(86.3% 0.0799 259.3); - --blue-7: oklch(80.8% 0.0995 259.3); - --blue-8: oklch(73.2% 0.1326 259.3); - --blue-9: oklch(53% 0.2085 259.3); - --blue-10: oklch(48.3% 0.2085 259.3); - --blue-11: oklch(52.9% 0.2085 259.3); - --blue-12: oklch(31.7% 0.1051 259.3); - - --blue-a1: color(display-p3 0.0235 0.349 1 / 0.012); - --blue-a2: color(display-p3 0.0235 0.4588 0.8941 / 0.036); - --blue-a3: color(display-p3 0.0078 0.3725 0.949 / 0.075); - --blue-a4: color(display-p3 0.0078 0.3882 0.9451 / 0.134); - --blue-a5: color(display-p3 0.0078 0.3843 0.9412 / 0.197); - --blue-a6: color(display-p3 0.0039 0.3725 0.9451 / 0.275); - --blue-a7: color(display-p3 0.0039 0.3373 0.949 / 0.365); - --blue-a8: color(display-p3 0.0039 0.3176 0.9216 / 0.499); - --blue-a9: color(display-p3 0 0.2588 0.8235 / 0.844); - --blue-a10: color(display-p3 0 0.2157 0.7569 / 0.871); - --blue-a11: color(display-p3 0 0.2588 0.8235 / 0.844); - --blue-a12: color(display-p3 0 0.102 0.3255 / 0.914); - - --blue-contrast: #fff; - --blue-surface: color(display-p3 0.9569 0.9725 1 / 0.8); - --blue-indicator: oklch(53% 0.2085 259.3); - --blue-track: oklch(53% 0.2085 259.3); - - --yellow-1: oklch(99.4% 0.0037 90.38); - --yellow-2: oklch(98.7% 0.025 90.38); - --yellow-3: oklch(97.1% 0.0762 90.38); - --yellow-4: oklch(94.8% 0.1115 90.38); - --yellow-5: oklch(92.1% 0.1396 90.38); - --yellow-6: oklch(88.1% 0.1307 90.38); - --yellow-7: oklch(83% 0.1244 90.38); - --yellow-8: oklch(76.1% 0.142 90.38); - --yellow-9: oklch(88.1% 0.1909 90.38); - --yellow-10: oklch(85.1% 0.1768 90.38); - --yellow-11: oklch(57.1% 0.1438 90.38); - --yellow-12: oklch(35.4% 0.047 90.38); - - --yellow-a1: color(display-p3 0.8039 0.6078 0.0196 / 0.02); - --yellow-a2: color(display-p3 0.9529 0.8118 0.0078 / 0.083); - --yellow-a3: color(display-p3 0.9686 0.8235 0.0039 / 0.244); - --yellow-a4: color(display-p3 0.9725 0.8039 0.0039 / 0.377); - --yellow-a5: color(display-p3 0.9647 0.7765 0 / 0.502); - --yellow-a6: color(display-p3 0.9098 0.6824 0 / 0.518); - --yellow-a7: color(display-p3 0.7843 0.5961 0 / 0.561); - --yellow-a8: color(display-p3 0.7294 0.5569 0 / 0.714); - --yellow-a9: color(display-p3 0.9608 0.7569 0 / 0.722); - --yellow-a10: color(display-p3 0.9294 0.7098 0 / 0.734); - --yellow-a11: color(display-p3 0.4941 0.3608 0 / 0.859); - --yellow-a12: color(display-p3 0.1529 0.1176 0 / 0.871); - - --yellow-contrast: #292109; - --yellow-surface: color(display-p3 1 0.9804 0.898 / 0.8); - --yellow-indicator: oklch(88.1% 0.1909 90.38); - --yellow-track: oklch(88.1% 0.1909 90.38); - - --red-1: oklch(99.4% 0.0031 23.01); - --red-2: oklch(98.3% 0.0082 23.01); - --red-3: oklch(95.6% 0.0208 23.01); - --red-4: oklch(92.8% 0.0466 23.01); - --red-5: oklch(89.6% 0.0611 23.01); - --red-6: oklch(85.7% 0.0735 23.01); - --red-7: oklch(80.7% 0.0881 23.01); - --red-8: oklch(74.5% 0.1116 23.01); - --red-9: oklch(58.4% 0.1932 23.01); - --red-10: oklch(54% 0.1957 23.01); - --red-11: oklch(55.7% 0.1932 23.01); - --red-12: oklch(33.9% 0.1079 23.01); - - --red-a1: color(display-p3 0.6745 0.0235 0.0235 / 0.012); - --red-a2: color(display-p3 0.8784 0.0196 0.0196 / 0.032); - --red-a3: color(display-p3 0.8118 0.1059 0.0078 / 0.083); - --red-a4: color(display-p3 0.8392 0.0902 0.0078 / 0.146); - --red-a5: color(display-p3 0.8471 0.098 0.0039 / 0.204); - --red-a6: color(display-p3 0.8235 0.0784 0.0039 / 0.263); - --red-a7: color(display-p3 0.7529 0.0706 0.0039 / 0.346); - --red-a8: color(display-p3 0.7098 0.0471 0.0039 / 0.444); - --red-a9: color(display-p3 0.6863 0 0.0078 / 0.726); - --red-a10: color(display-p3 0.6431 0 0.0157 / 0.789); - --red-a11: color(display-p3 0.6549 0 0.0118 / 0.761); - --red-a12: color(display-p3 0.2745 0 0 / 0.883); - - --red-contrast: #fff; - --red-surface: color(display-p3 0.9961 0.9647 0.9608 / 0.8); - --red-indicator: oklch(58.4% 0.1932 23.01); - --red-track: oklch(58.4% 0.1932 23.01); - - @media (color-gamut: p3) { - [data-theme="dark"] { - --orange-1: oklch(14.5% 0.0114 62.61); - --orange-2: oklch(20.2% 0.0184 62.61); - --orange-3: oklch(25.4% 0.0433 62.61); - --orange-4: oklch(29.1% 0.0762 62.61); - --orange-5: oklch(33.4% 0.0831 62.61); - --orange-6: oklch(38.6% 0.0832 62.61); - --orange-7: oklch(45.3% 0.0907 62.61); - --orange-8: oklch(54% 0.1112 62.61); - --orange-9: oklch(76.4% 0.1562 62.61); - --orange-10: oklch(72.9% 0.1562 62.61); - --orange-11: oklch(79.9% 0.1562 62.61); - --orange-12: oklch(92.5% 0.0502 62.61); - - --orange-a1: color(display-p3 0.9451 0 0 / 0.013); - --orange-a2: color(display-p3 0.9961 0.6235 0.3059 / 0.074); - --orange-a3: color(display-p3 1 0.6 0.1451 / 0.147); - --orange-a4: color(display-p3 1 0.4863 0 / 0.221); - --orange-a5: color(display-p3 1 0.5216 0.0392 / 0.278); - --orange-a6: color(display-p3 1 0.5922 0.1529 / 0.339); - --orange-a7: color(display-p3 1 0.6392 0.2627 / 0.425); - --orange-a8: color(display-p3 1 0.651 0.2706 / 0.56); - --orange-a9: color(display-p3 1 0.6706 0.3176 / 0.915); - --orange-a10: color(display-p3 1 0.6588 0.2824 / 0.866); - --orange-a11: color(display-p3 1 0.6902 0.3529 / 0.947); - --orange-a12: color(display-p3 1 0.902 0.8 / 0.98); - - --orange-contrast: #fff; - --orange-surface: color(display-p3 0.1725 0.1255 0.0784 / 0.5); - --orange-indicator: oklch(76.4% 0.1562 62.61); - --orange-track: oklch(76.4% 0.1562 62.61); - --gray-1: oklch(14.5% 0 none); - --gray-2: oklch(20.5% 0 none); - --gray-3: oklch(24.8% 0 none); - --gray-4: oklch(28% 0 none); - --gray-5: oklch(31% 0 none); - --gray-6: oklch(34.7% 0 none); - --gray-7: oklch(39.9% 0 none); - --gray-8: oklch(48.8% 0 none); - --gray-9: oklch(53.3% 0 none); - --gray-10: oklch(57.9% 0 none); - --gray-11: oklch(76.6% 0 none); - --gray-12: oklch(94.7% 0 none); - - --gray-a1: color(display-p3 0 0 0 / 0); - --gray-a2: color(display-p3 1 1 1 / 0.0531); - --gray-a3: color(display-p3 1 1 1 / 0.0939); - --gray-a4: color(display-p3 1 1 1 / 0.1265); - --gray-a5: color(display-p3 1 1 1 / 0.1551); - --gray-a6: color(display-p3 1 1 1 / 0.1959); - --gray-a7: color(display-p3 1 1 1 / 0.249); - --gray-a8: color(display-p3 1 1 1 / 0.351); - --gray-a9: color(display-p3 1 1 1 / 0.4); - --gray-a10: color(display-p3 1 1 1 / 0.4571); - --gray-a11: color(display-p3 1 1 1 / 0.6898); - --gray-a12: color(display-p3 1 1 1 / 0.9265); - - --gray-contrast: #ffffff; - --gray-surface: color(display-p3 0 0 0 / 5%); - --gray-indicator: oklch(53.3% 0 none); - --gray-track: oklch(53.3% 0 none); - - --green-1: oklch(14.5% 0.0142 149); - --green-2: oklch(20.5% 0.0175 149); - --green-3: oklch(26.7% 0.0421 149); - --green-4: oklch(31.6% 0.0629 149); - --green-5: oklch(36.4% 0.0726 149); - --green-6: oklch(41.3% 0.0809 149); - --green-7: oklch(46.7% 0.0917 149); - --green-8: oklch(52.7% 0.1065 149); - --green-9: oklch(58.5% 0.1482 149); - --green-10: oklch(54.2% 0.1065 149); - --green-11: oklch(78% 0.1482 149); - --green-12: oklch(90.5% 0.091 149); - - --green-a1: color(display-p3 0 0.9137 0 / 0.009); - --green-a2: color(display-p3 0.6353 0.9922 0.6353 / 0.066); - --green-a3: color(display-p3 0.5333 1 0.5647 / 0.135); - --green-a4: color(display-p3 0.502 1 0.5216 / 0.196); - --green-a5: color(display-p3 0.5333 1 0.549 / 0.254); - --green-a6: color(display-p3 0.5569 1 0.5961 / 0.311); - --green-a7: color(display-p3 0.5765 1 0.6078 / 0.38); - --green-a8: color(display-p3 0.5882 1 0.6078 / 0.458); - --green-a9: color(display-p3 0.4941 1 0.5294 / 0.552); - --green-a10: color(display-p3 0.6039 1 0.6275 / 0.474); - --green-a11: color(display-p3 0.6392 1 0.6588 / 0.805); - --green-a12: color(display-p3 0.8078 1 0.8157 / 0.935); - - --green-contrast: #fff; - --green-surface: color(display-p3 0.1098 0.1569 0.1098 / 0.5); - --green-indicator: oklch(58.5% 0.1482 149); - --green-track: oklch(58.5% 0.1482 149); - - --blue-1: oklch(14.5% 0.027 259.3); - --blue-2: oklch(20.1% 0.0329 259.3); - --blue-3: oklch(26.8% 0.0756 259.3); - --blue-4: oklch(31.7% 0.1017 259.3); - --blue-5: oklch(36.1% 0.114 259.3); - --blue-6: oklch(40.3% 0.1206 259.3); - --blue-7: oklch(45% 0.1312 259.3); - --blue-8: oklch(50.3% 0.1497 259.3); - --blue-9: oklch(53% 0.2085 259.3); - --blue-10: oklch(48.3% 0.1497 259.3); - --blue-11: oklch(77.7% 0.1345 259.3); - --blue-12: oklch(91.1% 0.0467 259.3); - - --blue-a1: color(display-p3 0 0.0431 0.9961 / 0.041); - --blue-a2: color(display-p3 0.2235 0.4824 0.9922 / 0.107); - --blue-a3: color(display-p3 0.1804 0.4471 1 / 0.249); - --blue-a4: color(display-p3 0.1843 0.4392 1 / 0.356); - --blue-a5: color(display-p3 0.2196 0.4627 1 / 0.433); - --blue-a6: color(display-p3 0.2706 0.5098 1 / 0.494); - --blue-a7: color(display-p3 0.298 0.5294 1 / 0.58); - --blue-a8: color(display-p3 0.302 0.5333 1 / 0.686); - --blue-a9: color(display-p3 0.1765 0.4353 1 / 0.845); - --blue-a10: color(display-p3 0.2784 0.5176 1 / 0.658); - --blue-a11: color(display-p3 0.5647 0.7294 1 / 0.976); - --blue-a12: color(display-p3 0.8431 0.898 1 / 0.988); - - --blue-contrast: #fff; - --blue-surface: color(display-p3 0.0784 0.1333 0.2431 / 0.5); - --blue-indicator: oklch(53% 0.2085 259.3); - --blue-track: oklch(53% 0.2085 259.3); - - --yellow-1: oklch(14.5% 0.0129 90.38); - --yellow-2: oklch(20.5% 0.0181 90.38); - --yellow-3: oklch(25.5% 0.0446 90.38); - --yellow-4: oklch(29.4% 0.0721 90.38); - --yellow-5: oklch(33.6% 0.082 90.38); - --yellow-6: oklch(38.6% 0.0793 90.38); - --yellow-7: oklch(45.3% 0.0827 90.38); - --yellow-8: oklch(53.6% 0.0975 90.38); - --yellow-9: oklch(86.5% 0.1768 90.38); - --yellow-10: oklch(83.4% 0.1768 90.38); - --yellow-11: oklch(87.4% 0.1768 90.38); - --yellow-12: oklch(93.6% 0.0728 90.38); - - --yellow-a1: color(display-p3 0.9137 0.0392 0 / 0.009); - --yellow-a2: color(display-p3 0.9882 0.8627 0.3569 / 0.062); - --yellow-a3: color(display-p3 1 0.7608 0.0706 / 0.131); - --yellow-a4: color(display-p3 1 0.7294 0 / 0.188); - --yellow-a5: color(display-p3 1 0.749 0.0706 / 0.237); - --yellow-a6: color(display-p3 1 0.8118 0.1373 / 0.29); - --yellow-a7: color(display-p3 1 0.8314 0.2941 / 0.372); - --yellow-a8: color(display-p3 1 0.8353 0.3216 / 0.478); - --yellow-a9: color(display-p3 1 0.8353 0.2824 / 0.968); - --yellow-a10: color(display-p3 1 0.8235 0.2745 / 0.927); - --yellow-a11: color(display-p3 1 0.8471 0.2941 / 0.968); - --yellow-a12: color(display-p3 1 0.9412 0.7412 / 0.976); - - --yellow-contrast: #292109; - --yellow-surface: color(display-p3 0.1647 0.1412 0.0784 / 0.5); - --yellow-indicator: oklch(86.5% 0.1768 90.38); - --yellow-track: oklch(86.5% 0.1768 90.38); - - --red-1: oklch(14.5% 0.0133 23.01); - --red-2: oklch(19.8% 0.0215 23.01); - --red-3: oklch(24.7% 0.0642 23.01); - --red-4: oklch(28.7% 0.0957 23.01); - --red-5: oklch(33.1% 0.1064 23.01); - --red-6: oklch(38.2% 0.1112 23.01); - --red-7: oklch(45% 0.1205 23.01); - --red-8: oklch(54.3% 0.1463 23.01); - --red-9: oklch(58.4% 0.1932 23.01); - --red-10: oklch(54% 0.1463 23.01); - --red-11: oklch(78.4% 0.1616 23.01); - --red-12: oklch(90.2% 0.0528 23.01); - - --red-a1: color(display-p3 0.9647 0 0 / 0.017); - --red-a2: color(display-p3 0.9961 0.5176 0.4118 / 0.074); - --red-a3: color(display-p3 1 0.2863 0.2431 / 0.176); - --red-a4: color(display-p3 1 0.2078 0.1922 / 0.258); - --red-a5: color(display-p3 1 0.2706 0.2706 / 0.323); - --red-a6: color(display-p3 1 0.3608 0.3412 / 0.392); - --red-a7: color(display-p3 1 0.4235 0.4 / 0.49); - --red-a8: color(display-p3 1 0.4392 0.4275 / 0.645); - --red-a9: color(display-p3 1 0.349 0.3529 / 0.764); - --red-a10: color(display-p3 1 0.4353 0.4235 / 0.641); - --red-a11: color(display-p3 1 0.6196 0.5882 / 0.939); - --red-a12: color(display-p3 1 0.8549 0.8353 / 0.972); - - --red-contrast: #fff; - --red-surface: color(display-p3 0.1882 0.102 0.0941 / 0.5); - --red-indicator: oklch(58.4% 0.1932 23.01); - --red-track: oklch(58.4% 0.1932 23.01); - } - } -} - -@import "@radix-ui/themes/components.css"; -@import "@radix-ui/themes/utilities.css"; - -.theme-root { - min-height: 100%; - display: flex; - flex: 1; - flex-direction: column; -} - -:root { - --color-background: #ffffff; - --code-font-family: "IBM Plex Mono", monospace; -} - -[data-theme="dark"] { - --color-background: #0a0a0a; - --code-font-family: "IBM Plex Mono", monospace; -} diff --git a/src/hooks/index.ts b/src/hooks/index.ts deleted file mode 100644 index 174e9f089c..0000000000 --- a/src/hooks/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from "./useFilteredTocItems"; -export * from "./useIsVisible"; -export * from "./useSelectionStore"; -export * from "./useDocItemStore"; -export * from "./useDocPageData"; -export * from "./useLoadOpenApiSchema"; -export * from "./useUIType"; diff --git a/src/hooks/useDocItemStore.ts b/src/hooks/useDocItemStore.ts deleted file mode 100644 index 3b4dc21bec..0000000000 --- a/src/hooks/useDocItemStore.ts +++ /dev/null @@ -1,102 +0,0 @@ -import React, { useSyncExternalStore } from "react"; - -export type DocsItemStateType = { - recipes: { - emailpassword: {}; - passwordless: { - contactMethod: "EMAIL" | "PHONE" | "EMAIL_OR_PHONE"; - flowType: "USER_INPUT_CODE_AND_MAGIC_LINK" | "USER_INPUT_CODE" | "MAGIC_LINK"; - }; - thirdparty: {}; - }; - appInfo: { - appName: string; - apiDomain: string; - apiBasePath: string; - websiteDomain: string; - websiteBasePath: string; - }; - appType: "single" | "multi"; - tenantType: "single" | "multi"; - coreInfo: { - hasSupertokensSession: boolean; - uri: string | null; - key: string | null; - }; -}; - -const DefaultState: DocsItemStateType = { - recipes: { - emailpassword: {}, - passwordless: { - contactMethod: "PHONE", - flowType: "MAGIC_LINK", - }, - thirdparty: {}, - }, - tenantType: "single", - appType: "single", - appInfo: { - appName: "", - apiDomain: "", - apiBasePath: "/auth", - websiteDomain: "", - websiteBasePath: "/auth", - }, - coreInfo: { - hasSupertokensSession: false, - uri: "", - key: "", - }, -}; - -let isInitialized = false; -let DocsItemState = DefaultState; - -const LOCAL_STORAGE_KEY = "page-dynamic-values"; - -const subscribers = new Set<() => void>(); - -const subscribe = (callback: () => void) => { - subscribers.add(callback); - return () => subscribers.delete(callback); -}; - -const getSnapshot = () => { - if (isInitialized) return DocsItemState; - const localStorageState = localStorage.getItem(LOCAL_STORAGE_KEY); - if (!localStorageState) { - isInitialized = true; - DocsItemState = DefaultState; - return DocsItemState; - } - try { - const initialState = JSON.parse(localStorageState); - if (!!initialState) { - DocsItemState = initialState; - return DocsItemState; - } - } catch (e) { - console.error(e); - DocsItemState = DefaultState; - return DocsItemState; - } finally { - isInitialized = true; - } -}; - -const notifySubscribers = () => { - subscribers.forEach((callback) => callback()); -}; - -export function useDocsItemStore(): [DocsItemStateType, (state: DocsItemStateType) => void] { - const set = (value: DocsItemStateType) => { - DocsItemState = value; - localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(value)); - notifySubscribers(); - }; - - const store = useSyncExternalStore(subscribe, getSnapshot, () => DefaultState); - - return [store as DocsItemStateType, set]; -} diff --git a/src/hooks/useDocPageData.ts b/src/hooks/useDocPageData.ts deleted file mode 100644 index fee7c52b41..0000000000 --- a/src/hooks/useDocPageData.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { useSyncExternalStore } from "react"; -import { DocPageState, docPageStore, InferDotNotationKeys, InferDotNotationValue } from "../lib"; - -export function useDocPageData>(path: T) { - const selector = () => { - return getObjectPropertyValue(docPageStore.getSnapshot(), path); - }; - const value = useSyncExternalStore(docPageStore.subscribe.bind(docPageStore), selector, selector); - return value as InferDotNotationValue; -} - -function getObjectPropertyValue(obj: object, key: string): unknown { - const keys = key.split("."); - let current = obj; - - if (keys.length === 1) return obj[keys[0]]; - - current = current[keys[0]]; - return getObjectPropertyValue(current, keys.slice(1).join(".")); -} diff --git a/src/hooks/useFilteredTocItems.ts b/src/hooks/useFilteredTocItems.ts deleted file mode 100644 index bae2ff8bc4..0000000000 --- a/src/hooks/useFilteredTocItems.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { useContext, useState, useLayoutEffect } from "react"; -import { DocItemContext } from "@site/src/context"; -import type { Props } from "@theme/TOC"; -import { useUIType } from "./useUIType"; - -/** - * The TOC component does not support dynamic headings. - * We use this abstraction, parsedTocItems, to show only the items that - * are currently visible in the page. - * - * ATM this only covers the uiType switcher but we should also extend it - * to allow dynamic headings based on tab selection. - */ -export default function useFilteredTocItems(toc: Props["toc"]) { - const { tenantType } = useContext(DocItemContext); - const { uiType } = useUIType(); - - const [filteredTocItems, setFilteredTocItems] = useState([]); - - useLayoutEffect(() => { - const mainContentElement = document.querySelector(`main`); - const hiddenElements: Element[] = []; - const hiddenUiType = uiType === "custom" ? "prebuilt" : "custom"; - const hiddenUiTypeContainer = document.querySelector(`[data-heading-filter="${hiddenUiType}"]`); - if (hiddenUiTypeContainer) hiddenElements.push(hiddenUiTypeContainer); - const hiddenTenantType = tenantType === "single" ? "multi" : "single"; - const hiddenTenantTypeContainer = document.querySelector(`[data-heading-filter="${hiddenTenantType}"]`); - if (hiddenTenantTypeContainer) hiddenElements.push(hiddenTenantTypeContainer); - const hiddenContainers = document.querySelectorAll(`[data-exclude-headings-from-toc="true"]`); - - hiddenContainers.forEach((container) => hiddenElements.push(container)); - - if (!mainContentElement || !hiddenElements.length) { - setFilteredTocItems(toc); - return; - } - - const allPageHeadings = document.querySelectorAll(`h2, h3, h4`); - const visibleHeadingsIds = Array.from(allPageHeadings) - .filter((heading) => { - return hiddenElements.every((hiddenElement) => { - return !hiddenElement.contains(heading); - }); - }) - .map((heading) => { - return heading.id; - }); - - const visibleHeadings: Record = {}; - setFilteredTocItems( - toc.filter((tocItem) => { - // Already marked as visible - if (visibleHeadings[tocItem.id]) return false; - if (visibleHeadingsIds.find((headingId) => headingId === tocItem.id)) { - visibleHeadings[tocItem.id] = true; - return true; - } - return false; - }), - ); - }, [toc, uiType, tenantType]); - - return filteredTocItems; -} diff --git a/src/hooks/useIsVisible.ts b/src/hooks/useIsVisible.ts deleted file mode 100644 index 9d0fad2777..0000000000 --- a/src/hooks/useIsVisible.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { useState, useRef, useEffect } from "react"; - -export function useIsVisible() { - const [isVisible, setIsVisible] = useState(false); - const elementRef = useRef(null); - useEffect(() => { - const observer = new IntersectionObserver( - ([entry]) => { - const visible = entry.isIntersecting; - setIsVisible(visible); - }, - { - threshold: 0.3, - }, - ); - - if (elementRef.current) { - observer.observe(elementRef.current); - } - return () => { - if (elementRef.current) { - observer.unobserve(elementRef.current); - } - }; - }, [elementRef]); - return { visibilityRef: elementRef, isVisible }; -} diff --git a/src/hooks/useLoadOpenApiSchema.ts b/src/hooks/useLoadOpenApiSchema.ts deleted file mode 100644 index 7d9b8f1780..0000000000 --- a/src/hooks/useLoadOpenApiSchema.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { useEffect, useState, lazy } from "react"; - -import type { OpenAPIV3 } from "@scalar/openapi-types"; - -// TODO: Cache the schema -export function useLoadOpenApiDocument(apiName: "cdi" | "fdi"): OpenAPIV3.PathItemObject | null { - const [document, setDocument] = useState(null); - - useEffect(() => { - async function loadDocument() { - try { - const response = await import(`@site/static/${apiName}.json`); - const document = response.default as OpenAPIV3.Document; - if (!document.paths) { - throw new Error(`Document paths not set`); - } - setDocument(document); - } catch (err) { - console.error("Error loading markdown file:", err); - } - } - loadDocument(); - }, []); - - return document; -} diff --git a/src/hooks/useSelection.ts b/src/hooks/useSelection.ts deleted file mode 100644 index 468a6c9c60..0000000000 --- a/src/hooks/useSelection.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { useSelectionStore } from "./useSelectionStore"; - -export function useGoFrameworksSelection() { - return useSelectionStore(GoFrameworksSelectionName, GoFrameworksDefaultValue); -} diff --git a/src/hooks/useSelectionStore.ts b/src/hooks/useSelectionStore.ts deleted file mode 100644 index dd3df4dc92..0000000000 --- a/src/hooks/useSelectionStore.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { useSyncExternalStore } from "react"; - -/** - * Data store that is used to syncronize - * the state of different selection components across the app. - * Example: - * - * If you want to also syncronize the state to local storage - * keep in mind that you will have to use string values. - */ -type SelectionStoreValue = { - subscribers: Set<() => void>; - value: unknown; -}; - -const LocalStorageKeyPrefix = "selection-store"; -const SelectionStore: Map = new Map(); - -const getLocalStorageKey = (selectionName: string) => `${LocalStorageKeyPrefix}-${selectionName}`; -const subscribe = - (selectionName: string, initialValue: unknown, useLocalStorage: boolean) => (callback: () => void) => { - if (!SelectionStore.has(selectionName)) { - let value = initialValue; - if (useLocalStorage) { - const localStorageValue = localStorage.getItem(getLocalStorageKey(selectionName)); - if (localStorageValue !== undefined) value = localStorageValue; - } - SelectionStore.set(selectionName, { - subscribers: new Set(), - value: value, - }); - } else { - SelectionStore.get(selectionName).subscribers.add(callback); - } - return () => { - SelectionStore.get(selectionName).subscribers.delete(callback); - }; - }; - -const getSnapshot = (selectionName: string) => () => { - if (!SelectionStore.has(selectionName)) { - return undefined; - } - return SelectionStore.get(selectionName).value; -}; - -export function useSelectionStore(selectionName: string, initialValue: T, useLocalStorage = false) { - const store = useSyncExternalStore( - subscribe(selectionName, initialValue, useLocalStorage), - getSnapshot(selectionName), - () => initialValue, - ); - - const set = (value: T) => { - if (!SelectionStore.has(selectionName)) { - throw new Error("Selection does not exist"); - } - SelectionStore.get(selectionName).value = value; - localStorage.setItem(getLocalStorageKey(selectionName), JSON.stringify(value)); - SelectionStore.get(selectionName).subscribers.forEach((callback) => callback()); - }; - - return [store, set] as [T, (value: T) => void]; -} diff --git a/src/hooks/useUIType.ts b/src/hooks/useUIType.ts deleted file mode 100644 index f433eb805f..0000000000 --- a/src/hooks/useUIType.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { useCallback, useMemo } from "react"; -import { useDocPageData } from "./useDocPageData"; -import { useLocation, useHistory } from "@docusaurus/router"; -import { docPageStore } from "../lib"; - -export function useUIType() { - const { search } = useLocation(); - const history = useHistory(); - const storeUIType = useDocPageData("uiType"); - const urlUIType = useMemo(() => { - const searchParams = new URLSearchParams(search); - return searchParams.get("uiType") as "prebuilt" | "custom" | null; - }, [search]); - - const uiType: "prebuilt" | "custom" = urlUIType || storeUIType || "prebuilt"; - - const onChangeUIType = useCallback( - (type: "prebuilt" | "custom") => { - const searchParams = new URLSearchParams(search); - searchParams.set("uiType", type); - history.push({ - pathname: history.location.pathname, - search: searchParams.toString(), - hash: history.location.hash, - }); - docPageStore.updateValue("uiType", type); - }, - [urlUIType, history], - ); - - return { uiType, onChangeUIType }; -} diff --git a/src/lib/amplitude.ts b/src/lib/amplitude.ts deleted file mode 100644 index 129fbdf072..0000000000 --- a/src/lib/amplitude.ts +++ /dev/null @@ -1,75 +0,0 @@ -import * as amplitude from "@amplitude/analytics-browser"; -import { sessionReplayPlugin } from "@amplitude/plugin-session-replay-browser"; - -let amplitudeInitialized = false; -let amplitudeUserIdentified = false; - -export const initAmplitude = () => { - if (amplitudeInitialized) { - return; - } - const sessionReplayTracking = sessionReplayPlugin({ - sampleRate: 0.3, - }); - amplitude.add(sessionReplayTracking); - amplitude.init("b61f581fe0775f56038a6264af879aa9", { - logLevel: isTestEnv() || isDev() ? amplitude.Types.LogLevel.Debug : amplitude.Types.LogLevel.None, - autocapture: { - attribution: true, - pageViews: true, - sessions: true, - formInteractions: true, - fileDownloads: true, - elementInteractions: true, - }, - }); - amplitudeInitialized = true; -}; - -export const trackEvent = (event: string, properties: Record, useBeacon = false) => { - if (!amplitudeInitialized) { - initAmplitude(); - } - if (useBeacon) { - amplitude.setTransport("beacon"); - amplitude.track(event, properties); - amplitude.flush(); - amplitude.setTransport("xhr"); - } else { - amplitude.track(event, properties); - } -}; - -export const trackBeaconEvent = (event: string, properties: Record) => { - if (!amplitudeInitialized) { - initAmplitude(); - } - amplitude.setTransport("beacon"); - amplitude.track(event, properties); - amplitude.flush(); - amplitude.setTransport("xhr"); -}; - -const identifyEvent = new amplitude.Identify(); - -export const identifyUser = (properties: Record) => { - if (!amplitudeInitialized) { - initAmplitude(); - } - if (amplitudeUserIdentified) { - return; - } - for (const [key, value] of Object.entries(properties)) { - identifyEvent.set(key, value); - } - - amplitude.identify(identifyEvent); - amplitudeUserIdentified = true; -}; - -function isDev() { - return window.location.host.startsWith("localhost"); -} -function isTestEnv() { - return window.location.host === "test.supertokens.com"; -} diff --git a/src/lib/analytics.ts b/src/lib/analytics.ts deleted file mode 100644 index 370f17dd3f..0000000000 --- a/src/lib/analytics.ts +++ /dev/null @@ -1,311 +0,0 @@ -import axios from "axios"; -import supertokens from "supertokens-website"; -import { v1 as uuidv1 } from "uuid"; -import Cookies from "js-cookie"; - -import { initAmplitude, trackEvent } from "./amplitude"; - -const COOKIE_CONSENT = "cookieconsent_status"; -const ANTCS_ENDPOINT_URL = "https://api.supertokens.com/0/antcs/ents"; -const baseAnalyticsStorageKey = "st_antcs"; -const antcsCookieName = "st_antcs"; // analytics cookie name - -function getAnalyticsCookieOptions() { - let domain = window.location.hostname; - if (window.location.hostname.endsWith("supertokens.com")) { - // This is done to make sure that the same cookie is shared across the - // multiple subdomain of supertokens.com - domain = ".supertokens.com"; - } - - return { - domain, - sameSite: "Lax", - expires: 10000, - }; -} - -const hostnameWhitelisting = { - "supertokens.com": true, - "www.supertokens.com": true, -}; - -const udidBlacklised = { - "st-team-udid1234": true, -}; - -const userConfig = { - timeout: 20000, - maxRedirects: 20, - withCredentials: true, - headers: { - "Content-Type": "application/json", - "api-version": 0, - }, -}; - -class Analytics { - private userId: string | null = null; - static instance: Analytics | null = null; - public currentPage: { - pathname: string; - hostname: string; - pageViewIntervals: Array<{ start: number; end?: number }>; - } | null = null; - - saveCurrentPage() { - this.currentPage = { - pathname: window.location.pathname, - hostname: window.location.hostname, - pageViewIntervals: [{ start: Date.now() }], - }; - } - - getUserId() { - let userIdInLocalStorage = localStorage === null ? null : localStorage.getItem(baseAnalyticsStorageKey); - - if (userIdInLocalStorage === "st-team-udid1234") { - return userIdInLocalStorage; - } - - if (this.hasCookieConsent !== false) { - const valueInCookie = Cookies.get(antcsCookieName); - if (valueInCookie !== undefined) { - return valueInCookie; - } - if (userIdInLocalStorage !== null) { - Cookies.set(antcsCookieName, userIdInLocalStorage, getAnalyticsCookieOptions()); - localStorage.removeItem(baseAnalyticsStorageKey); - return userIdInLocalStorage; - } - - const newUserId = uuidv1(); - Cookies.set(antcsCookieName, newUserId, getAnalyticsCookieOptions()); - return newUserId; - } - return "untracked_user"; - } - - getCommonData() { - if (this.userId === null) { - this.userId = this.getUserId(); - } - const userId = this.userId; - return { - page: window.location.href, - userId: userId, - }; - } - - get hasCookieConsent() { - if (window.location.hostname === "localhost") return true; - return getCookieConsent() === "allow"; - } - - get canSendEvents() { - const hostname = window.location.hostname; - const userId = this.getCommonData().userId; - if ( - (hostnameWhitelisting[hostname] === true || hostname.endsWith(".demo.supertokens.com")) && - udidBlacklised.hasOwnProperty(userId) === false && - this.hasCookieConsent - ) { - return true; - } - return false; - } - - init() { - if (!this.canSendEvents) return; - initAmplitude(); - } - - async sendEvent( - eventName: string, - payload: { data: Record; version?: string; useBeacon?: boolean }, - ) { - if (!this.hasCookieConsent) return; - const { data, version = "v1", useBeacon = false } = payload; - const commonData = this.getCommonData(); - const sessionUserId = await getSessionUserId(); - const timestamp = Date.now(); - const eventData = { - timestamp, - version, - sessionUserId, - ...commonData, - ...data, - }; - - if (!this.canSendEvents) { - // console.log(eventName, eventData); - return; - } - - const eventPayload = { - eventName: eventName, - data: eventData, - }; - axios.post(ANTCS_ENDPOINT_URL, eventPayload, userConfig).catch(console.error); - if (eventName !== "page_view") { - trackEvent(eventName, eventData, useBeacon); - } - return; - } - - async sendPageViewEvent() { - if (!this.currentPage) { - this.saveCurrentPage(); - } else { - this.sendPageExitEvent("page-change"); - } - await this.sendEvent("page_view", { - data: { - type: "page_view", - referrer: document.referrer, - }, - version: "v1", - }); - } - - isNewPage() { - if (this.currentPage.hostname !== window.location.hostname) { - return true; - } - if (this.currentPage.pathname !== window.location.pathname) { - return true; - } - return false; - } - - // page-change: user navigates from one page to another inside the docs app - // app-close: user closes the tab, user navigates to another website from the same tab - async sendPageExitEvent(transitionType: "page-change" | "app-close") { - if (transitionType === "page-change" && !this.isNewPage()) return; - if (!this.currentPage) return; - const currentTime = Date.now(); - this.currentPage.pageViewIntervals[this.currentPage.pageViewIntervals.length - 1].end = currentTime; - const totalTime = currentTime - this.currentPage.pageViewIntervals[0].start; - const activeTime = this.currentPage.pageViewIntervals.reduce((acc, interval) => { - if (interval.end === undefined) return acc; - return acc + interval.end - interval.start; - }, 0); - await this.sendEvent("page_exit", { - data: { - hostname: this.currentPage.hostname, - pathname: this.currentPage.pathname, - totalTime, - activeTime, - }, - version: "v1", - useBeacon: transitionType === "app-close", - }); - this.saveCurrentPage(); - } -} - -function getAnalyticsInstance() { - if (Analytics.instance === null) { - Analytics.instance = new Analytics(); - } - return Analytics.instance; -} - -export function trackPageView() { - getAnalyticsInstance().sendPageViewEvent(); -} - -export function trackPageExit(transitionType: "page-change" | "app-close"): void; -export function trackPageExit(transitionType: "visibility-change", visibilityState: "hidden" | "visible"): void; -export function trackPageExit( - transitionType: "page-change" | "app-close" | "visibility-change", - visibilityState?: "hidden" | "visible", -) { - const analyticsInstance = getAnalyticsInstance(); - if (transitionType === "page-change" || transitionType === "app-close") { - analyticsInstance.sendPageExitEvent(transitionType); - return; - } - if (visibilityState === "hidden") { - analyticsInstance.currentPage.pageViewIntervals[analyticsInstance.currentPage.pageViewIntervals.length - 1].end = - Date.now(); - } else if (visibilityState === "visible") { - analyticsInstance.currentPage.pageViewIntervals.push({ start: Date.now() }); - } -} - -export function init() { - const analyticsInstance = getAnalyticsInstance(); - - return analyticsInstance.init(); -} - -export function trackButtonClick(eventName: string, version = "v1", options?: Object) { - getAnalyticsInstance().sendEvent(eventName, { - data: { - type: "button_click", - ...options, - }, - version, - }); -} - -export function trackFormSubmit(eventName: string, version = "v1", options?: Object) { - getAnalyticsInstance().sendEvent(eventName, { - data: { - type: "button_click", - ...options, - }, - version, - }); -} - -export function trackLinkClick(eventName: string, version = "v5", options?: Object) { - getAnalyticsInstance().sendEvent(eventName, { - data: { - type: "link_click", - ...options, - }, - version, - }); -} - -export function getCookieConsent(): "allow" | "deny" | "unset" { - const consentCookie = Cookies.get(COOKIE_CONSENT); - if (consentCookie && consentCookie === "deny") { - return "deny"; - } - if (consentCookie && consentCookie === "allow") { - return "allow"; - } - return "unset"; -} - -export function setCookieConsent(consent: "allow" | "deny") { - Cookies.set(COOKIE_CONSENT, consent); -} - -async function getSessionUserId() { - let userId = ""; - try { - userId = await supertokens.getUserId(); - } catch (e) {} - return userId; -} - -export const AnalyticsEventNames = { - buttonTocItem: "button_toc_item", - buttonHeaderBlog: "button_header_blog", - buttonHeaderDiscord: "button_header_discord", - buttonHeaderGithub: "button_header_github", - buttonSidebarLink: "button_sidebar_link", - buttonSidebarCategory: "button_sidebar_category", - buttonHeaderWebsite: "button_header_website", - buttonHeaderViewDashboard: "button_header_view_dashboard", - buttonHeaderSignup: "button_header_signup", - buttonSearchResult: "button_search_result", - buttonSearchViewAllResults: "button_search_view_all_results", - buttonSearchTrigger: "button_search_trigger", - buttonReferenceCard: "button_reference_card", - buttonFeedbackForm: "button_documentation_submit_feedback", -}; diff --git a/src/lib/api.ts b/src/lib/api.ts deleted file mode 100644 index c2dea54140..0000000000 --- a/src/lib/api.ts +++ /dev/null @@ -1,324 +0,0 @@ -import { API_URL, MOCK_ENABLED } from "./constants"; -import axios from "axios"; -import { SaasAppListItem, SaasConnectionUrlDomain } from "./types"; - -const AxiosInstance = axios.create({ - baseURL: API_URL, - timeout: 50000, - maxRedirects: 20, - withCredentials: true, - xsrfCookieName: "", - xsrfHeaderName: "", -}); - -export async function getWebJsURI() { - const endpoint = "/frontend/web-js"; - const apiVersion = "0"; - - try { - const response = await AxiosInstance.get(endpoint, { - headers: { - "api-version": apiVersion, - }, - }); - - return response.data as { uri: Record }; - } catch (err) { - return { - uri: { - dateprovider: "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/dateprovider.test.js", - emailpassword: "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/emailpassword.test.js", - emailverification: - "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/emailverification.test.js", - multifactorauth: - "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/multifactorauth.test.js", - multitenancy: "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/multitenancy.test.js", - oauth2provider: - "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/oauth2provider.test.js", - passwordless: "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/passwordless.test.js", - session: "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/session.test.js", - supertokens: "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/supertokens.test.js", - thirdparty: "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/thirdparty.test.js", - totp: "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/totp.test.js", - website: "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/website.test.js", - userroles: "https://cdn.jsdelivr.net/gh/supertokens/supertokens-web-js@vX.Y.Z/bundle/userroles.test.js", - }, - }; - } -} - -export async function getSupportedPlugins(planType: string) { - const endpoint = "/plugins"; - const apiVersion = "0"; - const response = await AxiosInstance.get(endpoint, { - params: { - planType: planType === "COMMERCIAL_TRIAL" ? "COMMERCIAL" : planType, - mode: "PRODUCTION", - }, - headers: { - "api-version": apiVersion, - }, - }); - - return response.data as { plugins: { id: string; displayName: string }[] }; -} - -export async function getSupportedFrontends() { - const endpoint = "/frontends"; - const apiVersion = "0"; - const response = await AxiosInstance.get(endpoint, { - params: { - mode: "PRODUCTION", - }, - headers: { - "api-version": apiVersion, - }, - }); - - return response.data as { frontends: { id: string; displayName: string }[] }; -} - -export async function getSupportedDrivers() { - const endpoint = "/drivers"; - const apiVersion = "0"; - const response = await AxiosInstance.get(endpoint, { - params: { - planType: "FREE", - mode: "PRODUCTION", - }, - headers: { - "api-version": apiVersion, - }, - }); - - return response.data as { drivers: { id: string; displayName: string }[] }; -} - -export async function getCompatibility(driver: string, frontend: string) { - const endpoint = "/compatibility"; - const apiVersion = "0"; - const response = await AxiosInstance.get(endpoint, { - params: { - planType: "FREE", - plugin: "postgresql", - driver, - frontend, - }, - headers: { - "api-version": apiVersion, - }, - }); - - return response.data as { - cores: string[]; - coreToDriver: { [key: string]: string[] }; - coreToPlugin: { [key: string]: string[] }; - driverToFrontend: { [key: string]: string[] }; - }; -} - -export async function getAuthReactURI() { - const endpoint = "/frontend/auth-react"; - const apiVersion = "0"; - - try { - const response = await AxiosInstance.get(endpoint, { - headers: { - "api-version": apiVersion, - }, - }); - - return response.data as { uri: string }; - } catch (err) { - console.error(err); - return { - uri: "https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@vX.Y.Z/build/static/js/main.test.js", - }; - } -} - -export async function getUserInformation() { - const endpoint = "/user/info"; - const apiVersion = "0"; - const response = await AxiosInstance.get(endpoint, { - headers: { - "api-version": apiVersion, - }, - }); - - return response.data as { - email: string; - name: string; - country: string; - company: string; - }; -} - -export async function getCoreVersionForPlugin(plugin: string) { - const endpoint = "/plugin/dependency/cores"; - const apiVersion = "0"; - const response = await AxiosInstance.get(endpoint, { - params: { - planType: "FREE", - mode: "PRODUCTION", - name: plugin, - }, - headers: { - "api-version": apiVersion, - }, - }); - - return response.data as { cores: string[] }; -} - -export async function getSaasApp() { - let apiResponse: SaasConnectionUrlDomain[] = []; - if (MOCK_ENABLED) { - apiResponse = MockAPIResponse; - } else { - const oldApp = await getOldSaasApps(); - if (oldApp) return oldApp; - } - - apiResponse = await getNewSaasApps(); - - for (let i = 0; i < apiResponse.length; i++) { - let curr = apiResponse[i]; - if ("apps" in curr && !curr.isTemporarilyRemoved) { - for (let y = 0; y < curr.apps.length; y++) { - let currApp = curr.apps[y]; - if (currApp.appId === "public") { - let devDeployment = currApp.deployments[0]; - if (currApp.deployments.length > 1 && currApp.deployments[1].deploymentType === "development") { - devDeployment = currApp.deployments[1]; - } - return devDeployment.connectionInfo!; - } - } - } - } -} - -async function getOldSaasApps() { - const endpoint = "/saas/apps"; - const apiVersion = "1"; - - const response = await AxiosInstance.get(endpoint, { - headers: { - "api-version": apiVersion, - }, - }); - const olderResult = response.data as SaasAppListItem[]; - if (olderResult.length > 0) { - return olderResult[0].devDeployment.connectionInfo!; - } - return undefined; -} - -async function getNewSaasApps() { - const endpoint = "/saas/multi-tenancy/connection-uri-domain/list"; - const apiVersion = "1"; - - const response = await AxiosInstance.get(endpoint, { - headers: { - "api-version": apiVersion, - }, - }); - - return response.data as SaasConnectionUrlDomain[] | undefined; -} - -const MockAPIResponse: SaasConnectionUrlDomain[] = [ - { - deploymentId: "56a112ceb9e659c2fa0d19b63d76ead284bac7523f3b705bee90a38bd68ed424", - region: "us-east-1", - deploymentName: "My App 1", - isTemporarilyRemoved: false, - apps: [ - { - appId: "public", - deployments: [ - { - deploymentType: "development", - coreVersion: "6.0", - connectionInfo: { - host: "https://st-dev-47fa5b70-1bbe-11ee-8d64-91038b6bd2c7.aws.supertokens.io", - apiKeys: ["7b9N8m8U3jgtx=ZeNWn21fBsvg"], - }, - config: [ - { - keyName: "access_token_validity", - value: "3600", - description: "Type: integer\nTime in seconds for how long an access token is valid for.", - }, - { - keyName: "access_token_blacklisting", - value: "false", - description: - "Type: boolean\nDeprecated, please see changelog. Only used in CDI<=2.18\nIf true, allows for immediate revocation of any access token. Keep in mind that setting this to true will resultin a db query for each API call that requires authentication.", - }, - { - keyName: "access_token_signing_key_dynamic", - value: "true", - description: - "Type: boolean\nDeprecated, please see changelog.\nIf this is set to true, the access tokens created using CDI<=2.18 will be signed using a static signing key.", - }, - { - keyName: "access_token_dynamic_signing_key_update_interval", - value: "168", - description: "Type: integer\nTime in hours for how frequently the dynamic signing key will change.", - }, - { - keyName: "refresh_token_validity", - value: "144000", - description: "Type: double\nTime in mins for how long a refresh token is valid for.", - }, - { - keyName: "password_reset_token_lifetime", - value: "3600000", - description: - "Type: long\nTime in milliseconds for how long a password reset token / link is valid for.", - }, - { - keyName: "email_verification_token_lifetime", - value: "86400000", - description: - "Type: long\nTime in milliseconds for how long an email verification token / link is valid for.", - }, - { - keyName: "passwordless_max_code_input_attempts", - value: "5", - description: - "Type: integer\nThe maximum number of code input attempts per login before the user needs to restart.", - }, - { - keyName: "passwordless_code_lifetime", - value: "900000", - description: "Type: long\nTime in milliseconds for how long a passwordless code is valid for.", - }, - { - keyName: "totp_max_attempts", - value: "5", - description: - "Type: integer\nThe maximum number of invalid TOTP attempts that will trigger rate limiting.", - }, - { - keyName: "totp_rate_limit_cooldown_sec", - value: "900", - description: - "Type: integer\nThe time in seconds for which the user will be rate limited once totp_max_attempts is crossed.", - }, - { - keyName: "password_hashing_alg", - value: "BCRYPT", - description: - 'Type: "ARGON2" | "BCRYPT"\nThe password hashing algorithm to use. Values are "ARGON2" | "BCRYPT"', - }, - ], - status: "active", - }, - ], - }, - ], - }, -]; diff --git a/src/lib/categoryIcons.tsx b/src/lib/categoryIcons.tsx deleted file mode 100644 index d739a1dbc7..0000000000 --- a/src/lib/categoryIcons.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import React from "react"; -import { - Book, - Zap, - Key, - Shield, - Users, - ArrowRight, - Settings, - Server, - Mail, - Smartphone, - Share2, - Building, - Bot, - Layers, - Fingerprint, - MailCheck, - ShieldCheck, - Clock, - UserCheck, - ShieldAlert, - Timer, - UserCog, - Link, - BarChart3, - Puzzle, - Cloud, - Triangle, - Database, - Workflow, - Globe, - Folder, - FileText, - Monitor, - Code, - Bug, - Wrench, - Palette, - FlaskConical, - BookOpenCheck, - Cpu, - Hash, - History, - Construction, - Play, - ChevronRight, - Lightbulb, -} from "lucide-react"; -import type { LucideIcon } from "lucide-react"; - -interface CategoryIconMapping { - [key: string]: LucideIcon; -} - -const categoryIcons: CategoryIconMapping = { - // Main categories - References: Book, - Quickstart: Zap, - Authentication: Key, - "Additional Verification": Shield, - "Post Authentication": Users, - Migration: ArrowRight, - "Platform Configuration": Settings, - Deployment: Server, - - // Authentication methods - "Email Password": Mail, - Passwordless: Smartphone, - "Social Login": Share2, - "Enterprise Login": Building, - "Unified Login": Layers, - "Machine to Machine": Bot, - Passkeys: Fingerprint, - - // Quickstart integrations - Integrations: Puzzle, - "AWS Lambda": Cloud, - NextJS: Triangle, - "App Directory": Folder, - "Pages Directory": FileText, - GraphQL: Workflow, - Hasura: Database, - NestJS: Globe, - Netlify: Globe, - Supabase: Database, - Vercel: Triangle, - - // References and SDK sections - "Frontend SDKs": Monitor, - "Backend SDKs": Server, - "User Interface": Palette, - "CDI Reference": Code, - "FDI Reference": Code, - "Testing and Debugging": Bug, - "SuperTokens Core": Cpu, - - // Authentication reference subcategories - "Email/Password": Mail, - ThirdParty: Share2, - WebAuthn: Fingerprint, - OAuth: Key, - MFA: ShieldCheck, - Session: Clock, - TOTP: Hash, - OTP: Smartphone, - SAML: Building, - - // Quickstart guides and workflows - "Quickstart Guides": Zap, - "Advanced Workflows": Workflow, - "Legacy Method": History, - "Legacy method": History, - "Backend Setup": Server, - "Using prebuilt UI": Palette, - "Step 1: Account Creation": UserCheck, - "5. Checking Sessions in API Routes": Shield, - "Checking Sessions in API Routes": Shield, -}; - -interface CategoryIconProps { - categoryLabel: string; - className?: string; -} - -export function CategoryIcon({ categoryLabel, className }: CategoryIconProps) { - const IconComponent = categoryIcons[categoryLabel]; - - if (!IconComponent) { - return null; - } - - return ; -} - -export default CategoryIcon; diff --git a/src/lib/constants.ts b/src/lib/constants.ts deleted file mode 100644 index e14348b12a..0000000000 --- a/src/lib/constants.ts +++ /dev/null @@ -1,42 +0,0 @@ -export const DOCS_CONNTENT_DIV_ID = "docs-content"; -export const TOC_UI_TYPE_SWITCH_ID = "toc-ui-type-switch"; - -export const DOC_STORE_DEFAULT_VALUES = { - "appInfo.appName": "", - "appInfo.apiDomain": "", - "appInfo.websiteDomain": "", - "coreInfo.uri": "https://try.supertokens.com", - "coreInfo.key": "", -}; - -export const DOC_PAGE_STORE_DEFAULT_VALUES = { - apiDomain: "", - apiBasePath: "/auth", - coreDomain: "", - tenantId: "public", - appId: "public", -} as const; - -let API_URL = "https://dev.api.supertokens.com/0"; -let API_DOMAIN = "https://dev.api.supertokens.com"; -let API_BASE_PATH = "/0/auth"; -let WEBSITE_DOMAIN = "http://localhost:9001"; -let MOCK_ENABLED = false; - -try { - MOCK_ENABLED = window.location.hostname === "localhost"; - // we have try catch cause nexJS throws "window not defined" error.. - if (window.location.hostname === "supertokens.com" || window.location.hostname === "www.supertokens.com") { - API_URL = "https://api.supertokens.com/0"; - API_DOMAIN = "https://api.supertokens.com"; - API_BASE_PATH = "/0/auth"; - WEBSITE_DOMAIN = "https://supertokens.com"; - } else if (window.location.hostname === "test.supertokens.com") { - API_URL = "https://dev.api.supertokens.com/0"; - API_DOMAIN = "https://dev.api.supertokens.com"; - API_BASE_PATH = "/0/auth"; - WEBSITE_DOMAIN = "https://test.supertokens.com"; - } -} catch (ignored) {} - -export { API_URL, API_DOMAIN, API_BASE_PATH, WEBSITE_DOMAIN, MOCK_ENABLED }; diff --git a/src/lib/docPageStore.ts b/src/lib/docPageStore.ts deleted file mode 100644 index 5e5b3bcff8..0000000000 --- a/src/lib/docPageStore.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { DOC_PAGE_STORE_DEFAULT_VALUES } from "./constants"; -import { InferDotNotationKeys, InferDotNotationValue } from "./types"; - -export interface DocPageState { - nextjsRouterType: "app-router" | "pages-router"; - accountType: "managed" | "self-hosted"; - selfHostedDeploymentType: "with-docker" | "without-docker"; - tenantType: "single-tenant" | "multi-tenant"; - apiRequestExampleLanguage: "shell" | "nodejs" | "python" | "go"; - uiType: "prebuilt" | "custom"; - apiDomain: string; - apiBasePath: string; - websiteDomain: string; - websiteBasePath: string; - tenantId: string; - appId: string; - tokenTransferMethod: "cookie" | "header"; - coreDomain: string; -} - -class DocPageStore { - private state: DocPageState; - private listeners: Set<() => void>; - - constructor() { - this.state = this.initState(); - this.listeners = new Set(); - } - - private persistToLocalStorage() { - if (typeof window !== "undefined" && localStorage) { - localStorage.setItem("docPageState", JSON.stringify(this.state)); - } - } - - private initState(): DocPageState { - if (typeof window !== "undefined" && localStorage) { - try { - const state = JSON.parse(localStorage.getItem("docPageState")); - if (state) return state; - } catch (e) { - console.error(e); - } - } - return { - tenantType: "single-tenant", - nextjsRouterType: "app-router", - accountType: "managed", - uiType: "prebuilt", - selfHostedDeploymentType: "with-docker", - apiRequestExampleLanguage: "shell", - apiDomain: DOC_PAGE_STORE_DEFAULT_VALUES.apiDomain, - apiBasePath: DOC_PAGE_STORE_DEFAULT_VALUES.apiBasePath, - websiteDomain: "{websiteDomain}", - websiteBasePath: "/auth", - tenantId: DOC_PAGE_STORE_DEFAULT_VALUES.tenantId, - appId: DOC_PAGE_STORE_DEFAULT_VALUES.appId, - coreDomain: DOC_PAGE_STORE_DEFAULT_VALUES.coreDomain, - tokenTransferMethod: "cookie", - }; - } - - public getSnapshot() { - return this.state; - } - - subscribe(listener: () => void) { - this.listeners.add(listener); - return () => this.listeners.delete(listener); - } - - updateValue, K extends InferDotNotationValue>( - key: T, - value: K, - ) { - const newState = { ...this.state }; - setObjectProperty(newState, key, value); - this.state = newState; - this.persistToLocalStorage(); - this.notifyListeners(); - } - - private notifyListeners() { - this.listeners.forEach((listener) => listener()); - } -} - -export const docPageStore = new DocPageStore(); - -function setObjectProperty(obj: object, key: string, value: unknown) { - const keys = key.split("."); - if (typeof obj !== "object" || obj === null) { - throw new TypeError("First argument must be a non-null object"); - } - let current = obj; - - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - if (i === keys.length - 1) { - current[key] = value; - } else if (!(key in current)) { - current[key] = {}; - } - current = current[key]; - } -} diff --git a/src/lib/generateCodeSnippetFromAPIRequest.ts b/src/lib/generateCodeSnippetFromAPIRequest.ts deleted file mode 100644 index bd12276275..0000000000 --- a/src/lib/generateCodeSnippetFromAPIRequest.ts +++ /dev/null @@ -1,330 +0,0 @@ -import { getExampleFromSchema } from "./getExampleFromSchema"; -import type { OpenAPIV3 } from "@scalar/openapi-types"; - -type Environment = "shell" | "nodejs" | "go" | "python"; - -export enum AuthType { - None = "none", - Bearer = "bearer", - ApiKey = "apiKey", - Cookie = "cookie", -} - -export function generateCodeSnippetFromAPIRequest(params: { - host: string; - operation: OpenAPIV3.OperationObject; - security: OpenAPIV3.Document["components"]["securitySchemes"]; - environment: Environment; - method: string; - preferredAuthType?: AuthType; - path: string; -}): string { - const { environment } = params; - let apiCodeSnippet: APICodeSnippet; - - switch (environment) { - case "shell": - apiCodeSnippet = new ShellAPICodeSnippet(params); - break; - case "nodejs": - apiCodeSnippet = new NodeJSAPICodeSnippet(params); - break; - case "go": - apiCodeSnippet = new GoAPICodeSnippet(params); - break; - case "python": - apiCodeSnippet = new PythonAPICodeSnippet(params); - break; - default: - throw new Error(`Invalid environment ${environment}`); - } - - return apiCodeSnippet.render(); -} - -abstract class APICodeSnippet { - public apiDomain: string; - public request: OpenAPIV3.OperationObject; - public security: OpenAPIV3.Document["components"]["securitySchemes"]; - public method: string; - public path: string; - public preferredAuthType?: AuthType; - constructor(params: { - host: string; - operation: OpenAPIV3.OperationObject; - security: OpenAPIV3.Document["components"]["securitySchemes"]; - method: string; - path: string; - preferredAuthType?: AuthType; - }) { - this.apiDomain = params.host; - this.request = params.operation; - this.method = params.method; - this.path = params.path; - this.security = params.security; - this.preferredAuthType = params.preferredAuthType; - } - - get queryParams(): string { - if (!this.request.parameters) return ""; - - const queryParams = this.request.parameters.filter((param) => param.in === "query" && param.required); - if (!queryParams.length) return ""; - return queryParams - .map((parameter) => { - const example = getExampleFromSchema(parameter.schema); - return `${parameter.name}=${example}`; - }) - .join("&"); - } - - get pathWithQueryParams() { - const queryParams = this.queryParams; - return queryParams ? `${this.path}?${queryParams}` : this.path; - } - - get body(): Record | null { - const requestBody = this.request.requestBody as OpenAPIV3.RequestBodyObject; - if (!requestBody || !requestBody.content || !requestBody.content["application/json"]) { - return null; - } - const bodySchema = requestBody.content["application/json"]; - - const example: Record = {}; - - if (bodySchema.examples) { - return bodySchema.examples; - } - - if ("oneOf" in bodySchema.schema) { - const firstOption = bodySchema.schema.oneOf[0]; - - if (firstOption.example) return firstOption.example; - for (const [key, propSchema] of Object.entries(firstOption.properties)) { - example[key] = this.extractSchemaExample(propSchema); - } - return example; - } - - if (bodySchema.example) { - return bodySchema.example; - } - - return this.extractSchemaExample(bodySchema.schema) as Record; - } - - get securityRequirements() { - const operation = this.request; - const security = this.security; - - if (!operation) return []; - if (!operation.security) return []; - if (!security) return []; - - return operation.security - .map((securityRequirement) => { - const requirementName = Object.keys(securityRequirement)[0]; - const req = security[requirementName] as OpenAPIV3.SecuritySchemeObject | null; - return req as OpenAPIV3.SecuritySchemeObject; - }) - .filter((v) => v); - } - - get headers(): Record { - const headers: Record = { - "Content-Type": "application/json; charset=utf-8", - }; - - if (this.request.parameters) { - const headerParams = this.request.parameters.filter((param) => param.in === "header" && param.required); - headerParams.forEach((param) => { - headers[param.name] = getExampleFromSchema(param.schema) as string; - }); - } - - const securityRequirements = this.securityRequirements; - - if (securityRequirements.length > 0) { - for (const securityRequirement of securityRequirements) { - if (this.preferredAuthType && this.preferredAuthType !== securityRequirement.type) continue; - if (securityRequirement.type === "http") { - headers["Authorization"] = "Bearer {{token}}"; - } else if (securityRequirement.type === "apiKey" && securityRequirement.in === "cookie") { - headers["Cookie"] = `${securityRequirement.name}={{token}}`; - } else if (securityRequirement.type === "apiKey" && securityRequirement.in === "header") { - headers[securityRequirement.name] = "{{api_key}}"; - } - } - } - - return headers; - } - - private extractSchemaExample(schema: OpenAPIV3.SchemaObject): unknown { - if (schema.oneOf) { - return this.extractSchemaExample(schema.oneOf[0]); - } - - if (schema.example) { - return schema.example; - } - - if (schema.default) { - return schema.default; - } - - return getExampleFromSchema(schema); - } - - abstract render(): string; -} - -class ShellAPICodeSnippet extends APICodeSnippet { - private get formattedMethod() { - return this.method.toUpperCase(); - } - - render() { - let snippet = `curl -L \\ - --request ${this.formattedMethod} \\ - --url '${this.apiDomain}${this.pathWithQueryParams}'`; - - const headers = this.headers; - for (const [headerName, headerValue] of Object.entries(headers)) { - snippet += ` \\ - --header '${headerName}: ${headerValue}'`; - } - - const body = this.body; - if (body) { - snippet += ` \\ - --data '${JSON.stringify(body, null, 6)}' -`; - } else { - snippet += `\n`; - } - return snippet; - } -} - -class NodeJSAPICodeSnippet extends APICodeSnippet { - private get formattedMethod() { - return this.method.toUpperCase(); - } - - render() { - const body = this.body; - const bodyString = body ? `body: JSON.stringify(${JSON.stringify(body, null, 2)})` : ""; - - // Format headers for Node.js - const headers = this.headers; - const headersString = Object.entries(headers) - .map(([name, value]) => ` '${name}': '${value}'`) - .join(",\n"); - - return `const BASE_URL = "${this.apiDomain}" - -const url = \`\$\{BASE_URL\}${this.pathWithQueryParams}\`; -const options = { - method: '${this.formattedMethod}', - headers: { -${headersString} - },${bodyString ? "\n " + bodyString : ""} -} - -fetch(url, options) - .then(response => response.json()) - .then(json => console.log(json)) - .catch(err => console.error(err)); -`; - } -} - -class GoAPICodeSnippet extends APICodeSnippet { - private get formattedMethod() { - return this.method.toUpperCase(); - } - - render() { - const body = this.body; - const imports = ["fmt", "net/http", body ? "strings" : null, "io"].filter(Boolean).join("\n "); - const stringifiedBody = body ? JSON.stringify(body, null, 2) : ""; - - let bodyCode = ""; - if (body) { - bodyCode = `payload := \`${stringifiedBody}\` - req, _ := http.NewRequest("${this.formattedMethod}", url, payload); -`; - } else { - bodyCode = `req, _ := http.NewRequest("${this.formattedMethod}", url, nil)`; - } - - const headers = this.headers; - const headersCode = Object.entries(headers) - .map(([name, value]) => ` req.Header.Add("${name}", "${value}")`) - .join("\n"); - - return `import ( - ${imports} -) - -func main() { - baseUrl := "${this.apiDomain}" - url := fmt.Sprintf("%s${this.pathWithQueryParams}", baseUrl) - ${bodyCode} - -${headersCode} - - res, _ := http.DefaultClient.Do(req) - - defer res.Body.Close() - body, _ := io.ReadAll(res.Body) - - fmt.Println(string(body)) -}`; - } -} - -class PythonAPICodeSnippet extends APICodeSnippet { - private get formattedMethod() { - return this.method.toLowerCase(); - } - - render() { - const body = this.body; - let imports = `import requests -from typing import Dict, Any`; - - let bodyCode = ""; - if (body) { - const bodyExample = JSON.stringify(body, null, 2); - let pythonDict = bodyExample - .replace(/"([^"]+)":/g, "$1:") // Convert "key": to key: - .replace(/: "([^"]+)"/g, ': "$1"') // Keep string values - .replace(/true/g, "True") // Convert boolean - .replace(/false/g, "False") - .replace(/null/g, "None"); - - bodyCode = `payload: Dict[str, Any] = ${pythonDict}`; - } - - const headers = this.headers; - const headersDict = Object.entries(headers) - .map(([name, value]) => ` "${name}": "${value}"`) - .join(",\n"); - - return `${imports} - -BASE_URL = "${this.apiDomain}" - -url = f"{BASE_URL}${this.pathWithQueryParams}" - -${bodyCode ? bodyCode + "\n\n" : ""}headers = { -${headersDict} -} - -response = requests.${this.formattedMethod}(url${body ? ", json=payload" : ""}, headers=headers) - -print(response.json())`; - } -} diff --git a/src/lib/generateExampleFromAPIRequestSchema.ts b/src/lib/generateExampleFromAPIRequestSchema.ts deleted file mode 100644 index 61e6c4c883..0000000000 --- a/src/lib/generateExampleFromAPIRequestSchema.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { APIRequestSchema } from "../types"; - -export function generateExampleFromAPIRequestSchema(schema: APIRequestSchema) { - if (schema.example) return schema.example; - if (schema.enum) return schema.enum[0]; - if (schema.type === "array") { - const example = generateExampleFromAPIRequestSchema(schema.items); - return [example]; - } - - if (schema.type === "object" && schema.properties) { - const example: Record = {}; - for (const key in schema.properties) { - example[key] = generateExampleFromAPIRequestSchema(schema.properties[key]); - } - - return example; - } - - return {}; -} diff --git a/src/lib/getExampleFromSchema.ts b/src/lib/getExampleFromSchema.ts deleted file mode 100644 index fe126eaa34..0000000000 --- a/src/lib/getExampleFromSchema.ts +++ /dev/null @@ -1,368 +0,0 @@ -/** Hard limit for rendering circular references */ -const MAX_LEVELS_DEEP = 5; -/** Sets the max number of properties after the third level to prevent exponential horizontal growth */ -const MAX_PROPERTIES = 10; - -const genericExampleValues: Record = { - // 'date-time': '1970-01-01T00:00:00Z', - "date-time": new Date().toISOString(), - // 'date': '1970-01-01', - date: new Date().toISOString().split("T")[0]!, - email: "hello@example.com", - hostname: "example.com", - // https://tools.ietf.org/html/rfc6531#section-3.3 - "idn-email": "jane.doe@example.com", - // https://tools.ietf.org/html/rfc5890#section-2.3.2.3 - "idn-hostname": "example.com", - ipv4: "127.0.0.1", - ipv6: "51d4:7fab:bfbf:b7d7:b2cb:d4b4:3dad:d998", - "iri-reference": "/entitiy/1", - // https://tools.ietf.org/html/rfc3987 - iri: "https://example.com/entity/123", - "json-pointer": "/nested/objects", - password: "super-secret", - regex: "/[a-z]/", - // https://tools.ietf.org/html/draft-handrews-relative-json-pointer-01 - "relative-json-pointer": "1/nested/objects", - // full-time in https://tools.ietf.org/html/rfc3339#section-5.6 - // 'time': '00:00:00Z', - time: new Date().toISOString().split("T")[1]!.split(".")[0]!, - // either a URI or relative-reference https://tools.ietf.org/html/rfc3986#section-4.1 - "uri-reference": "../folder", - "uri-template": "https://example.com/{id}", - uri: "https://example.com", - uuid: "123e4567-e89b-12d3-a456-426614174000", - "object-id": "6592008029c8c3e4dc76256c", -}; - -/** - * We can use the `format` to generate some random values. - */ -function guessFromFormat(schema: Record, fallback: string = "") { - return genericExampleValues[schema.format] ?? fallback; -} - -/** Map of all the results */ -const resultCache = new WeakMap, any>(); - -/** Store result in the cache, and return the result */ -function cache(schema: Record, result: unknown) { - // Avoid unnecessary WeakMap operations for primitive values - if (typeof result !== "object" || result === null) { - return result; - } - - resultCache.set(schema, result); - - return result; -} - -/** - * This function takes an OpenAPI schema and generates an example from it - */ -export const getExampleFromSchema = ( - schema: Record, - options?: { - /** - * The fallback string for empty string values. - * @default '' - */ - emptyString?: string; - /** - * Whether to use the XML tag names as keys - * @default false - */ - xml?: boolean; - /** - * Whether to show read-only/write-only properties. Otherwise all properties are shown. - * @default undefined - */ - mode?: "read" | "write"; - /** - * Dynamic values to add to the example. - */ - variables?: Record; - /** - * Whether to omit empty and optional properties. - * @default false - */ - omitEmptyAndOptionalProperties?: boolean; - }, - level: number = 0, - parentSchema?: Record, - name?: string, -): any => { - if (!schema) return ""; - - // Check if the result is already cached - if (resultCache.has(schema)) { - return resultCache.get(schema); - } - - // Check whether it’s a circular reference - if (level === MAX_LEVELS_DEEP + 1) { - try { - // Fails if it contains a circular reference - JSON.stringify(schema); - } catch { - return "[Circular Reference]"; - } - } - - // Sometimes, we just want the structure and no values. - // But if `emptyString` is set, we do want to see some values. - const makeUpRandomData = !!options?.emptyString; - - // Check if the property is read-only/write-only - if ((options?.mode === "write" && schema.readOnly) || (options?.mode === "read" && schema.writeOnly)) { - return undefined; - } - - // Use given variables as values - if (schema["x-variable"]) { - const value = options?.variables?.[schema["x-variable"]]; - - // Return the value if it’s defined - if (value !== undefined) { - // Type-casting - if (schema.type === "number" || schema.type === "integer") { - return Number.parseInt(value, 10); - } - - return cache(schema, value); - } - } - - // Use the first example, if there’s an array - if (Array.isArray(schema.examples) && schema.examples.length > 0) { - return cache(schema, schema.examples[0]); - } - - // Use an example, if there’s one - if (schema.example !== undefined) { - return cache(schema, schema.example); - } - - // Use a default value, if there’s one - if (schema.default !== undefined) { - return cache(schema, schema.default); - } - - // enum: [ 'available', 'pending', 'sold' ] - if (Array.isArray(schema.enum) && schema.enum.length > 0) { - return cache(schema, schema.enum[0]); - } - - // Check if the property is required - const isObjectOrArray = - schema.type === "object" || - schema.type === "array" || - !!schema.allOf?.at?.(0) || - !!schema.anyOf?.at?.(0) || - !!schema.oneOf?.at?.(0); - if (!isObjectOrArray && options?.omitEmptyAndOptionalProperties === true) { - const isRequired = - schema.required === true || - parentSchema?.required === true || - parentSchema?.required?.includes(name ?? schema.name); - - if (!isRequired) { - return undefined; - } - } - - // Object - if (schema.type === "object" || schema.properties !== undefined) { - const response: Record = {}; - let propertyCount = 0; - - // Regular properties - if (schema.properties !== undefined) { - for (const propertyName in schema.properties) { - if (Object.prototype.hasOwnProperty.call(schema.properties, propertyName)) { - // Only apply property limit for nested levels (level > 0) - if (level > 3 && propertyCount >= MAX_PROPERTIES) { - response["..."] = "[Additional Properties Truncated]"; - break; - } - - const property = schema.properties[propertyName]; - const propertyXmlTagName = options?.xml ? property.xml?.name : undefined; - - const value = getExampleFromSchema(property, options, level + 1, schema, propertyName); - - if (typeof value !== "undefined") { - response[propertyXmlTagName ?? propertyName] = value; - propertyCount++; - } - } - } - } - - // Pattern properties (regex) - if (schema.patternProperties !== undefined) { - for (const pattern in schema.patternProperties) { - if (Object.prototype.hasOwnProperty.call(schema.patternProperties, pattern)) { - const property = schema.patternProperties[pattern]; - - // Use the regex pattern as an example key - const exampleKey = pattern; - - response[exampleKey] = getExampleFromSchema(property, options, level + 1, schema, exampleKey); - } - } - } - - // Additional properties - if (schema.additionalProperties !== undefined) { - const anyTypeIsValid = - // true - schema.additionalProperties === true || - // or an empty object {} - (typeof schema.additionalProperties === "object" && !Object.keys(schema.additionalProperties).length); - - if (anyTypeIsValid) { - response["ANY_ADDITIONAL_PROPERTY"] = "anything"; - } else if (schema.additionalProperties !== false) { - response["ANY_ADDITIONAL_PROPERTY"] = getExampleFromSchema(schema.additionalProperties, options, level + 1); - } - } - - if (schema.anyOf !== undefined) { - Object.assign(response, getExampleFromSchema(schema.anyOf[0], options, level + 1)); - } else if (schema.oneOf !== undefined) { - Object.assign(response, getExampleFromSchema(schema.oneOf[0], options, level + 1)); - } else if (schema.allOf !== undefined) { - Object.assign( - response, - ...schema.allOf - .map((item: Record) => getExampleFromSchema(item, options, level + 1, schema)) - .filter((item: any) => item !== undefined), - ); - } - - return cache(schema, response); - } - - // Array - if (schema.type === "array" || schema.items !== undefined) { - const itemsXmlTagName = schema?.items?.xml?.name; - const wrapItems = !!(options?.xml && schema.xml?.wrapped && itemsXmlTagName); - - if (schema.example !== undefined) { - return cache(schema, wrapItems ? { [itemsXmlTagName]: schema.example } : schema.example); - } - - // Check whether the array has a anyOf, oneOf, or allOf rule - if (schema.items) { - // First handle allOf separately since it needs special handling - if (schema.items.allOf) { - // If the first item is an object type, merge all schemas - if (schema.items.allOf[0].type === "object") { - const mergedExample = getExampleFromSchema( - { type: "object", allOf: schema.items.allOf }, - options, - level + 1, - schema, - ); - - return cache(schema, wrapItems ? [{ [itemsXmlTagName]: mergedExample }] : [mergedExample]); - } - // For non-objects (like strings), collect all examples - const examples = schema.items.allOf - .map((item: Record) => getExampleFromSchema(item, options, level + 1, schema)) - .filter((item: any) => item !== undefined); - - return cache(schema, wrapItems ? examples.map((example: any) => ({ [itemsXmlTagName]: example })) : examples); - } - - // Handle other rules (anyOf, oneOf) - const rules = ["anyOf", "oneOf"]; - for (const rule of rules) { - if (!schema.items[rule]) { - continue; - } - - const schemas = schema.items[rule].slice(0, 1); - const exampleFromRule = schemas - .map((item: Record) => getExampleFromSchema(item, options, level + 1, schema)) - .filter((item: any) => item !== undefined); - - return cache(schema, wrapItems ? [{ [itemsXmlTagName]: exampleFromRule }] : exampleFromRule); - } - } - - if (schema.items?.type) { - const exampleFromSchema = getExampleFromSchema(schema.items, options, level + 1); - - return wrapItems ? [{ [itemsXmlTagName]: exampleFromSchema }] : [exampleFromSchema]; - } - - return []; - } - - const exampleValues: Record = { - string: makeUpRandomData ? guessFromFormat(schema, options?.emptyString) : "", - boolean: true, - integer: schema.min ?? 1, - number: schema.min ?? 1, - array: [], - }; - - if (schema.type !== undefined && exampleValues[schema.type] !== undefined) { - return cache(schema, exampleValues[schema.type]); - } - - const discriminateSchema = schema.oneOf || schema.anyOf; - // Check if property has the `oneOf` | `anyOf` key - if (Array.isArray(discriminateSchema) && discriminateSchema.length > 0) { - // Get the first item from the `oneOf` | `anyOf` array - const firstOneOfItem = discriminateSchema[0]; - - // Return an example for the first item - return getExampleFromSchema(firstOneOfItem, options, level + 1); - } - - // Check if schema has the `allOf` key - if (Array.isArray(schema.allOf)) { - let example: any = null; - - // Loop through all `allOf` schemas - schema.allOf.forEach((allOfItem: Record) => { - // Return an example from the schema - const newExample = getExampleFromSchema(allOfItem, options, level + 1); - - // Merge or overwrite the example - example = - typeof newExample === "object" && typeof example === "object" - ? { - ...(example ?? {}), - ...newExample, - } - : Array.isArray(newExample) && Array.isArray(example) - ? [...(example ?? {}), ...newExample] - : newExample; - }); - - return cache(schema, example); - } - - // Check if schema is a union type - if (Array.isArray(schema.type)) { - // Return null if the type is nullable - if (schema.type.includes("null")) { - return null; - } - // Return an example for the first type in the union - const exampleValue = exampleValues[schema.type[0]]; - if (exampleValue !== undefined) { - return cache(schema, exampleValue); - } - } - - // Warn if the type is unknown … - // console.warn(`[getExampleFromSchema] Unknown property type "${schema.type}".`) - - // … and just return null for now. - return null; -}; diff --git a/src/lib/index.ts b/src/lib/index.ts deleted file mode 100644 index 9ef59daeed..0000000000 --- a/src/lib/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export * from "./constants"; -export * from "./docPageStore"; -export * from "./types"; -export * from "./generateCodeSnippetFromAPIRequest"; -export * from "./normalizePath"; -export * from "./generateExampleFromAPIRequestSchema"; -export * from "./getExampleFromSchema"; -export * from "./search"; -export * from "./themeStore"; -export * from "./replaceVariablesForScalar"; -export * from "./replaceVariablesInApiPath"; diff --git a/src/lib/normalizeOpenAPIObject.ts b/src/lib/normalizeOpenAPIObject.ts deleted file mode 100644 index b10402a12d..0000000000 --- a/src/lib/normalizeOpenAPIObject.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { OpenAPIV3 } from "@scalar/openapi-types"; - -export function normalizeOpenAPIObject(schema: OpenAPIV3.SchemaObject) { - if (!schema.allOf) return schema; - - const acc: OpenAPIV3.SchemaObject = { - type: "object", - name: schema.name, - properties: {}, - }; - - for (const item of schema.allOf) { - acc.properties = { ...acc.properties, ...item.properties }; - } - - if (schema.oneOf) { - acc.oneOf = schema.oneOf.map((item) => { - return { type: "object", properties: { ...item.properties, ...acc.properties } }; - }); - delete acc.properties; - } - - return acc; -} diff --git a/src/lib/normalizePath.ts b/src/lib/normalizePath.ts deleted file mode 100644 index ea2b68cb63..0000000000 --- a/src/lib/normalizePath.ts +++ /dev/null @@ -1,29 +0,0 @@ -export function normalizePath(path: string): string { - if (!path || typeof path !== "string") { - return "/"; - } - - const normalizedPath = path.startsWith("/") ? path : "/" + path; - const segments = normalizedPath.split("/").filter((segment) => segment.length > 0); - const normalizedSegments: string[] = []; - - for (const segment of segments) { - if (segment === ".") { - continue; - } else if (segment === "..") { - if (normalizedSegments.length > 0) { - normalizedSegments.pop(); - } - } else { - normalizedSegments.push(segment); - } - } - - const result = "/" + normalizedSegments.join("/"); - - if (path.endsWith("/") && result !== "/" && !path.endsWith("./") && !path.endsWith("../")) { - return result + "/"; - } - - return result; -} diff --git a/src/lib/replaceVariablesForScalar.ts b/src/lib/replaceVariablesForScalar.ts deleted file mode 100644 index 1c2a687f17..0000000000 --- a/src/lib/replaceVariablesForScalar.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { OpenAPIV3 } from "@scalar/openapi-types"; -import { replaceVariablesInApiPath } from "./replaceVariablesInApiPath"; - -export function replaceVariablesForScalar( - apiDocument: OpenAPIV3.Document, - apiName: "fdi" | "cdi", - variables: Record, -) { - let parsedDocument = { ...apiDocument }; - const serverUrl = apiName === "fdi" ? variables.apiDomain : variables.coreDomain; - parsedDocument.servers = [{ url: serverUrl }]; - - const pathParams = { - apiBasePath: variables.apiBasePath, - tenantId: variables.tenantId, - appId: variables.appId, - }; - - const pathsToRemove: string[] = []; - - // If the request parameters sepecifies an "examaple" value - // it will get rendered wrong by the API client (it makes you choose from a floating menu) - // We use "default" instead to force the element to be a simple text input - for (const path in parsedDocument.paths) { - for (const method in parsedDocument.paths[path]) { - const operation = parsedDocument.paths[path][method]; - if (!operation.parameters) continue; - operation.parameters = operation.parameters - .map((param: any) => { - let defaultValue: string = ""; - if (!param.schema) return param; - if (param.example) { - defaultValue = param.example; - delete param.example; - } - if (param.schema && param.schema.example) { - defaultValue = param.schema.example; - delete param.schema.example; - } - param.schema.default = pathParams[param.name] || defaultValue; - return param; - }) - .filter((param) => { - // Scalar doesn't play well witht our custom paths - // We build a custom path based on the config values and omit those in the API client - if (pathParams[param.name]) return false; - return true; - }); - - parsedDocument.paths[replaceVariablesInApiPath(path, pathParams)] = parsedDocument.paths[path]; - pathsToRemove.push(path); - } - } - - return parsedDocument; -} diff --git a/src/lib/replaceVariablesInApiPath.ts b/src/lib/replaceVariablesInApiPath.ts deleted file mode 100644 index f7d79169f0..0000000000 --- a/src/lib/replaceVariablesInApiPath.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { normalizePath } from "./normalizePath"; - -export function replaceVariablesInApiPath(path: string, variables: Record) { - let parsedPath = path; - for (const key in variables) { - parsedPath = parsedPath.replace(`{${key}}`, variables[key]); - } - return normalizePath(parsedPath); -} diff --git a/src/lib/scrollOffset.ts b/src/lib/scrollOffset.ts deleted file mode 100644 index 2fb8e9ed28..0000000000 --- a/src/lib/scrollOffset.ts +++ /dev/null @@ -1,62 +0,0 @@ -export function getNavbarHeight(): number { - if (typeof window === "undefined") return 140; - - const navbar = document.querySelector("nav.navbar"); - if (!navbar) return 140; - - const height = navbar.getBoundingClientRect().height; - return height; -} - -function scrollToElementWithOffset(element: Element): void { - const navbarHeight = getNavbarHeight(); - const elementRect = element.getBoundingClientRect(); - const absoluteElementTop = elementRect.top + window.pageYOffset; - const targetScrollTop = absoluteElementTop - navbarHeight - 16; - - window.scrollTo({ - top: targetScrollTop, - behavior: "smooth", - }); -} - -function handleHashNavigation(): void { - if (typeof window === "undefined") return; - - const hash = window.location.hash; - if (!hash) return; - - const targetId = hash.substring(1); - const targetElement = document.getElementById(targetId); - - if (targetElement) { - setTimeout(() => { - scrollToElementWithOffset(targetElement); - }, 100); - } -} - -function handleHashLinkClick(event: Event): void { - const target = event.target as HTMLElement; - const link = target.closest('a[href^="#"]') as HTMLAnchorElement; - - if (!link || !link.hash) return; - - const targetId = link.hash.substring(1); - const targetElement = document.getElementById(targetId); - - if (targetElement) { - event.preventDefault(); - history.pushState(null, "", link.hash); - scrollToElementWithOffset(targetElement); - } -} - -export function initScrollOffset(): void { - if (typeof window === "undefined") return; - - setTimeout(handleHashNavigation, 100); - setTimeout(handleHashNavigation, 500); - window.addEventListener("hashchange", handleHashNavigation); - document.addEventListener("click", handleHashLinkClick); -} diff --git a/src/lib/search.ts b/src/lib/search.ts deleted file mode 100644 index 781c70a668..0000000000 --- a/src/lib/search.ts +++ /dev/null @@ -1,302 +0,0 @@ -import { searchClient, SearchResponses } from "@algolia/client-search"; -import type { Hit } from "@algolia/client-search"; - -import fdiPathsMapping from "/fdi-mapping.json"; -import cdiPathsMapping from "/cdi-mapping.json"; - -type SearchResultType = "guide" | "tutorial" | "sdk-reference" | "api-reference"; - -export type ParsedSearchResult = - | { - index: "supertokens_documentation"; - id: string; - url: string; - meta: { - highlight: string; - category: string; - hierarchy: string[]; - type: SearchResultType; - }; - } - | { - index: "supertokens_api_references"; - id: string; - url: string; - meta: { - summary: string; - method: string; - path: string; - apiType: "fdi" | "cdi"; - }; - } - | { - index: "supertokens_sdk_references"; - id: string; - url: string; - meta: { - name: string; - signature: string; - language: "typescript" | "go" | "python"; - type: "variable" | "function" | "class" | "type" | "method"; - namespace: string; - }; - }; - -type DocumentationSearchResult = { - anchor: string; - category: string; - content: string; - type: SearchResultType; - hierarchy: { - lvl0: string | null; - lvl1: string | null; - lvl2: string | null; - lvl3: string | null; - lvl4: string | null; - lvl5: string | null; - lvl6: string | null; - }; - url: string; -}; - -type ApiReferenceSearchResult = { - endpoint: { - path: string; - method: string; - summary: string; - description?: string; - operationId?: string; - tags: string[]; - deprecated: boolean; - path_depth: number; - }; - apiType: "cdi" | "fdi"; - version?: string; -}; - -type SdkReferenceSearchResult = { - name: string; - type: "variable" | "function" | "class" | "type" | "method"; - language: "typescript" | "go" | "python"; - repository: string; - file: string; - line: number; - content: string; - comments?: string; - signature?: string; - returnType?: string; - namespace: string; - deprecated: boolean; -}; - -type SearchResultHit = Hit | Hit | Hit; - -const client = searchClient("HQ5R0VRJGG", "b6f38b3627dcd0642b67f24fe2e1a8eb"); -const SearchCache: Record = {}; -const CacheTTL = 1000 * 60 * 5; -type IndexName = "supertokens_documentation" | "supertokens_api_references" | "supertokens_sdk_references"; - -type DocumentationIndexPageType = "guide" | "tutorial" | "sdk-reference" | "api-reference"; -type DocumentationIndexTypeFacetFilter = `type:${DocumentationIndexPageType}`; - -type QueryParameters = { - indexName: IndexName; - facetFilters?: DocumentationIndexTypeFacetFilter[] | DocumentationIndexTypeFacetFilter[][]; -}; - -export async function search(query: string, _parameters?: QueryParameters[]): Promise { - const parameters = _parameters || [ - { indexName: "supertokens_documentation" }, - { indexName: "supertokens_api_references" }, - { indexName: "supertokens_sdk_references" }, - ]; - const cacheKey = parameters.map((p) => `${p.indexName}-${query}-${p.facetFilters?.join(":")}`).join(";"); - - if (SearchCache[cacheKey] && SearchCache[cacheKey].timestamp > new Date(Date.now() - CacheTTL)) { - return SearchCache[cacheKey].results; - } - - try { - const response = await client.search({ - requests: parameters.map((param) => ({ - indexName: param.indexName, - query, - facetFilters: param.facetFilters, - offset: 0, - length: 50, - highlightPreTag: "", - highlightPostTag: "", - snippetEllipsisText: "…", - attributesToSnippet: [ - "hierarchy.lvl1:10", - "hierarchy.lvl2:10", - "hierarchy.lvl3:10", - "hierarchy.lvl4:10", - "content:20", - "category:10", - ], - })), - }); - if (SearchCache[cacheKey]) { - clearTimeout(SearchCache[cacheKey].cleanupFn); - } - const results = parseResponse(response); - SearchCache[cacheKey] = { - results, - timestamp: new Date(), - cleanupFn: setTimeout(() => { - delete SearchCache[cacheKey]; - }, CacheTTL), - }; - return results; - } catch (e) { - console.error(e); - return null; - } -} - -function parseResponse(response: SearchResponses): ParsedSearchResult[] { - return response.results - .map((indexResponse) => { - if (!("hits" in indexResponse)) { - console.warn("No hits found in index response", indexResponse); - return []; - } - return indexResponse.hits.map((hit) => { - if (indexResponse.index === "supertokens_sdk_references") { - return parseSdkReferenceSearchResult(hit as Hit); - } else if (indexResponse.index === "supertokens_api_references") { - return parseApiReferenceSearchResult(hit as Hit); - } - - return parseDocumentationSearchResult(hit as Hit); - }); - }) - .flat() - .filter(Boolean); -} - -function parseDocumentationSearchResult(hit: Hit): ParsedSearchResult { - if (!hit._highlightResult || !hit._highlightResult.hierarchy) { - console.warn("No highlight result found for hit", hit); - return undefined; - } - - const highlight = extractHighlight(hit); - if (!highlight) { - console.warn("No highlight found for hit", hit); - } - let hierarchy: string[] = []; - if (hit.hierarchy) { - hierarchy = Object.values(hit.hierarchy).filter(Boolean); - } - - return { - id: hit.objectID, - index: "supertokens_documentation", - url: hit.url, - meta: { - type: hit.type, - hierarchy, - highlight, - category: hit.category, - }, - }; -} - -function parseApiReferenceSearchResult(hit: Hit): ParsedSearchResult { - const pathsMapping = hit.apiType.toLowerCase() === "cdi" ? cdiPathsMapping : fdiPathsMapping; - const mapping = pathsMapping[hit.endpoint.operationId]; - let url = `https://supertokens.com/docs/references`; - if (mapping) { - url = `${url}${mapping.filePath.replace(/\.mdx$/, "")}`; - } else { - url = `${url}/${hit.apiType.toLowerCase()}`; - } - - return { - id: hit.objectID, - index: "supertokens_api_references", - url, - meta: { - method: hit.endpoint.method, - path: hit.endpoint.path, - summary: hit.endpoint.summary, - apiType: hit.apiType, - }, - }; -} - -function parseSdkReferenceSearchResult(hit: Hit): ParsedSearchResult { - const filePathWithoutPrefix = hit.file.replace("./", ""); - const url = `https://github.com/supertokens/${hit.repository}/blob/master/${filePathWithoutPrefix}#L${hit.line}`; - - return { - id: hit.objectID, - index: "supertokens_sdk_references", - url, - meta: { - name: hit.name, - signature: hit.signature, - language: hit.language, - namespace: hit.namespace, - type: hit.type, - }, - }; -} - -function extractHighlight(hit: SearchResultHit): string | undefined { - if (!hit._snippetResult) { - return undefined; - } - - const snippetResult = hit._snippetResult; - - // @ts-expect-error - if (snippetResult.content && snippetResult.content?.matchLevel !== "none") { - // @ts-expect-error - return snippetResult.content.value; - } - - // @ts-expect-error - if (snippetResult.category && snippetResult.category.matchLevel !== "none") { - const hierarchyItems = Object.values(snippetResult.hierarchy); - const lastHierarchyItem = hierarchyItems[hierarchyItems.length - 1]; - // @ts-expect-error - return `${formatCategory(snippetResult.category.value)} - ${lastHierarchyItem.value}`; - } - - // If the match is based on headings get two values to prevent multiple rows with the same value - const hierarchyItems = Object.values(snippetResult.hierarchy); - const matchedHierarchyItemIndex = hierarchyItems.findIndex((item) => item?.matchLevel !== "none"); - if (matchedHierarchyItemIndex === -1) { - console.warn("No match level found for hierarchy items", hierarchyItems); - return undefined; - } - - const matchedHierarchyItem = hierarchyItems[matchedHierarchyItemIndex]; - const nextIndex = matchedHierarchyItemIndex + 1; - if (nextIndex >= hierarchyItems.length) { - return matchedHierarchyItem.value; - } else { - const nextHierarchyItem = hierarchyItems[nextIndex]; - return `${matchedHierarchyItem.value} - ${nextHierarchyItem?.value}`; - } -} - -function formatCategory(label: string): string { - return label - .split(" ") - .map((word) => { - const regex = /(.*?)<\/mark>/g; - const matches = word.match(regex); - let extractedWord = !matches.length ? word : matches.map((match) => match.replace(/<\/?mark>/g, "")).join(""); - if (extractedWord === "sdk") return "SDK"; - if (extractedWord === "cdi") return "CDI"; - if (extractedWord === "fdi") return "FDI"; - if (extractedWord === "ai") return "AI"; - extractedWord = extractedWord.charAt(0).toUpperCase() + extractedWord.slice(1); - return matches.length ? `${extractedWord}` : extractedWord; - }) - .join(" "); -} diff --git a/src/lib/themeStore.ts b/src/lib/themeStore.ts deleted file mode 100644 index d315ece590..0000000000 --- a/src/lib/themeStore.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { useSyncExternalStore } from "react"; - -export type ColorMode = "light" | "dark"; - -// The color mode explicitly chosen by the user -// null => no choice has been made, or the choice has been reverted to OS value -export type ColorModeChoice = ColorMode | null; - -function getSystemColorMode(): ColorMode { - if (typeof window === "undefined") return "light"; - return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; -} - -function subscribeToMedia(query: string, listener: (event: MediaQueryListEvent) => void): () => void { - if (typeof window === "undefined") return () => {}; - const mql = window.matchMedia(query); - mql.addEventListener("change", listener); - return () => mql.removeEventListener("change", listener); -} - -function subscribeToSystemColorModeChange(onChange: (newSystemColorMode: ColorMode) => void): () => void { - return subscribeToMedia("(prefers-color-scheme: dark)", () => onChange(getSystemColorMode())); -} - -const ColorModeStorageKey = "supertokens-theme"; - -const storage = { - get: (): string | null => { - if (typeof window === "undefined") return null; - try { - return localStorage.getItem(ColorModeStorageKey); - } catch { - return null; - } - }, - set: (value: string) => { - if (typeof window === "undefined") return; - try { - localStorage.setItem(ColorModeStorageKey, value); - } catch {} - }, - del: () => { - if (typeof window === "undefined") return; - try { - localStorage.removeItem(ColorModeStorageKey); - } catch {} - }, - listen: (callback: (event: { newValue: string | null }) => void) => { - if (typeof window === "undefined") return () => {}; - - const listener = (e: StorageEvent) => { - if (e.key === ColorModeStorageKey) { - callback({ newValue: e.newValue }); - } - }; - - window.addEventListener("storage", listener); - return () => window.removeEventListener("storage", listener); - }, -}; - -const DefaultColorMode: ColorMode = "dark"; -const SystemAttribute = "system"; - -const coerceToColorMode = (colorMode: string | null): ColorMode => (colorMode === "dark" ? "dark" : "light"); -const coerceToColorModeChoice = (colorMode: string | null): ColorModeChoice => - colorMode === null || colorMode === SystemAttribute ? null : coerceToColorMode(colorMode); - -const ColorModeAttribute = { - get: (): ColorMode => { - if (typeof document === "undefined") return DefaultColorMode; - return coerceToColorMode(document.documentElement.getAttribute("data-theme")); - }, - set: (colorMode: ColorMode) => { - if (typeof document === "undefined") return; - document.documentElement.setAttribute("data-theme", coerceToColorMode(colorMode)); - }, -}; - -const ColorModeChoiceAttribute = { - get: (): ColorModeChoice => { - if (typeof document === "undefined") return null; - return coerceToColorModeChoice(document.documentElement.getAttribute("data-theme-choice")); - }, - set: (colorMode: ColorModeChoice) => { - if (typeof document === "undefined") return; - document.documentElement.setAttribute("data-theme-choice", coerceToColorModeChoice(colorMode) ?? SystemAttribute); - }, -}; - -const persistColorModeChoice = (newColorMode: ColorModeChoice) => { - if (newColorMode === null) { - storage.del(); - } else { - const coercedValue = coerceToColorMode(newColorMode); - storage.set(coercedValue); - } -}; - -interface ThemeState { - colorMode: ColorMode; - colorModeChoice: ColorModeChoice; -} - -class ThemeStore { - private state: ThemeState; - private listeners = new Set<() => void>(); - private systemChangeUnsubscribe: (() => void) | null = null; - private storageUnsubscribe: (() => void) | null = null; - private initialized = false; - - constructor() { - this.state = { - colorMode: DefaultColorMode, - colorModeChoice: null, - }; - } - - private initialize() { - if (this.initialized) return; - this.initialized = true; - - const storedValue = storage.get(); - const storedChoice = coerceToColorModeChoice(storedValue); - - let colorModeChoice: ColorModeChoice; - let colorMode: ColorMode; - - if (storedChoice !== null) { - colorModeChoice = storedChoice; - colorMode = storedChoice; - } else { - colorModeChoice = ColorModeChoiceAttribute.get(); - colorMode = colorModeChoice !== null ? colorModeChoice : getSystemColorMode(); - } - - this.state = { - colorMode, - colorModeChoice, - }; - - // Update DOM attributes to match the restored state - ColorModeAttribute.set(colorMode); - ColorModeChoiceAttribute.set(colorModeChoice); - - this.systemChangeUnsubscribe = subscribeToSystemColorModeChange((newSystemColorMode) => { - if (this.state.colorModeChoice === null) { - this.updateColorMode(newSystemColorMode, this.state.colorModeChoice); - } - }); - - // Subscribe to storage changes (for cross-tab synchronization) - this.storageUnsubscribe = storage.listen((e) => { - const newChoice = coerceToColorModeChoice(e.newValue); - - if (newChoice !== this.state.colorModeChoice) { - this.setColorMode(newChoice, false); - } - }); - } - - private updateColorMode(colorMode: ColorMode, colorModeChoice: ColorModeChoice) { - this.state = { colorMode, colorModeChoice }; - ColorModeAttribute.set(colorMode); - ColorModeChoiceAttribute.set(colorModeChoice); - this.notifyListeners(); - } - - private notifyListeners() { - this.listeners.forEach((listener) => listener()); - } - - getSnapshot = (): ThemeState => { - if (!this.initialized && typeof window !== "undefined") { - this.initialize(); - } - return this.state; - }; - - subscribe = (listener: () => void): (() => void) => { - if (!this.initialized && typeof window !== "undefined") { - this.initialize(); - } - - this.listeners.add(listener); - return () => { - this.listeners.delete(listener); - }; - }; - - setColorMode = (newColorModeChoice: ColorModeChoice, persist = true) => { - if (newColorModeChoice === null) { - const newColorMode = getSystemColorMode(); - this.updateColorMode(newColorMode, null); - } else { - this.updateColorMode(newColorModeChoice, newColorModeChoice); - } - - if (persist) persistColorModeChoice(newColorModeChoice); - }; - - destroy() { - this.systemChangeUnsubscribe?.(); - this.storageUnsubscribe?.(); - this.listeners.clear(); - } -} - -const themeStore = new ThemeStore(); - -export type ThemeOption = "system" | "light" | "dark"; - -export function useTheme() { - const state = useSyncExternalStore(themeStore.subscribe, themeStore.getSnapshot, () => ({ - colorMode: DefaultColorMode, - colorModeChoice: null, - })); - - const setTheme = (theme: ThemeOption) => { - const colorModeChoice = theme === "system" ? null : theme; - themeStore.setColorMode(colorModeChoice); - }; - - return { - theme: state.colorMode, - setTheme, - }; -} - -export { themeStore }; diff --git a/src/lib/types.ts b/src/lib/types.ts deleted file mode 100644 index 5a0ef8f9ab..0000000000 --- a/src/lib/types.ts +++ /dev/null @@ -1,342 +0,0 @@ -type SaasConnectionUrlDomainCommonInfo = { - deploymentId: string; - deploymentName: string; - region: string; -}; - -type SaasAppDeploymentConnectionInfo = { - host: string; - apiKeys: string[]; -}; - -type SaasConnectionUriDomainApp = { - appId: string; - deployments: SaasAppDeployment[]; -}; - -type SaasAppDeploymentCommonInfo = { - coreVersion: string; - config: SaasAppDeploymentConfig[]; - status: "active" | "restarting"; -}; - -type SaasAppDeploymentConfig = { - keyName: string; - value: string; - description: string | number | boolean; -}; - -type SaasAppDevDeployment = SaasAppDeploymentCommonInfo & { - deploymentType: "development"; - connectionInfo: SaasAppDeploymentConnectionInfo; -}; - -type SaasAppProdDeployment = SaasAppDeploymentCommonInfo & { - deploymentType: "production"; - connectionInfo?: SaasAppDeploymentConnectionInfo & { - serviceApiKey: string; - }; - pricing?: { - basePrice: number; - pricePerInstance: number; - numberOfInstancesToPayFor: number; - nextDueDate?: number; - }; -}; - -type SaasAppDeployment = SaasAppDevDeployment | SaasAppProdDeployment; - -export type SaasConnectionUrlDomain = SaasConnectionUrlDomainCommonInfo & - ( - | { - isTemporarilyRemoved: false; - apps: SaasConnectionUriDomainApp[]; - } - | { - isTemporarilyRemoved: true; - isRecreating: boolean; - } - ); - -export type SaasAppListItem = { - appName: string; - appId: string; - region: string; - isTemporarilyRemoved: boolean; - devDeployment: SassAppDevData; - prodDeployment: SassAppProductionData; -}; - -export type SassAppDevData = { - id: string; - /** Version in format X.Y */ - supertokensVersion?: string; - connectionInfo?: { - host: string; - apiKeys: string[]; - }; - config: { - keyName: string; - value: string | number | boolean; - description: string; - }[]; - supertokensInstance: { - status: "active" | "restarting"; - /** unique ID across all instances */ - containerName: string; - }[]; -}; - -type SassAppProductionData = SassAppDevData & { - userHadCreated: boolean; - connectionInfo?: SassAppDevData["connectionInfo"] & { - serviceApiKey: string; - }; - pricing?: { - basePrice: number; - pricePerInstance: number; - numberOfInstancesToPayFor: number; - nextDueDate?: number; - }; -}; - -export interface OpenAPIDocument { - openapi: string; - info: InfoObject; - servers?: ServerObject[]; - paths: PathsObject; - components?: ComponentsObject; - security?: SecurityRequirementObject[]; - tags?: TagObject[]; - externalDocs?: ExternalDocumentationObject; -} - -interface InfoObject { - title: string; - description?: string; - termsOfService?: string; - contact?: ContactObject; - license?: LicenseObject; - version: string; -} - -interface ContactObject { - name?: string; - url?: string; - email?: string; -} - -interface LicenseObject { - name: string; - url?: string; -} - -interface ServerObject { - url: string; - description?: string; - variables?: { [variable: string]: ServerVariableObject }; -} - -interface ServerVariableObject { - enum?: string[]; - default: string; - description?: string; -} - -interface PathsObject { - [path: string]: PathItemObject; -} - -interface PathItemObject { - $ref?: string; - summary?: string; - description?: string; - get?: OperationObject; - put?: OperationObject; - post?: OperationObject; - delete?: OperationObject; - options?: OperationObject; - head?: OperationObject; - patch?: OperationObject; - trace?: OperationObject; - servers?: ServerObject[]; - parameters?: (ParameterObject | ReferenceObject)[]; -} - -interface OperationObject { - tags?: string[]; - summary?: string; - description?: string; - externalDocs?: ExternalDocumentationObject; - operationId?: string; - parameters?: (ParameterObject | ReferenceObject)[]; - requestBody?: RequestBodyObject | ReferenceObject; - responses: ResponsesObject; - callbacks?: { [callback: string]: CallbackObject | ReferenceObject }; - deprecated?: boolean; - security?: SecurityRequirementObject[]; - servers?: ServerObject[]; -} - -interface ExternalDocumentationObject { - description?: string; - url: string; -} - -interface ParameterObject { - name: string; - in: "query" | "header" | "path" | "cookie"; - description?: string; - required?: boolean; - deprecated?: boolean; - allowEmptyValue?: boolean; - style?: string; - explode?: boolean; - allowReserved?: boolean; - schema?: SchemaObject | ReferenceObject; - example?: any; - examples?: { [media: string]: ExampleObject | ReferenceObject }; - content?: { [media: string]: MediaTypeObject }; -} - -interface ReferenceObject { - $ref: string; -} - -interface RequestBodyObject { - description?: string; - content: { [media: string]: MediaTypeObject }; - required?: boolean; -} - -interface ResponsesObject { - [status: string]: ResponseObject | ReferenceObject; -} - -interface ResponseObject { - description: string; - headers?: { [header: string]: HeaderObject | ReferenceObject }; - content?: { [media: string]: MediaTypeObject }; - links?: { [link: string]: LinkObject | ReferenceObject }; -} - -interface CallbackObject { - [url: string]: PathItemObject | ReferenceObject; -} - -interface ExampleObject { - summary?: string; - description?: string; - value?: any; - externalValue?: string; -} - -interface MediaTypeObject { - schema?: SchemaObject | ReferenceObject; - example?: any; - examples?: { [media: string]: ExampleObject | ReferenceObject }; - encoding?: { [media: string]: EncodingObject }; -} - -interface EncodingObject { - contentType?: string; - headers?: { [header: string]: HeaderObject | ReferenceObject }; - style?: string; - explode?: boolean; - allowReserved?: boolean; -} - -interface HeaderObject extends ParameterObject {} - -interface LinkObject { - operationRef?: string; - operationId?: string; - parameters?: { [parameter: string]: any }; - requestBody?: any; - description?: string; - server?: ServerObject; -} - -interface SecurityRequirementObject { - [name: string]: string[]; -} - -interface ComponentsObject { - schemas?: { [schema: string]: SchemaObject | ReferenceObject }; - responses?: { [response: string]: ResponseObject | ReferenceObject }; - parameters?: { [parameter: string]: ParameterObject | ReferenceObject }; - examples?: { [example: string]: ExampleObject | ReferenceObject }; - requestBodies?: { [request: string]: RequestBodyObject | ReferenceObject }; - headers?: { [header: string]: HeaderObject | ReferenceObject }; - securitySchemes?: { - [scheme: string]: SecuritySchemeObject | ReferenceObject; - }; - links?: { [link: string]: LinkObject | ReferenceObject }; - callbacks?: { [callback: string]: CallbackObject | ReferenceObject }; -} - -interface SchemaObject { - title?: string; - description?: string; - type?: string; - format?: string; - nullable?: boolean; - required?: string[]; - properties?: { [property: string]: SchemaObject | ReferenceObject }; - items?: SchemaObject | ReferenceObject; - allOf?: (SchemaObject | ReferenceObject)[]; - oneOf?: (SchemaObject | ReferenceObject)[]; - anyOf?: (SchemaObject | ReferenceObject)[]; - not?: SchemaObject | ReferenceObject; - enum?: any[]; - // Add more schema properties as needed -} - -interface TagObject { - name: string; - description?: string; - externalDocs?: ExternalDocumentationObject; -} - -interface SecuritySchemeObject { - type: string; - description?: string; - name?: string; - in?: string; - scheme?: string; - bearerFormat?: string; - flows?: OAuthFlowsObject; - openIdConnectUrl?: string; -} - -interface OAuthFlowsObject { - implicit?: OAuthFlowObject; - password?: OAuthFlowObject; - clientCredentials?: OAuthFlowObject; - authorizationCode?: OAuthFlowObject; -} - -interface OAuthFlowObject { - authorizationUrl: string; - tokenUrl: string; - refreshUrl?: string; - scopes: { [scope: string]: string }; -} - -export type InferDotNotationKeys = T extends object - ? { - [K in keyof T]: K extends string - ? T[K] extends object - ? `${K}` | `${K}.${InferDotNotationKeys}` - : `${K}` - : never; - }[keyof T] - : never; - -export type InferDotNotationValue = P extends keyof T - ? T[P] - : P extends `${infer K}.${infer Rest}` - ? K extends keyof T - ? InferDotNotationValue - : never - : never; diff --git a/src/plugins/addNofollowToExternalLinks.js b/src/plugins/addNofollowToExternalLinks.js deleted file mode 100644 index bb140f49b8..0000000000 --- a/src/plugins/addNofollowToExternalLinks.js +++ /dev/null @@ -1,84 +0,0 @@ -const url = require("url"); - -module.exports = () => { - /** - * Check if the URL is external or not - * @param {string} href the URL that is to be checked - * @returns boolean true if the URL is external and false otherwise - */ - function isUrlExternal(href) { - try { - const hrefFromURL = new url.URL(href); - const host = hrefFromURL.host; - const protocol = hrefFromURL.protocol; - - // no nofollow needed for email or phone number links - if (protocol === "mailto:" || protocol === "tel:") { - return false; - } - - // if the host contains `supertokens.com` - if (host.includes("supertokens.com")) { - return false; - } - - // if the host does not contain `supertokens.com`, it is an external URL - return true; - } catch { - // the URL constructor throws in case the URL is relative - // in that case it is not an external url - return false; - } - } - - /** - * Check if the node element is a link and if it should have `nofollow` - * @param {Node} data element node from the document's tree - * @returns boolean true if `nofollow` should be added and false otherwise - */ - function shouldAddNofollowToLink(data) { - return ( - data !== undefined && - data.type === "element" && - data.tagName === "a" && - data.properties !== undefined && - isUrlExternal(data.properties.href) - ); - } - - /** - * Add `nofollow` to the element passed if it is an external link and recursively do the same to the element's children - * @param {Node} data element node from the document's tree - * @returns updated element with `nofollow` in external links - */ - function addNofollowToExternalLinks(data) { - try { - if (shouldAddNofollowToLink(data)) { - data.properties = Object.assign({}, data.properties, { - rel: "nofollow noreferrer noopener", - }); - } - - if (data.children) { - data.children = data.children.map((child) => { - return addNofollowToExternalLinks(child); - }); - } - - return data; - } catch (error) { - console.log(error.message); - } - } - - const transformer = (data, _) => { - if (data.children !== undefined && data.children.length > 0) { - data.children = data.children.map((child) => { - return addNofollowToExternalLinks(child); - }); - } - return data; - }; - - return transformer; -}; diff --git a/src/plugins/generateLllmsFullTxt.ts b/src/plugins/generateLllmsFullTxt.ts deleted file mode 100644 index 3e8ea3eac1..0000000000 --- a/src/plugins/generateLllmsFullTxt.ts +++ /dev/null @@ -1,415 +0,0 @@ -import fs from "fs"; -import type { OpenAPIV3 } from "@scalar/openapi-types"; -import path from "path"; -import matter from "gray-matter"; -import { getAllMdxFiles } from "./utils/getAllMdxFiles"; - -async function extractImportStatements(content: string): Promise<{ name: string; module: string; index: number }[]> { - const imports: Array<{ name: string; module: string; index: number }> = []; - const importPattern = /import\s+(?:(?:{[\s\S]*?})|(?:[\w*]+))\s+from\s+['"]([^'"]+)['"]/g; - - let match; - while ((match = importPattern.exec(content)) !== null) { - const importStatement = match[0]; - const modulePath = match[1]; - const index = match[2]; - - if (importStatement.includes("{")) { - const namedMatch = importStatement.match(/import\s+{([\s\S]*?)}\s+from/); - if (namedMatch && namedMatch[1]) { - const namedImportsText = namedMatch[1].replace(/\s*,\s*/g, ",").replace(/[\r\n]+\s*/g, ""); - - const namedImports = namedImportsText - .split(",") - .map((name) => name.trim()) - .filter((name) => name.length > 0); - - for (const name of namedImports) { - imports.push({ - name: name, - module: modulePath, - index, - }); - } - } - } else { - const defaultMatch = importStatement.match(/import\s+([\w*]+)\s+from/); - if (defaultMatch && defaultMatch[1]) { - const componentName = defaultMatch[1].trim(); - imports.push({ - name: componentName, - module: modulePath, - index, - }); - } - } - } - - return imports.filter((item) => item.module.includes("src") || item.module.includes("_blocks")); -} - -function extractMainTitle(mdxContent: string): { - title: string; - content: string; -} { - const trimmedContent = mdxContent.trim(); - - const h1Regex = /^#\s+(.+?)(?:\r?\n|$)/m; - const h1Match = trimmedContent.match(h1Regex); - - if (h1Match) { - const title = h1Match[1].trim(); - const content = trimmedContent.replace(h1Match[0], "").trim(); - - return { title, content }; - } - - const lines = trimmedContent.split(/\r?\n/); - let titleLine = ""; - let titleIndex = -1; - const importRegex = /^import\s+.+from\s+['"].+['"];?$/; - - for (let i = 0; i < lines.length; i++) { - const line = lines[i].trim(); - if (!line || importRegex.test(line)) { - continue; - } - - titleLine = line; - titleIndex = i; - break; - } - - let contentLines = [...lines]; - if (titleIndex >= 0) { - contentLines.splice(titleIndex, 1); - } else { - titleLine = "Untitled Document"; - } - - return { - title: titleLine, - content: contentLines.join("\n").trim(), - }; -} - -function removeImportStatements(content: string): string { - const lines = content.split("\n"); - const cleanedLines: string[] = []; - - let i = 0; - while (i < lines.length) { - const line = lines[i].trim(); - - if (line.startsWith("import ")) { - if (line.includes(";") || line.includes(" from ")) { - i++; - continue; - } - - let importComplete = false; - while (i < lines.length && !importComplete) { - const currentLine = lines[i]; - if (currentLine.includes(";") || currentLine.includes(" from ")) { - importComplete = true; - } - i++; - } - continue; - } - - if (line.startsWith("export ") && line.includes(" from ")) { - if (line.includes(";")) { - i++; - continue; - } - - let exportComplete = false; - while (i < lines.length && !exportComplete) { - const currentLine = lines[i]; - if (currentLine.includes(";")) { - exportComplete = true; - } - i++; - } - continue; - } - - cleanedLines.push(lines[i]); - i++; - } - - let result = cleanedLines.join("\n"); - result = result.replace(/^\n+/, ""); - result = result.replace(/\n{3,}/g, "\n\n"); - return result; -} - -function removeReferences(content: string): string { - const lines = content.split(/\r?\n/); - - const nextStepsIndex = lines.indexOf("## Next steps"); - if (nextStepsIndex >= 0) { - lines.splice(nextStepsIndex, 1); - } - - const seeAlsoIndex = lines.indexOf("## See also"); - if (seeAlsoIndex >= 0) { - lines.splice(seeAlsoIndex, 1); - } - - return lines.join("\n").trim(); -} - -const AllImports: Array<{ name: string; module: string }> = []; - -const fdiReference = JSON.parse(fs.readFileSync("./static/fdi.json", "utf8")) as OpenAPIV3.Document; -const cdiReference = JSON.parse(fs.readFileSync("./static/cdi.json", "utf8")) as OpenAPIV3.Document; - -async function parseApiReferenceContent(filePath: string, apiType: "fdi" | "cdi"): Promise { - const mdxContent = await fs.promises.readFile(filePath, "utf8"); - const regex = /path\s*=\s*"([^"]+)"/; - const match = mdxContent.match(regex); - const path = match[1]; - const apiSpec = apiType === "fdi" ? fdiReference : cdiReference; - - if (path) { - const value = apiSpec.paths[path]; - if (value) return JSON.stringify(value, null, 2); - } - - return ""; -} - -async function parseMdxContent(filePath: string, usePageTitle = false): Promise { - const mdxContent = await fs.promises.readFile(filePath, "utf8"); - const { content } = matter(mdxContent); - const imports: Array<{ name: string; module: string }> = await extractImportStatements(content); - AllImports.push(...imports); - - const mdxBlocks = imports.filter((item) => item.module.includes("_blocks")); - let index = 0; - let processedContent = removeImportStatements(content); - const dirPath = path.dirname(filePath); - - for (const block of mdxBlocks) { - const blockPath = block.module.startsWith("/") ? `.${block.module}` : path.join(dirPath, block.module); - const blockContent = await parseMdxContent(blockPath); - processedContent = processedContent.replaceAll(`<${block.name} />`, blockContent); - } - - const componentsToRemove: string[] = [ - "AppInfoForm", - "UIType.Switch", - "PaidFeatureCallout", - "TokensCallout", - "ExampleAppForm", - "OAuthVerifyTokensCallout", - "PasswordlessRecipeForm", - "OAuthEmailVerificationCallout", - "TokensCallout", - ]; - const componentsToReplace: Record = { - "UIType.CustomUIContent": "CustomUIInstructions", - "UIType.PrebuiltUIContent": "PrebuiltUIInstructions", - FrontendCustomUITabs: "Tabs", - FrontendPrebuiltUITabs: "Tabs", - BackendTabs: "Tabs", - NodePackageManagerCard: "Tabs", - FrontendTabs: "Tabs", - DatabaseTabs: "Tabs", - JavascriptHttpLibraryCard: "Tabs", - NpmOrScriptsCard: "Tabs", - MobileFrameworksCard: "Tabs", - CodeSampleCard: "Tabs", - NodeFrameworksCard: "Tabs", - GoFrameworksCard: "Tabs", - PythonFrameworksCard: "Tabs", - SelfHostingTabs: "Tabs", - AccountTypeCard: "Tabs", - PythonSyncAsyncCard: "Tabs", - }; - - for (const component in componentsToReplace) { - processedContent = processedContent.replaceAll(component, componentsToReplace[component]); - } - - processedContent = processedContent.replaceAll("Tabs.TabItem", "Tab"); - processedContent = processedContent.replaceAll("Tabs.Content", "Tab"); - - for (const component of componentsToRemove) { - processedContent = processedContent.replaceAll(`<${component} />`, ""); - processedContent = processedContent.replaceAll(`<${component}/>`, ""); - } - - processedContent = removeReferences(processedContent); - processedContent = replaceVariables(processedContent); - - if (filePath.includes("_blocks")) { - return processedContent.trim(); - } - - const llmsRegex = /[\s\S]*?<\/RemoveForLLMs>/g; - processedContent = processedContent.replaceAll(llmsRegex, ""); - - const { title, content: contentWithoutTitle } = extractMainTitle(processedContent); - const filePathWithoutExtension = filePath.replace(/\.[^/.]+$/, ""); - const [, relativePath] = filePathWithoutExtension.split("/docs").filter(Boolean); - const url = `https://supertokens.com/docs${relativePath}`; - const parsedTitle = usePageTitle ? title : buildTitle(title, filePath); - processedContent = ` -# ${parsedTitle} -Source: ${url} - -${contentWithoutTitle} -`; - - return processedContent.trim(); -} - -function replaceVariables(content: string): string { - const variables = [ - ["^{appInfo.appName}", ""], - ["^{appInfo.apiDomain}", ""], - ["^{appInfo.websiteDomain}", ""], - ["^{appInfo.apiBasePath}", ""], - ["^{appInfo.websiteBasePath}", ""], - ["^{coreInfo.uri}", ""], - ["^{coreInfo.apiKey}", ""], - ]; - - let processedContent = content; - for (const [variable, value] of variables) { - processedContent = processedContent.replaceAll(variable, value); - } - - return processedContent; -} - -function buildTitle(currentTitle: string, filePath: string): string { - const [, relativePath] = filePath.split("/docs").filter(Boolean); - const dirPath = path.dirname(relativePath); - const pathComponents = dirPath.split("/").filter(Boolean); - - let title = ""; - let currentPath = `./docs`; - for (const component of pathComponents) { - const categoryJsonPath = path.join(currentPath, component, "_category_.json"); - currentPath = path.join(currentPath, component); - const categoryJson = JSON.parse(fs.readFileSync(categoryJsonPath, "utf8")); - title += `${categoryJson.label} - `; - } - - if (!currentTitle) { - console.warn("No title found for file", filePath); - } - - return `${title} ${currentTitle}`; -} - -async function generateApiReferenceText(apiName: "cdi" | "fdi") { - const apiReference = apiName === "fdi" ? fdiReference : cdiReference; - const apiReferenceMapping = JSON.parse( - await fs.promises.readFile(`./static/${apiName}-mapping.json`, "utf8"), - ) as OpenAPIV3.Document; - - let text = ``; - for (const route in apiReference.paths) { - for (const method in apiReference.paths[route]) { - const operation = apiReference.paths[route][method]; - const mapping = apiReferenceMapping[operation.operationId]; - if (operation.deprecated) continue; - if (!mapping) continue; - const title = operation.summary || route; - const pathWithoutExtension = mapping.filePath.replace(/\.[^/.]+$/, ""); - const url = `https://supertokens.com/docs/references${pathWithoutExtension}`; - text = `${text}\n\n## ${title}\nSource: ${url}\nEndpoint: ${method.toUpperCase()} ${route}`; - } - } - return text; -} - -export default function createLLMFullFile(context) { - return { - name: "generate-llms-full-txt", - loadContent: async () => { - const { siteDir } = context; - const contentDir = path.join(siteDir, "docs"); - const allFiles: { title: string; content: string; path: string; description: string }[] = []; - - // const skipFiles = [ - // "docs/index.mdx", - // "docs/quickstart/example-apps/generate-example-app.mdx", - // "docs/quickstart/next-steps.mdx", - // "overview.mdx", - // "introduction.mdx", - // "compatibility-table.mdx", - // ]; - - const mainDirectories = [ - "/quickstart", - "/authentication", - "/additional-verification", - "/post-authentication", - "/deployment", - "/migration", - "/platform-configuration", - "/references", - ]; - - for (const dir of mainDirectories) { - const fullPath = path.join(contentDir, dir); - // const mdxFiles = await getAllMdxFiles(fullPath, skipFiles); - const mdxFiles = await getAllMdxFiles(fullPath, []); - allFiles.push(...mdxFiles); - } - - return { files: allFiles }; - }, - postBuild: async ({ content, outDir, routes }) => { - const parsedFiles = await Promise.all( - content.files.map(async (file) => { - let content = ""; - if ((file.path.includes("fdi") || file.path.includes("cdi")) && !file.path.includes("introduction")) { - content = await parseApiReferenceContent(file.path, file.path.includes("fdi") ? "fdi" : "cdi"); - } else { - content = await parseMdxContent(file.path); - } - return { ...file, content }; - }), - ); - let llmsFullTxt = parsedFiles.map((file) => file.content).join("\n\n"); - - const uniqueImports = AllImports.filter( - (item, index, self) => index === self.findIndex((t) => t.module === item.module), - ); - const importsWithoutBlocks = uniqueImports.filter((item) => !item.module.includes("_blocks")); - - const fdiIntro = await parseMdxContent("./docs/references/fdi/introduction.mdx", true); - const cdiIntro = await parseMdxContent("./docs/references/cdi/introduction.mdx", true); - const fdiReferenceFullTxt = await generateApiReferenceText("fdi"); - const cdiReferenceFullTxt = await generateApiReferenceText("cdi"); - - llmsFullTxt = `${llmsFullTxt} -${fdiIntro} -${fdiReferenceFullTxt} -\n\n -${cdiIntro} -${cdiReferenceFullTxt} -`; - - fs.writeFileSync(path.join(outDir, "llms-full.txt"), llmsFullTxt); - - for (const file of parsedFiles) { - const regex = /.*\/docs\/(.+)\.mdx$/; - const match = file.path.match(regex); - const outputPath = path.join(outDir, `md/${match[1]}.md`); - const directoryPath = path.dirname(outputPath); - const normalizedPath = path.normalize(directoryPath); - - fs.mkdirSync(normalizedPath, { recursive: true }); - fs.writeFileSync(outputPath, file.content); - } - }, - }; -} diff --git a/src/plugins/generateLllmsTxt.ts b/src/plugins/generateLllmsTxt.ts deleted file mode 100644 index 5f01235fce..0000000000 --- a/src/plugins/generateLllmsTxt.ts +++ /dev/null @@ -1,167 +0,0 @@ -import fs from "fs"; -import path from "path"; -import matter from "gray-matter"; - -async function getAllMdxFiles(dir: string) { - const allFiles: { title: string; content: string; path: string; description: string }[] = []; - if (dir.includes("_blocks")) return []; - - let orderedItems = []; - - const entries = await fs.promises.readdir(dir, { withFileTypes: true }); - for (const entry of entries) { - const fullPath = path.join(dir, entry.name); - if (fullPath.includes("_blocks")) { - continue; - } - if (entry.isDirectory()) { - const categoryJsonPath = path.join(fullPath, "_category_.json"); - let categoryOrder = 1; - if (fs.existsSync(categoryJsonPath)) { - const categoryJson = JSON.parse(fs.readFileSync(categoryJsonPath, "utf8")); - categoryOrder = categoryJson.position; - } - - orderedItems.push({ directory: true, order: categoryOrder, path: fullPath }); - } - if (entry.name.endsWith(".mdx")) { - const mdxFileContent = await fs.promises.readFile(fullPath, "utf8"); - const { data } = matter(mdxFileContent); - const filePosition = data.sidebar_position || 1; - orderedItems.push({ directory: false, order: filePosition, path: fullPath }); - } - } - - orderedItems.sort((a, b) => a.order - b.order); - - for (const item of orderedItems) { - if (item.directory) { - const mdxFiles = await getAllMdxFiles(item.path); - allFiles.push(...mdxFiles); - } else if (item.path.endsWith(".mdx")) { - const mdxFileContent = await fs.promises.readFile(item.path, "utf8"); - const { data, content } = matter(mdxFileContent); - if (data.skip_llms_txt) continue; - // Skip nextjs until we update the docs - if (item.path.includes("/integrations/nextjs")) continue; - const title = data.llms_txt_title || data.title; - allFiles.push({ title, content, path: item.path, description: data.description }); - } - } - return allFiles; -} - -function buildContent(files: { path: string; description?: string; title: string }[]) { - return files - .map((file) => { - const regex = /.*\/docs\/(.+)\.mdx$/; - const match = file.path.match(regex); - - const src = `https://supertokens.com/docs/${match[1]}.md`; - const parsedDescription = file.description ? `: ${file.description}` : ""; - return `- [${file.title}](${src})${parsedDescription}`; - }) - .join("\n"); -} - -export default function createLLMfiles(context) { - return { - name: "generate-llms-txt", - loadContent: async () => { - const { siteDir } = context; - const contentDir = path.join(siteDir, "docs"); - const allFiles: { title: string; content: string; path: string; description: string }[] = []; - - const mainDirectories = [ - "/quickstart", - "/authentication", - "/additional-verification", - "/post-authentication", - "/deployment", - "/migration", - "/platform-configuration", - "/references", - ]; - - for (const dir of mainDirectories) { - const fullPath = path.join(contentDir, dir); - const mdxFiles = await getAllMdxFiles(fullPath); - allFiles.push(...mdxFiles); - } - - return { files: allFiles }; - }, - postBuild: async ({ content, routes, outDir }) => { - const llmsTxt = ` -# SuperTokens - -## Docs - -### Quickstart -${buildContent(content.files.filter((file) => file.path.includes("/quickstart")))} - -### Email/Password Login -${buildContent(content.files.filter((file) => file.path.includes("/authentication/email-password")))} - -### Passwordless Login -${buildContent(content.files.filter((file) => file.path.includes("/authentication/passwordless")))} - -### Social Login -${buildContent(content.files.filter((file) => file.path.includes("/authentication/social")))} - -### Enterprise Login -${buildContent(content.files.filter((file) => file.path.includes("/authentication/enterprise")))} - -### Unified Login -${buildContent(content.files.filter((file) => file.path.includes("/authentication/unified-login")))} - -### Machine to Machine Authentication -${buildContent(content.files.filter((file) => file.path.includes("/authentication/m2m")))} - -### Passkeys Authentication -${buildContent(content.files.filter((file) => file.path.includes("/authentication/passkeys")))} - -### Multi-factor Authentication -${buildContent(content.files.filter((file) => file.path.includes("/additional-verification/mfa")))} - -### Session Verification -${buildContent(content.files.filter((file) => file.path.includes("/additional-verification/session-verification")))} - -### Email Verification -${buildContent(content.files.filter((file) => file.path.includes("/additional-verification/email-verification")))} - -### Attack Protection Suite -${buildContent(content.files.filter((file) => file.path.includes("/additional-verification/attack-protection-suite")))} - -### User Roles -${buildContent(content.files.filter((file) => file.path.includes("/additional-verification/user-roles")))} - -### Account Linking -${buildContent(content.files.filter((file) => file.path.includes("/post-authentication/account-linking")))} - -### Session Management -${buildContent(content.files.filter((file) => file.path.includes("/post-authentication/session-management")))} - -### User Management -${buildContent(content.files.filter((file) => file.path.includes("/post-authentication/user-management")))} - -### Dashboard -${buildContent(content.files.filter((file) => file.path.includes("/post-authentication/dashboard")))} - -### Migration -${buildContent(content.files.filter((file) => file.path.includes("/migration") && !file.path.includes("/mfa")))} - -### Deploy and configure SuperTokens Core -${buildContent(content.files.filter((file) => file.path.includes("/deployment")))} -${buildContent(content.files.filter((file) => file.path.includes("/platform-configuration")))} - -### References -${buildContent(content.files.filter((file) => file.path.includes("/references") && !file.path.includes("/fdi") && !file.path.includes("/cdi")))} - - -`; - - fs.writeFileSync(path.join(outDir, "llms.txt"), llmsTxt); - }, - }; -} diff --git a/src/plugins/reactBundle.js b/src/plugins/reactBundle.js deleted file mode 100644 index 0da113264a..0000000000 --- a/src/plugins/reactBundle.js +++ /dev/null @@ -1,47 +0,0 @@ -// loads the react JS bundle for supertokens.com for footer and analytics etc.. - -module.exports = function myPlugin(context, options) { - return { - name: "react-bundle", - injectHtmlTags() { - if (process.env.MODE !== "production") { - return {}; - } - console.log("ADDING supertokens.com REACT BUNDLE"); - return { - postBodyTags: [ - { - tagName: "div", - attributes: { - id: "supertokens-root", - }, - }, - { - tagName: "script", - attributes: { - src: "/static/bundle.js", - type: "text/javascript", - }, - }, - { - tagName: "script", - attributes: { - src: "/static/antcs.js", - type: "text/javascript", - }, - }, - ], - headTags: [ - { - tagName: "script", - innerHTML: 'window.intercomSettings = {api_base: "https://api-iam.intercom.io",app_id: "fx5npc7c"};', - }, - { - tagName: "script", - innerHTML: `(function(){var w=window;var ic=w.Intercom;if(typeof ic==="function"){ic('reattach_activator');ic('update',w.intercomSettings);}else{var d=document;var i=function(){i.c(arguments);};i.q=[];i.c=function(args){i.q.push(args);};w.Intercom=i;var l=function(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src='https://widget.intercom.io/widget/fx5npc7c';var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s,x);};if(document.readyState==='complete'){l();}else if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})();`, - }, - ], - }; - }, - }; -}; diff --git a/src/plugins/remarkAddBadgesInHeadings.ts b/src/plugins/remarkAddBadgesInHeadings.ts deleted file mode 100644 index 3a5b08176a..0000000000 --- a/src/plugins/remarkAddBadgesInHeadings.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { visit } from "unist-util-visit"; - -const OptionalBadgeNode = { - type: "mdxJsxFlowElement", - name: "span", - attributes: [ - { - type: "mdxJsxAttribute", - name: "class", - value: "rt-reset rt-Badge rt-r-size-3 rt-variant-soft rt-high-contrast", - }, - { - type: "mdxJsxAttribute", - name: "data-accent-color", - value: "gray", - }, - { - type: "mdxJsxAttribute", - name: "data-radius", - value: "full", - }, - // { - // type: "mdxJsxAttribute", - // name: "style", - // value: { verticalAlign: "middle", marginLeft: "var(--space-1)" }, - // }, - ], - children: [ - { - type: "text", - value: "Optional", - }, - ], - data: { - _mdxExplicitJsx: true, - }, -}; - -/** - * Adds an optional badge to headings that have the {{optional}} property - */ -export default function remarkAddBadgesInHeadings() { - return (tree, file) => { - visit(tree, "heading", (node, index, parent) => { - node.children = node.children.map((child) => { - if (child.type === "mdxTextExpression" && child.value === "{optional}") { - child = OptionalBadgeNode; - } - return child; - }); - }); - }; -} diff --git a/src/plugins/remarkAddPaidFeatureCallout.ts b/src/plugins/remarkAddPaidFeatureCallout.ts deleted file mode 100644 index c0ab8d43d8..0000000000 --- a/src/plugins/remarkAddPaidFeatureCallout.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { visit } from "unist-util-visit"; - -const PaidFeatureBadgeNode = { - type: "mdxJsxFlowElement", - name: "PaidFeatureCallout", - attributes: [], - children: [], - data: { - _mdxExplicitJsx: true, - }, -}; - -/** - * Adds the PaidFeatureCallout component where {{paidFeature}} is used - */ -export default function remarkAddBadgesInHeadings() { - return (tree, file) => { - visit(tree, "mdxTextExpression", (node, index, parent) => { - if (node.value !== "{{paidFeature}}") { - node = PaidFeatureBadgeNode; - } - }); - }; -} diff --git a/src/plugins/remarkDocItemContextValues.ts b/src/plugins/remarkDocItemContextValues.ts deleted file mode 100644 index 628c873a07..0000000000 --- a/src/plugins/remarkDocItemContextValues.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { visit } from "unist-util-visit"; - -/** - * Replaces {props.propName} value - * with - * This way we can render dynamic values that are set in DocItemContext - */ -export default function remarkDocItemContextValues() { - return (tree) => { - visit(tree, "mdxFlowExpression", (node) => { - node.type = "mdxJsxFlowElement"; - node.name = "DocItemContextValue"; - const [, propertyPath] = node.value.split("props."); - const propertyPathWithDotNotation = propertyPath.replaceAll(/_/g, "."); - - node.attributes = [ - { - type: "mdxJsxAttribute", - name: "propertyPath", - value: propertyPathWithDotNotation, - }, - ]; - node.data = { _mdxExplicitJsx: true }; - node.children = []; - }); - }; -} diff --git a/src/plugins/remarkDocItemDescription.ts b/src/plugins/remarkDocItemDescription.ts deleted file mode 100644 index 4e1c9cf2c4..0000000000 --- a/src/plugins/remarkDocItemDescription.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { visit } from "unist-util-visit"; - -/** - * Renders the frontmatter description as a subtitle - */ -export default function remarkDocItemDescription() { - return (tree, file) => { - const renderDescription = file.data.frontMatter.renderDescription; - if (renderDescription === false) return; - const description = file.data.frontMatter.description; - if (!description) return; - const filePath = file.history[0]; - // TODO: Remove this after we go through all the docs - const validPaths = [ - "authentication/email-password", - "authentication/passwordless", - "authentication/social", - "authentication/enterprise", - ]; - if (!validPaths.some((path) => filePath.includes(path))) return; - visit(tree, "mdxJsxFlowElement", (node, index, parent) => { - if (node.name !== "header") return; - const descriptionNode = { - type: "mdxJsxFlowElement", - name: "p", - attributes: [ - // { - // type: "mdxJsxAttribute", - // name: "data-accent-color", - // value: "gray", - // }, - { - type: "mdxJsxAttribute", - name: "class", - value: "rt-Text rt-r-size-5 page-subtitle", - }, - ], - children: [ - { - type: "paragraph", - children: [ - { - type: "text", - value: description, - }, - ], - }, - ], - data: { - _mdxExplicitJsx: true, - }, - }; - - const separatorNode = { - type: "mdxJsxFlowElement", - name: "span", - attributes: [ - { - type: "mdxJsxAttribute", - name: "data-accent-color", - value: "gray", - }, - { - type: "mdxJsxAttribute", - name: "class", - value: "rt-Separator rt-r-orientation-horizontal rt-r-size-4 rt-r-mt-2 rt-r-mb-6", - }, - ], - children: [], - data: { - _mdxExplicitJsx: true, - }, - }; - - node.children.push(descriptionNode, separatorNode); - }); - }; -} diff --git a/src/plugins/remarkRemoveCodeTypeCheckingCommentsAndRows.ts b/src/plugins/remarkRemoveCodeTypeCheckingCommentsAndRows.ts deleted file mode 100644 index 0d1a2f12f1..0000000000 --- a/src/plugins/remarkRemoveCodeTypeCheckingCommentsAndRows.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { visit } from "unist-util-visit"; - -/** - * Removes additional rows that are used only for code type checking - * Things like: # type: ignore - * - */ -export default function remarkRemoveCodeTypeCheckingCommentsAndRows() { - return (tree) => { - visit(tree, "code", (node) => { - const lines = node.value.split("\n"); - const filteredLines = lines.filter((line) => { - return ( - !line.includes("REMOVE_FROM_OUTPUT") && - !line.includes("@ts-expect-error") && - !line.includes("@ts-nocheck") && - !line.includes("@ts-ignore") && - !line.includes("// typecheck-only") - ); - }); - const parsedLines = filteredLines.map((line) => { - return line.replaceAll("# type: ignore", ""); - }); - - node.value = parsedLines.join("\n"); - }); - }; -} diff --git a/src/plugins/remarkRemoveWebJsScriptImports.ts b/src/plugins/remarkRemoveWebJsScriptImports.ts deleted file mode 100644 index 65a55bdf66..0000000000 --- a/src/plugins/remarkRemoveWebJsScriptImports.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { visit } from "unist-util-visit"; - -/** - * Removes *-web-js-script and *-auth-react-script imports from ts files - * Also adds window.* to specific lines in Angular and Vue code samples - * - * For code snippets that use our JS SDK from scripts - * we add custom imports in the docs CodeBlocks. - * This is done to prevent errors in the code type checking process. - */ -export default function remarkRemoveWebJsScriptImports() { - return (tree) => { - visit(tree, "code", (node) => { - const targetedLanguages = ["tsx", "ts", "typescript"]; - if (!targetedLanguages.includes(node.lang)) return; - - const lines = node.value.split("\n"); - let filteredLines = lines.filter((line) => { - return !line.includes("supertokens-web-js-script") && !line.includes("supertokens-auth-react-script"); - }); - - const mappedLines = filteredLines.map((line: string) => { - const supertokensUIRegex = - /^(\s*)(supertokensUI(?:Init|ThirdParty|EmailPassword|Passwordless|OAuth2Provider|Session).*)/; - const match = line.match(supertokensUIRegex); - if (match) { - const [, spaces, content] = match; - return `${spaces}(window as any).${content}`; - } - - return line; - }); - - node.value = mappedLines.join("\n"); - }); - }; -} diff --git a/src/plugins/transformOpenSearchLink.js b/src/plugins/transformOpenSearchLink.js deleted file mode 100644 index 3a077577fa..0000000000 --- a/src/plugins/transformOpenSearchLink.js +++ /dev/null @@ -1,55 +0,0 @@ -const path = require("path"); -const fs = require("fs"); - -module.exports = () => { - async function readHTML(filePath) { - return new Promise((resolve, reject) => { - try { - fs.readFile(filePath, "utf8", (err, data) => { - if (err) { - return reject(err); - } - return resolve(data); - }); - } catch (err) { - reject(err); - } - }); - } - - async function writeToHTML(filePath, modifiedContent) { - return new Promise((resolve, reject) => { - try { - fs.writeFile(filePath, modifiedContent, "utf8", (err) => { - if (err) { - return reject(err); - } else { - return resolve(); - } - }); - } catch (error) { - rej(error); - } - }); - } - return { - name: "transform-opensearch-link", - async postBuild({ routesPaths, outDir }) { - for (let i = 0; i < routesPaths.length; i++) { - const route = routesPaths[i]; - if (route === "/") { - continue; - } - const trailingExtention = route.endsWith(".html") ? "" : ".html"; - try { - const filePath = path.join(outDir + route + trailingExtention); - const htmlString = await readHTML(filePath); - const modifiedContent = htmlString.replace(/opensearch.xml/g, "docs/opensearch.xml"); - await writeToHTML(filePath, modifiedContent); - } catch (error) { - console.log(error); - } - } - }, - }; -}; diff --git a/src/plugins/utils/getAllMdxFiles.ts b/src/plugins/utils/getAllMdxFiles.ts deleted file mode 100644 index f83b4bd5db..0000000000 --- a/src/plugins/utils/getAllMdxFiles.ts +++ /dev/null @@ -1,55 +0,0 @@ -import fs from "fs"; -import path from "path"; -import matter from "gray-matter"; - -export async function getAllMdxFiles(dir: string, skipFiles: string[]) { - const allFiles: { title: string; content: string; path: string; description: string }[] = []; - if (dir.includes("_blocks")) return []; - - let orderedItems = []; - - const entries = await fs.promises.readdir(dir, { withFileTypes: true }); - for (const entry of entries) { - const fullPath = path.join(dir, entry.name); - if (fullPath.includes("_blocks")) { - continue; - } - if (skipFiles.some((pathToSkip) => fullPath.includes(pathToSkip))) { - continue; - } - if (entry.isDirectory()) { - const categoryJsonPath = path.join(fullPath, "_category_.json"); - let categoryOrder = 1; - if (fs.existsSync(categoryJsonPath)) { - const categoryJson = JSON.parse(fs.readFileSync(categoryJsonPath, "utf8")); - categoryOrder = categoryJson.position; - } - - orderedItems.push({ directory: true, order: categoryOrder, path: fullPath }); - } - if (entry.name.endsWith(".mdx")) { - const mdxFileContent = await fs.promises.readFile(fullPath, "utf8"); - const { data } = matter(mdxFileContent); - const filePosition = data.sidebar_position || 1; - orderedItems.push({ directory: false, order: filePosition, path: fullPath }); - } - } - - orderedItems.sort((a, b) => a.order - b.order); - - for (const item of orderedItems) { - if (item.directory) { - const mdxFiles = await getAllMdxFiles(item.path, skipFiles); - allFiles.push(...mdxFiles); - } else if (item.path.endsWith(".mdx")) { - const mdxFileContent = await fs.promises.readFile(item.path, "utf8"); - const { data, content } = matter(mdxFileContent); - if (data.skip_llms_txt) continue; - // Skip nextjs until we update the docs - if (item.path.includes("/integrations/nextjs")) continue; - const title = data.llms_txt_title || data.title; - allFiles.push({ title, content, path: item.path, description: data.description }); - } - } - return allFiles; -} diff --git a/src/theme/Admonition/Icon/Danger.tsx b/src/theme/Admonition/Icon/Danger.tsx deleted file mode 100644 index 11b1751c0b..0000000000 --- a/src/theme/Admonition/Icon/Danger.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react"; -import type { Props } from "@theme/Admonition/Icon/Danger"; - -export default function AdmonitionIconDanger(props: Props): JSX.Element { - return ( - - - - ); -} diff --git a/src/theme/Admonition/Icon/Info.tsx b/src/theme/Admonition/Icon/Info.tsx deleted file mode 100644 index db69baa3c8..0000000000 --- a/src/theme/Admonition/Icon/Info.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react"; -import type { Props } from "@theme/Admonition/Icon/Info"; - -export default function AdmonitionIconInfo(props: Props): JSX.Element { - return ( - - - - ); -} diff --git a/src/theme/Admonition/Icon/Note.tsx b/src/theme/Admonition/Icon/Note.tsx deleted file mode 100644 index 549464b94b..0000000000 --- a/src/theme/Admonition/Icon/Note.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react"; -import type { Props } from "@theme/Admonition/Icon/Note"; - -export default function AdmonitionIconNote(props: Props): JSX.Element { - return ( - - - - ); -} diff --git a/src/theme/Admonition/Icon/Tip.tsx b/src/theme/Admonition/Icon/Tip.tsx deleted file mode 100644 index 7b1b63d8d9..0000000000 --- a/src/theme/Admonition/Icon/Tip.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react"; -import type { Props } from "@theme/Admonition/Icon/Tip"; - -export default function AdmonitionIconTip(props: Props): JSX.Element { - return ( - - - - ); -} diff --git a/src/theme/Admonition/Icon/Warning.tsx b/src/theme/Admonition/Icon/Warning.tsx deleted file mode 100644 index 8f6069653f..0000000000 --- a/src/theme/Admonition/Icon/Warning.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react"; -import type { Props } from "@theme/Admonition/Icon/Warning"; - -export default function AdmonitionIconCaution(props: Props): JSX.Element { - return ( - - - - ); -} diff --git a/src/theme/Admonition/Layout/index.tsx b/src/theme/Admonition/Layout/index.tsx deleted file mode 100644 index bafaab5294..0000000000 --- a/src/theme/Admonition/Layout/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React, { type ReactNode } from "react"; -import clsx from "clsx"; -import { ThemeClassNames } from "@docusaurus/theme-common"; - -import type { Props } from "@theme/Admonition/Layout"; - -import styles from "./styles.module.css"; - -function AdmonitionContainer({ - type, - className, - children, -}: Pick & { children: ReactNode }) { - return ( -
    - {children} -
    - ); -} - -function AdmonitionHeading({ icon, title }: Pick) { - return ( -
    - {icon} - {title} -
    - ); -} - -function AdmonitionContent({ children }: Pick) { - return children ?
    {children}
    : null; -} - -export default function AdmonitionLayout(props: Props): JSX.Element { - const { type, icon, title, children, className } = props; - return ( - - {title || icon ? : null} - {children} - - ); -} diff --git a/src/theme/Admonition/Layout/styles.module.css b/src/theme/Admonition/Layout/styles.module.css deleted file mode 100644 index a9c98a03de..0000000000 --- a/src/theme/Admonition/Layout/styles.module.css +++ /dev/null @@ -1,35 +0,0 @@ -.admonition { - margin-bottom: 1em; -} - -.admonitionHeading { - font: var(--ifm-heading-font-weight) var(--ifm-h5-font-size) / var(--ifm-heading-line-height) - var(--ifm-heading-font-family); - text-transform: uppercase; -} - -/* Heading alone without content (does not handle fragment content) */ -.admonitionHeading:not(:last-child) { - margin-bottom: 0.3rem; -} - -.admonitionHeading code { - text-transform: none; -} - -.admonitionIcon { - display: inline-block; - vertical-align: middle; - margin-right: 0.4em; -} - -.admonitionIcon svg { - display: inline-block; - height: 1.6em; - width: 1.6em; - fill: var(--ifm-alert-foreground-color); -} - -.admonitionContent > :last-child { - margin-bottom: 0; -} diff --git a/src/theme/Admonition/Type/Caution.tsx b/src/theme/Admonition/Type/Caution.tsx deleted file mode 100644 index 8e5028199a..0000000000 --- a/src/theme/Admonition/Type/Caution.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import Translate from "@docusaurus/Translate"; -import type { Props } from "@theme/Admonition/Type/Caution"; -import AdmonitionLayout from "@theme/Admonition/Layout"; -import IconWarning from "@theme/Admonition/Icon/Warning"; - -const infimaClassName = "alert alert--warning"; - -const defaultProps = { - icon: , - title: ( - - caution - - ), -}; - -// TODO remove before v4: Caution replaced by Warning -// see https://github.com/facebook/docusaurus/issues/7558 -export default function AdmonitionTypeCaution(props: Props): JSX.Element { - return ( - - {props.children} - - ); -} diff --git a/src/theme/Admonition/Type/Danger.tsx b/src/theme/Admonition/Type/Danger.tsx deleted file mode 100644 index abec2fe5aa..0000000000 --- a/src/theme/Admonition/Type/Danger.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import Translate from "@docusaurus/Translate"; -import type { Props } from "@theme/Admonition/Type/Danger"; -import AdmonitionLayout from "@theme/Admonition/Layout"; -import IconDanger from "@theme/Admonition/Icon/Danger"; - -const infimaClassName = "alert alert--danger"; - -const defaultProps = { - icon: , - title: ( - - danger - - ), -}; - -export default function AdmonitionTypeDanger(props: Props): JSX.Element { - return ( - - {props.children} - - ); -} diff --git a/src/theme/Admonition/Type/Info.tsx b/src/theme/Admonition/Type/Info.tsx deleted file mode 100644 index 2112fc3366..0000000000 --- a/src/theme/Admonition/Type/Info.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import Translate from "@docusaurus/Translate"; -import type { Props } from "@theme/Admonition/Type/Info"; -import AdmonitionLayout from "@theme/Admonition/Layout"; -import IconInfo from "@theme/Admonition/Icon/Info"; - -const infimaClassName = "alert alert--info"; - -const defaultProps = { - icon: , - title: ( - - info - - ), -}; - -export default function AdmonitionTypeInfo(props: Props): JSX.Element { - return ( - - {props.children} - - ); -} diff --git a/src/theme/Admonition/Type/Note.tsx b/src/theme/Admonition/Type/Note.tsx deleted file mode 100644 index d5a006979d..0000000000 --- a/src/theme/Admonition/Type/Note.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import Translate from "@docusaurus/Translate"; -import type { Props } from "@theme/Admonition/Type/Note"; -import AdmonitionLayout from "@theme/Admonition/Layout"; -import IconNote from "@theme/Admonition/Icon/Note"; - -const infimaClassName = "alert alert--secondary"; - -const defaultProps = { - icon: , - title: ( - - note - - ), -}; - -export default function AdmonitionTypeNote(props: Props): JSX.Element { - return ( - - {props.children} - - ); -} diff --git a/src/theme/Admonition/Type/Tip.tsx b/src/theme/Admonition/Type/Tip.tsx deleted file mode 100644 index 0fad1035c4..0000000000 --- a/src/theme/Admonition/Type/Tip.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import Translate from "@docusaurus/Translate"; -import type { Props } from "@theme/Admonition/Type/Tip"; -import AdmonitionLayout from "@theme/Admonition/Layout"; -import IconTip from "@theme/Admonition/Icon/Tip"; - -const infimaClassName = "alert alert--success"; - -const defaultProps = { - icon: , - title: ( - - tip - - ), -}; - -export default function AdmonitionTypeTip(props: Props): JSX.Element { - return ( - - {props.children} - - ); -} diff --git a/src/theme/Admonition/Type/Warning.tsx b/src/theme/Admonition/Type/Warning.tsx deleted file mode 100644 index d2daf82dc7..0000000000 --- a/src/theme/Admonition/Type/Warning.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import Translate from "@docusaurus/Translate"; -import type { Props } from "@theme/Admonition/Type/Warning"; -import AdmonitionLayout from "@theme/Admonition/Layout"; -import IconWarning from "@theme/Admonition/Icon/Warning"; - -const infimaClassName = "alert alert--warning"; - -const defaultProps = { - icon: , - title: ( - - warning - - ), -}; - -export default function AdmonitionTypeWarning(props: Props): JSX.Element { - return ( - - {props.children} - - ); -} diff --git a/src/theme/Admonition/Types.tsx b/src/theme/Admonition/Types.tsx deleted file mode 100644 index 04bc701bc3..0000000000 --- a/src/theme/Admonition/Types.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from "react"; -import AdmonitionTypeNote from "@theme/Admonition/Type/Note"; -import AdmonitionTypeTip from "@theme/Admonition/Type/Tip"; -import AdmonitionTypeInfo from "@theme/Admonition/Type/Info"; -import AdmonitionTypeWarning from "@theme/Admonition/Type/Warning"; -import AdmonitionTypeDanger from "@theme/Admonition/Type/Danger"; -import AdmonitionTypeCaution from "@theme/Admonition/Type/Caution"; -import type AdmonitionTypes from "@theme/Admonition/Types"; - -const admonitionTypes: typeof AdmonitionTypes = { - note: AdmonitionTypeNote, - tip: AdmonitionTypeTip, - info: AdmonitionTypeInfo, - warning: AdmonitionTypeWarning, - danger: AdmonitionTypeDanger, -}; - -// Undocumented legacy admonition type aliases -// Provide hardcoded/untranslated retrocompatible label -// See also https://github.com/facebook/docusaurus/issues/7767 -const admonitionAliases: typeof AdmonitionTypes = { - secondary: (props) => , - important: (props) => , - success: (props) => , - caution: AdmonitionTypeCaution, -}; - -export default { - ...admonitionTypes, - ...admonitionAliases, -}; diff --git a/src/theme/Admonition/admonition.scss b/src/theme/Admonition/admonition.scss deleted file mode 100644 index 7705c0349d..0000000000 --- a/src/theme/Admonition/admonition.scss +++ /dev/null @@ -1,25 +0,0 @@ -.admonition { - margin-bottom: var(--space-5); - overflow-wrap: break-word; - word-wrap: break-word; - overflow-y: auto; - - &__content { - overflow-y: auto; - font-size: var(--font-size-2); - line-height: var(--line-height-2); - letter-spacing: var(--letter-spacing-2); - text-align: left; - color: var(--accent-a11); - - & > *:last-child { - margin-bottom: 0; - } - - ul li { - &:before { - margin-top: -3px !important; - } - } - } -} diff --git a/src/theme/Admonition/index.tsx b/src/theme/Admonition/index.tsx deleted file mode 100644 index c656689308..0000000000 --- a/src/theme/Admonition/index.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React, { type ComponentType } from "react"; -import { processAdmonitionProps } from "@docusaurus/theme-common"; -import type { Props } from "@theme/Admonition"; -import AdmonitionTypes from "@theme/Admonition/Types"; - -import ExclamationTriangleIcon from "/img/icons/exclamation-triangle.svg"; -import InfoCircledIcon from "/img/icons/info-circled.svg"; -import { Callout, Flex } from "@radix-ui/themes"; - -import "./admonition.scss"; -type AdmonitionType = "info" | "note" | "tip" | "caution" | "danger" | "warning"; - -const AdmonitionTypeToIconRecord: Record>> = { - info: InfoCircledIcon, - note: InfoCircledIcon, - tip: InfoCircledIcon, - caution: ExclamationTriangleIcon, - danger: ExclamationTriangleIcon, - warning: ExclamationTriangleIcon, -}; - -type CalloutColor = React.ComponentProps["color"]; - -const AdmonitionTypeToColorRecord: Record = { - info: "blue", - note: "gray", - tip: "green", - caution: "yellow", - danger: "red", - warning: "yellow", -}; - -export default function Admonition(unprocessedProps: Props): JSX.Element { - const props = processAdmonitionProps(unprocessedProps); - let { type, title, children } = props; - let color = AdmonitionTypeToColorRecord[type]; - let Icon = AdmonitionTypeToIconRecord[type]; - - if (!Icon) { - Icon = AdmonitionTypeToIconRecord.info; - } - - if (!color) { - color = "blue"; - } - - if (!title) { - title = type; - } - - if (title === "no-title") { - return ( - - - - -
    {children}
    -
    - ); - } - - return ( - - - - - - {title} - -
    {children}
    -
    - ); -} diff --git a/src/theme/CodeBlock/Container/index.tsx b/src/theme/CodeBlock/Container/index.tsx deleted file mode 100644 index 4774d4fad9..0000000000 --- a/src/theme/CodeBlock/Container/index.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React, { type ComponentProps } from "react"; -import clsx from "clsx"; -import { ThemeClassNames, usePrismTheme } from "@docusaurus/theme-common"; -import { getPrismCssVariables } from "@docusaurus/theme-common/internal"; -import styles from "./styles.module.css"; - -export default function CodeBlockContainer({ - as: As, - ...props -}: { as: T } & ComponentProps): JSX.Element { - const prismTheme = usePrismTheme(); - const prismCssVariables = getPrismCssVariables(prismTheme); - return ( - - ); -} diff --git a/src/theme/CodeBlock/Container/styles.module.css b/src/theme/CodeBlock/Container/styles.module.css deleted file mode 100644 index d6836487c5..0000000000 --- a/src/theme/CodeBlock/Container/styles.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.codeBlockContainer { - background: var(--prism-background-color); - color: var(--prism-color); - margin-bottom: var(--ifm-leading); - box-shadow: inset 0 -1px 0 0 var(--gray-a5); - border-top: 1px solid var(--gray-5); - border-left: 1px solid var(--gray-5); - border-right: 1px solid var(--gray-5); - border-bottom: 1px solid var(--gray-5); - border-radius: var(--radius-4); -} diff --git a/src/theme/CodeBlock/Content/Element.tsx b/src/theme/CodeBlock/Content/Element.tsx deleted file mode 100644 index bcdb3d26bc..0000000000 --- a/src/theme/CodeBlock/Content/Element.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import Container from "@theme/CodeBlock/Container"; -import type { Props } from "@theme/CodeBlock/Content/Element"; - -import styles from "./styles.module.css"; - -//
     tags in markdown map to CodeBlocks. They may contain JSX children. When
    -// the children is not a simple string, we just return a styled block without
    -// actually highlighting.
    -export default function CodeBlockJSX({ children, className }: Props): JSX.Element {
    -  return (
    -    
    -      {children}
    -    
    -  );
    -}
    diff --git a/src/theme/CodeBlock/Content/String.tsx b/src/theme/CodeBlock/Content/String.tsx
    deleted file mode 100644
    index 19a672e4e4..0000000000
    --- a/src/theme/CodeBlock/Content/String.tsx
    +++ /dev/null
    @@ -1,174 +0,0 @@
    -import React, { useContext, useReducer } from "react";
    -import clsx from "clsx";
    -import { useThemeConfig, usePrismTheme } from "@docusaurus/theme-common";
    -import {
    -  parseCodeBlockTitle,
    -  parseLanguage,
    -  parseLines,
    -  containsLineNumbers,
    -  useCodeWordWrap,
    -} from "@docusaurus/theme-common/internal";
    -import { Highlight, type Language } from "prism-react-renderer";
    -
    -import EyeIcon from "/img/icons/eye.svg";
    -import CodeIcon from "/img/icons/code.svg";
    -import Line from "@theme/CodeBlock/Line";
    -import CopyButton from "@theme/CodeBlock/CopyButton";
    -import WordWrapButton from "@theme/CodeBlock/WordWrapButton";
    -import Container from "@theme/CodeBlock/Container";
    -import type { Props } from "@theme/CodeBlock/Content/String";
    -
    -import { AppTypeSelect } from "@site/src/components/Select/AppTypeSelect";
    -
    -import { Box, Button, Flex, SegmentedControl } from "@radix-ui/themes";
    -
    -import styles from "./styles.module.css";
    -
    -// Prism languages are always lowercase
    -// We want to fail-safe and allow both "php" and "PHP"
    -// See https://github.com/facebook/docusaurus/issues/9012
    -function normalizeLanguage(language: string | undefined): string | undefined {
    -  return language?.toLowerCase();
    -}
    -
    -type CodeBlockContextType = {
    -  metastring: string;
    -  showPreview: boolean;
    -  toggleShowPreview: () => boolean;
    -};
    -
    -const CodeBlockContext = React.createContext({} as CodeBlockContextType);
    -
    -export default function CodeBlockString({
    -  children,
    -  className: blockClassName = "",
    -  metastring,
    -  title: titleProp,
    -  showLineNumbers: showLineNumbersProp,
    -  language: languageProp,
    -}: Props): JSX.Element {
    -  const {
    -    prism: { defaultLanguage, magicComments },
    -  } = useThemeConfig();
    -  const [showPreview, toggleShowPreview] = useReducer((state) => !state, false);
    -  const language = normalizeLanguage(languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage);
    -
    -  const prismTheme = usePrismTheme();
    -  const wordWrap = useCodeWordWrap();
    -
    -  const showAppTypeSelect = metastring?.includes("showAppTypeSelect") || false;
    -
    -  // We still parse the metastring in case we want to support more syntax in the
    -  // future. Note that MDX doesn't strip quotes when parsing metastring:
    -  // "title=\"xyz\"" => title: "\"xyz\""
    -  const title = parseCodeBlockTitle(metastring) || titleProp;
    -  const previewImage = parseCodeBlockPreview(metastring);
    -
    -  const { lineClassNames, code } = parseLines(children, {
    -    metastring,
    -    language,
    -    magicComments,
    -  });
    -  const showLineNumbers = showLineNumbersProp ?? containsLineNumbers(metastring);
    -
    -  return (
    -    
    -      
    -        
    -        
    - {!showPreview ? ( - <> - - {({ className, style, tokens, getLineProps, getTokenProps }) => ( -
    -                    
    -                      {tokens.map((line, i) => (
    -                        
    -                      ))}
    -                    
    -                  
    - )} -
    -
    - {(wordWrap.isEnabled || wordWrap.isCodeScrollable) && ( - wordWrap.toggle()} - isEnabled={wordWrap.isEnabled} - /> - )} - -
    - - ) : ( -
    - -
    - )} -
    -
    -
    - ); -} - -function CodeBlockHeader() { - const { metastring, toggleShowPreview } = useContext(CodeBlockContext); - - const showAppTypeSelect = metastring?.includes("showAppTypeSelect") || false; - const title = parseCodeBlockTitle(metastring); - const previewImage = parseCodeBlockPreview(metastring); - - const showHeader = title || showAppTypeSelect || previewImage; - if (!showHeader) return null; - - return ( -
    - {title} - - {showAppTypeSelect ? : null} - {previewImage ? ( - - - - Code - - - - - - Preview - - - - ) : null} - -
    - ); -} - -const codeBlockPreviewRegex = /preview=(?["'])(?.*?)\1/; - -export function parseCodeBlockPreview(metastring?: string): string { - return metastring?.match(codeBlockPreviewRegex)?.groups!.preview ?? ""; -} diff --git a/src/theme/CodeBlock/Content/styles.module.css b/src/theme/CodeBlock/Content/styles.module.css deleted file mode 100644 index 478202a3fc..0000000000 --- a/src/theme/CodeBlock/Content/styles.module.css +++ /dev/null @@ -1,92 +0,0 @@ -.codeBlockContent { - position: relative; - /* rtl:ignore */ - direction: ltr; - border-radius: inherit; -} - -.codeBlockTitle { - display: flex; - flex-direction: row; - align-items: center; - color: var(--gray-11); - border-bottom: 1px solid var(--gray-5); - font-size: var(--ifm-code-font-size); - padding: var(--space-2) var(--space-3); - border-top-left-radius: inherit; - border-top-right-radius: inherit; -} - -.codeBlock { - --ifm-pre-background: var(--prism-background-color); - margin: 0; - padding: 0; -} - -.codeBlockImageContainer { - display: flex; - justify-content: center; - padding: var(--space-5); - img { - border-radius: calc(var(--radius-4) - 3px); - } -} - -.codeBlockTitle + .codeBlockContent .codeBlock { - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -.codeBlockStandalone { - padding: 0; -} - -.codeBlockLines { - font: inherit; - /* rtl:ignore */ - float: left; - min-width: 100%; - padding: var(--ifm-pre-padding); -} - -.codeBlockLinesWithNumbering { - display: table; - padding: var(--ifm-pre-padding) 0; -} - -@media print { - .codeBlockLines { - white-space: pre-wrap; - } -} - -.buttonGroup { - display: flex; - column-gap: 0.2rem; - position: absolute; - /* rtl:ignore */ - right: calc(var(--ifm-pre-padding) / 2); - top: calc(var(--ifm-pre-padding) / 2); -} - -.buttonGroup button { - display: flex; - align-items: center; - background: var(--prism-background-color); - color: var(--prism-color); - border: 1px solid var(--ifm-color-emphasis-300); - border-radius: var(--ifm-global-radius); - padding: 0.4rem; - line-height: 0; - transition: opacity var(--ifm-transition-fast) ease-in-out; - opacity: 0; -} - -.buttonGroup button:focus-visible, -.buttonGroup button:hover { - opacity: 1 !important; -} - -:global(.theme-code-block:hover) .buttonGroup button { - opacity: 0.4; -} diff --git a/src/theme/CodeBlock/CopyButton/index.tsx b/src/theme/CodeBlock/CopyButton/index.tsx deleted file mode 100644 index 45bde9644c..0000000000 --- a/src/theme/CodeBlock/CopyButton/index.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React, { useCallback, useState, useRef, useEffect } from "react"; -import clsx from "clsx"; -import copy from "copy-text-to-clipboard"; -import { translate } from "@docusaurus/Translate"; -import type { Props } from "@theme/CodeBlock/CopyButton"; -import IconCopy from "@theme/Icon/Copy"; -import IconSuccess from "@theme/Icon/Success"; - -import styles from "./styles.module.css"; - -export default function CopyButton({ code, className }: Props): JSX.Element { - const [isCopied, setIsCopied] = useState(false); - const copyTimeout = useRef(undefined); - const handleCopyCode = useCallback(() => { - copy(code); - setIsCopied(true); - copyTimeout.current = window.setTimeout(() => { - setIsCopied(false); - }, 1000); - }, [code]); - - useEffect(() => () => window.clearTimeout(copyTimeout.current), []); - - return ( - - ); -} diff --git a/src/theme/CodeBlock/CopyButton/styles.module.css b/src/theme/CodeBlock/CopyButton/styles.module.css deleted file mode 100644 index d5268e900b..0000000000 --- a/src/theme/CodeBlock/CopyButton/styles.module.css +++ /dev/null @@ -1,40 +0,0 @@ -:global(.theme-code-block:hover) .copyButtonCopied { - opacity: 1 !important; -} - -.copyButtonIcons { - position: relative; - width: 1.125rem; - height: 1.125rem; -} - -.copyButtonIcon, -.copyButtonSuccessIcon { - position: absolute; - top: 0; - left: 0; - fill: currentColor; - opacity: inherit; - width: inherit; - height: inherit; - transition: all var(--ifm-transition-fast) ease; -} - -.copyButtonSuccessIcon { - top: 50%; - left: 50%; - transform: translate(-50%, -50%) scale(0.33); - opacity: 0; - color: #00d600; -} - -.copyButtonCopied .copyButtonIcon { - transform: scale(0.33); - opacity: 0; -} - -.copyButtonCopied .copyButtonSuccessIcon { - transform: translate(-50%, -50%) scale(1); - opacity: 1; - transition-delay: 0.075s; -} diff --git a/src/theme/CodeBlock/Line/index.tsx b/src/theme/CodeBlock/Line/index.tsx deleted file mode 100644 index cbc19e62f2..0000000000 --- a/src/theme/CodeBlock/Line/index.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import type { Props } from "@theme/CodeBlock/Line"; - -import styles from "./styles.module.css"; - -export default function CodeBlockLine({ - line, - classNames, - showLineNumbers, - getLineProps, - getTokenProps, -}: Props): JSX.Element { - if (line.length === 1 && line[0]!.content === "\n") { - line[0]!.content = ""; - } - - const lineProps = getLineProps({ - line, - className: clsx(classNames, showLineNumbers && styles.codeLine), - }); - - const lineTokens = line.map((token, key) => ); - - return ( - - {showLineNumbers ? ( - <> - - {lineTokens} - - ) : ( - lineTokens - )} -
    -
    - ); -} diff --git a/src/theme/CodeBlock/Line/styles.module.css b/src/theme/CodeBlock/Line/styles.module.css deleted file mode 100644 index be667eddc9..0000000000 --- a/src/theme/CodeBlock/Line/styles.module.css +++ /dev/null @@ -1,49 +0,0 @@ -/* Intentionally has zero specificity, so that to be able to override -the background in custom CSS file due bug https://github.com/facebook/docusaurus/issues/3678 */ -:where(:root) { - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); -} - -:where([data-theme="light"]) { - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); -} - -:where([data-theme="dark"]) { - --docusaurus-highlighted-code-line-bg: rgb(100 100 100); -} - -:global(.theme-code-block-highlighted-line) { - background-color: var(--docusaurus-highlighted-code-line-bg); - display: block; - margin: 0 calc(-1 * var(--ifm-pre-padding)); - padding: 0 var(--ifm-pre-padding); -} - -.codeLine { - display: table-row; - counter-increment: line-count; -} - -.codeLineNumber { - display: table-cell; - text-align: right; - width: 1%; - position: sticky; - left: 0; - padding: 0 var(--ifm-pre-padding); - background: var(--ifm-pre-background); - overflow-wrap: normal; -} - -.codeLineNumber::before { - content: counter(line-count); - opacity: 0.4; -} - -:global(.theme-code-block-highlighted-line) .codeLineNumber::before { - opacity: 0.8; -} - -.codeLineContent { - padding-right: var(--ifm-pre-padding); -} diff --git a/src/theme/CodeBlock/WordWrapButton/index.tsx b/src/theme/CodeBlock/WordWrapButton/index.tsx deleted file mode 100644 index 2a55cfd0b9..0000000000 --- a/src/theme/CodeBlock/WordWrapButton/index.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import { translate } from "@docusaurus/Translate"; -import type { Props } from "@theme/CodeBlock/WordWrapButton"; -import IconWordWrap from "@theme/Icon/WordWrap"; - -import styles from "./styles.module.css"; - -export default function WordWrapButton({ className, onClick, isEnabled }: Props): JSX.Element | null { - const title = translate({ - id: "theme.CodeBlock.wordWrapToggle", - message: "Toggle word wrap", - description: "The title attribute for toggle word wrapping button of code block lines", - }); - - return ( - - ); -} diff --git a/src/theme/CodeBlock/WordWrapButton/styles.module.css b/src/theme/CodeBlock/WordWrapButton/styles.module.css deleted file mode 100644 index fdbc894646..0000000000 --- a/src/theme/CodeBlock/WordWrapButton/styles.module.css +++ /dev/null @@ -1,8 +0,0 @@ -.wordWrapButtonIcon { - width: 1.2rem; - height: 1.2rem; -} - -.wordWrapButtonEnabled .wordWrapButtonIcon { - color: var(--ifm-color-primary); -} diff --git a/src/theme/CodeBlock/index.tsx b/src/theme/CodeBlock/index.tsx deleted file mode 100644 index 0a34036ea4..0000000000 --- a/src/theme/CodeBlock/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React, { isValidElement, useContext, type ReactNode } from "react"; -import useIsBrowser from "@docusaurus/useIsBrowser"; -import ElementContent from "@theme/CodeBlock/Content/Element"; -import StringContent from "@theme/CodeBlock/Content/String"; -import type { Props } from "@theme/CodeBlock"; -import { DocItemContext, getContextValue } from "@site/src/context"; -import { DOC_STORE_DEFAULT_VALUES } from "@site/src/lib/constants"; - -/** - * Best attempt to make the children a plain string so it is copyable. If there - * are react elements, we will not be able to copy the content, and it will - * return `children` as-is; otherwise, it concatenates the string children - * together. - */ -function maybeStringifyChildren(children: ReactNode): ReactNode { - if (React.Children.toArray(children).some((el) => isValidElement(el))) { - return children; - } - // The children is now guaranteed to be one/more plain strings - return Array.isArray(children) ? children.join("") : (children as string); -} - -// TODO: Limit this to only string code blocks -// This way we prevent using
     tags and just handle ``` blocks
    -export default function CodeBlock({ children: rawChildren, ...props }: Props): JSX.Element {
    -  // The Prism theme on SSR is always the default theme but the site theme can
    -  // be in a different mode. React hydration doesn't update DOM styles that come
    -  // from SSR. Hence force a re-render after mounting to apply the current
    -  // relevant styles.
    -  const isBrowser = useIsBrowser();
    -  const children = maybeStringifyChildren(rawChildren);
    -  const CodeBlockComp = typeof children === "string" ? StringContent : ElementContent;
    -  const context = useContext(DocItemContext);
    -  const dynamicValuesRegex = /\^\{([^}]+)\}/g;
    -
    -  let parsedChildren = children;
    -  if (typeof children === "string") {
    -    parsedChildren = children.replaceAll(dynamicValuesRegex, (match, key) => {
    -      const value = getContextValue(context, key, DOC_STORE_DEFAULT_VALUES[key]);
    -      return (value as string) || "";
    -    });
    -  }
    -
    -  return (
    -    
    -      {parsedChildren as string}
    -    
    -  );
    -}
    diff --git a/src/theme/CodeInline/index.scss b/src/theme/CodeInline/index.scss
    deleted file mode 100644
    index e69de29bb2..0000000000
    diff --git a/src/theme/CodeInline/index.tsx b/src/theme/CodeInline/index.tsx
    deleted file mode 100644
    index 933c9cb9f8..0000000000
    --- a/src/theme/CodeInline/index.tsx
    +++ /dev/null
    @@ -1,30 +0,0 @@
    -import React, { useContext } from "react";
    -import { Code } from "@radix-ui/themes";
    -
    -import { DocItemContext, getContextValue } from "@site/src/context";
    -import { DOC_STORE_DEFAULT_VALUES } from "@site/src/lib/constants";
    -
    -// Simple component used to render inline code blocks
    -// its purpose is to be swizzled and customized
    -// MDX 1 used to have a inlineCode comp, see https://mdxjs.com/migrating/v2/
    -export default function CodeInline(props: React.ComponentProps) {
    -  const { children, color = "gray", ...rest } = props;
    -
    -  const context = useContext(DocItemContext);
    -  const dynamicValuesRegex = /\^\{([^}]+)\}/g;
    -
    -  let parsedChildren = children;
    -  if (typeof children === "string") {
    -    parsedChildren = children.replaceAll(dynamicValuesRegex, (match, key) => {
    -      const value = getContextValue(context, key, DOC_STORE_DEFAULT_VALUES[key]);
    -      return (value as string) || "";
    -    });
    -  }
    -
    -  // Use a span because docusaurus default code styles conflict with radix-ui styles
    -  return (
    -    
    -      {parsedChildren}
    -    
    -  );
    -}
    diff --git a/src/theme/DocItem/Content/index.scss b/src/theme/DocItem/Content/index.scss
    deleted file mode 100644
    index a14afb2f92..0000000000
    --- a/src/theme/DocItem/Content/index.scss
    +++ /dev/null
    @@ -1,44 +0,0 @@
    -.markdown {
    -  ul {
    -    list-style: none;
    -    margin: 0;
    -    padding-left: var(--space-5);
    -    display: flex;
    -    flex-direction: column;
    -    margin-bottom: var(--space-5);
    -    gap: var(--space-2);
    -  }
    -
    -  ul li {
    -    & > * {
    -      margin-bottom: calc(var(--space-1) + 5px);
    -      margin-top: calc(var(--space-1) + 5px);
    -    }
    -
    -    & > *:last-child {
    -      margin-bottom: 0;
    -    }
    -
    -    & > *:first-child {
    -      margin-top: 0;
    -    }
    -
    -    margin: 0;
    -    padding: 0;
    -    &:before {
    -      content: "-";
    -      font-size: 25px;
    -      color: var(--gray-7);
    -      margin-top: -9px;
    -      position: absolute;
    -      margin-left: calc(-1 * var(--space-5));
    -    }
    -    // p {
    -    //   margin: 0;
    -    // }
    -  }
    -
    -  // p {
    -  //   color: var(--gray-a11);
    -  // }
    -}
    diff --git a/src/theme/DocItem/Content/index.tsx b/src/theme/DocItem/Content/index.tsx
    deleted file mode 100644
    index c9e103ac10..0000000000
    --- a/src/theme/DocItem/Content/index.tsx
    +++ /dev/null
    @@ -1,45 +0,0 @@
    -import React from "react";
    -import clsx from "clsx";
    -import { ThemeClassNames } from "@docusaurus/theme-common";
    -import { useDoc } from "@docusaurus/plugin-content-docs/client";
    -import Heading from "@theme/Heading";
    -import MDXContent from "@theme/MDXContent";
    -import type { Props } from "@theme/DocItem/Content";
    -
    -import "./index.scss";
    -
    -/**
    - Title can be declared inside md content or declared through
    - front matter and added manually. To make both cases consistent,
    - the added title is added under the same div.markdown block
    - See https://github.com/facebook/docusaurus/pull/4882#issuecomment-853021120
    -
    - We render a "synthetic title" if:
    - - user doesn't ask to hide it with front matter
    - - the markdown content does not already contain a top-level h1 heading
    -*/
    -function useSyntheticTitle(): string | null {
    -  const { metadata, frontMatter, contentTitle } = useDoc();
    -  const shouldRender = !frontMatter.hide_title && typeof contentTitle === "undefined";
    -  if (!shouldRender) {
    -    return null;
    -  }
    -  return metadata.title;
    -}
    -
    -export default function DocItemContent({ children }: Props): JSX.Element {
    -  const syntheticTitle = useSyntheticTitle();
    -
    -  const { metadata, frontMatter } = useDoc();
    -
    -  return (
    -    
    - {syntheticTitle && ( -
    - {syntheticTitle} -
    - )} - {children} -
    - ); -} diff --git a/src/theme/DocItem/Footer/index.scss b/src/theme/DocItem/Footer/index.scss deleted file mode 100644 index f61313a1e8..0000000000 --- a/src/theme/DocItem/Footer/index.scss +++ /dev/null @@ -1,12 +0,0 @@ -.feedback-submit-message { - animation: fadeIn 0.2s ease-in-out; -} - -@keyframes fadeIn { - 0% { - opacity: 0; - } - 100% { - opacity: 1; - } -} diff --git a/src/theme/DocItem/Footer/index.tsx b/src/theme/DocItem/Footer/index.tsx deleted file mode 100644 index 48aba1f9ac..0000000000 --- a/src/theme/DocItem/Footer/index.tsx +++ /dev/null @@ -1,306 +0,0 @@ -import React, { useCallback, useState } from "react"; -import clsx from "clsx"; -import { ThemeClassNames } from "@docusaurus/theme-common"; -import { useDoc } from "@docusaurus/plugin-content-docs/client"; - -import { motion } from "motion/react"; -import ThumbsUpIcon from "/img/icons/thumbs-up.svg"; -import PenIcon from "/img/icons/pen.svg"; -import ThumbsDownIcon from "/img/icons/thumbs-down.svg"; - -import { Box, Text, Flex, TextArea, Button, Dialog, RadioGroup } from "@radix-ui/themes"; -import { trackFormSubmit, AnalyticsEventNames } from "@site/src/lib/analytics"; - -import "./index.scss"; - -export default function DocItemFooter(): JSX.Element | null { - const { metadata } = useDoc(); - const { editUrl, frontMatter, lastUpdatedAt, lastUpdatedBy, tags } = metadata; - const { show_feedback = true } = frontMatter; - - const canDisplayTagsRow = tags.length > 0; - const canDisplayEditMetaRow = !!(editUrl || lastUpdatedAt || lastUpdatedBy); - - const canDisplayFooter = canDisplayTagsRow || canDisplayEditMetaRow || show_feedback; - - if (!canDisplayFooter) { - return null; - } - - return ( - -
    - - {show_feedback && } - {canDisplayEditMetaRow && ( - - - - - - )} - - {/* {canDisplayTagsRow && ( */} - {/*
    */} - {/*
    */} - {/* */} - {/*
    */} - {/*
    */} - {/* )} */} -
    -
    - ); -} - -const PositiveOptionValues = { - accurate: "accurate", - solvedMyProblem: "solved my problem", - easyToUnderstand: "easy to understand", - helpedMeDecide: "helped me decide to use the product", - other: "other reason", -} as const; - -const NegativeOptionsValues = { - inaccurate: "Inaccurate", - couldNotFind: "could not find what I was looking for", - hardToUnderstand: "hard to understand", - codeSampleErrors: "code sample errors", - other: "other reason", -}; - -function DocFeedback() { - const [hasSubmittedFeedback, setHasSubmittedFeedback] = React.useState(false); - const [selectedReason, setSelectedReason] = React.useState(null); - const [feedback, setFeedback] = React.useState(null); - - const onOpenChange = useCallback((isOpen) => { - if (isOpen) return; - setSelectedReason(null); - setFeedback(null); - }, []); - const onSubmit = useCallback( - (e: React.MouseEvent) => { - e.preventDefault(); - if (!selectedReason) return; - - // @ts-expect-error - const feedbackType = event.target.dataset.feedbackType as string; - - trackFormSubmit(AnalyticsEventNames.buttonFeedbackForm, "v1", { - feedbackType, - feedbackReason: selectedReason, - feedbackAdditionalInfo: feedback, - }); - setHasSubmittedFeedback(true); - }, - [selectedReason, feedback], - ); - - if (hasSubmittedFeedback) { - return ( - - Thank you for your feedback! - - ); - } - - return ( - - - Was this page helpful? - - - - - - - - - - What did you like? - - - - - Accurate - - Accurately describes the product or feature. - - {selectedReason === PositiveOptionValues.accurate && ( - - )} - - - - - Solved my problem - - Helped me resolve an issue. - - {selectedReason === PositiveOptionValues.solvedMyProblem && ( - - )} - - - - - Easy to understand - - Easy to follow and comprehend. - - {selectedReason === PositiveOptionValues.easyToUnderstand && ( - - )} - - - - - Helped me decide to use the product - - Convinced me to adopt the product or feature. - - {selectedReason === PositiveOptionValues.helpedMeDecide && ( - - )} - - - - Another reason - {selectedReason === PositiveOptionValues.other && ( - - )} - - - - - - - - - - - - - - - - - - What went wrong? - - - - - Inaccurate - - Doesn't accurately describe the product or feature. - - {selectedReason === NegativeOptionsValues.inaccurate && ( - - )} - - - - - Could not find - - Couldn't find what I was looking for. - - {selectedReason === NegativeOptionsValues.couldNotFind && ( - - )} - - - - - Hard to understand - - Too complicated or unclear. - - {selectedReason === NegativeOptionsValues.hardToUnderstand && ( - - )} - - - - - Code sample errors - - One or more code samples are incorrect. - - {selectedReason === NegativeOptionsValues.codeSampleErrors && ( - - )} - - - - Another reason - {selectedReason === NegativeOptionsValues.other && ( - - )} - - - - - - - - - - - - - - ); -} - -function AdditionalFeedbackTextArea({ onChange }: { onChange: (value: string) => void }) { - return ( -