@masheev/better-auth 0.0.0-stage → 1.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +20 -0
- package/README.md +31 -2
- package/TYPE-PATCH-NOTICE.md +9 -0
- package/TYPE-PATCH-PROVENANCE.json +267 -0
- package/dist/_virtual/_rolldown/runtime.mjs +27 -0
- package/dist/adapters/drizzle-adapter/index.d.mts +1 -0
- package/dist/adapters/drizzle-adapter/index.mjs +2 -0
- package/dist/adapters/index.d.mts +26 -0
- package/dist/adapters/index.mjs +9 -0
- package/dist/adapters/kysely-adapter/index.d.mts +1 -0
- package/dist/adapters/kysely-adapter/index.mjs +2 -0
- package/dist/adapters/memory-adapter/index.d.mts +1 -0
- package/dist/adapters/memory-adapter/index.mjs +2 -0
- package/dist/adapters/mongodb-adapter/index.d.mts +1 -0
- package/dist/adapters/mongodb-adapter/index.mjs +2 -0
- package/dist/adapters/prisma-adapter/index.d.mts +1 -0
- package/dist/adapters/prisma-adapter/index.mjs +2 -0
- package/dist/api/dispatch.d.mts +34 -0
- package/dist/api/dispatch.mjs +275 -0
- package/dist/api/index.d.mts +4053 -0
- package/dist/api/index.mjs +220 -0
- package/dist/api/middlewares/authorization.d.mts +69 -0
- package/dist/api/middlewares/authorization.mjs +78 -0
- package/dist/api/middlewares/index.d.mts +2 -0
- package/dist/api/middlewares/origin-check.d.mts +17 -0
- package/dist/api/middlewares/origin-check.mjs +155 -0
- package/dist/api/rate-limiter/index.mjs +318 -0
- package/dist/api/routes/account.d.mts +413 -0
- package/dist/api/routes/account.mjs +619 -0
- package/dist/api/routes/callback.d.mts +32 -0
- package/dist/api/routes/callback.mjs +261 -0
- package/dist/api/routes/email-verification.d.mts +160 -0
- package/dist/api/routes/email-verification.mjs +324 -0
- package/dist/api/routes/error.d.mts +27 -0
- package/dist/api/routes/error.mjs +387 -0
- package/dist/api/routes/index.d.mts +12 -0
- package/dist/api/routes/ok.d.mts +35 -0
- package/dist/api/routes/ok.mjs +27 -0
- package/dist/api/routes/password.d.mts +182 -0
- package/dist/api/routes/password.mjs +206 -0
- package/dist/api/routes/session.d.mts +450 -0
- package/dist/api/routes/session.mjs +481 -0
- package/dist/api/routes/sign-in.d.mts +186 -0
- package/dist/api/routes/sign-in.mjs +368 -0
- package/dist/api/routes/sign-out.d.mts +51 -0
- package/dist/api/routes/sign-out.mjs +96 -0
- package/dist/api/routes/sign-up.d.mts +159 -0
- package/dist/api/routes/sign-up.mjs +275 -0
- package/dist/api/routes/update-session.d.mts +74 -0
- package/dist/api/routes/update-session.mjs +57 -0
- package/dist/api/routes/update-user.d.mts +428 -0
- package/dist/api/routes/update-user.mjs +522 -0
- package/dist/api/state/oauth.d.mts +53 -0
- package/dist/api/state/oauth.mjs +38 -0
- package/dist/api/state/should-session-refresh.d.mts +12 -0
- package/dist/api/state/should-session-refresh.mjs +13 -0
- package/dist/api/to-auth-endpoints.mjs +60 -0
- package/dist/auth/base.mjs +66 -0
- package/dist/auth/full.d.mts +28 -0
- package/dist/auth/full.mjs +29 -0
- package/dist/auth/minimal.d.mts +10 -0
- package/dist/auth/minimal.mjs +11 -0
- package/dist/auth/trusted-origins.mjs +106 -0
- package/dist/client/broadcast-channel.d.mts +19 -0
- package/dist/client/broadcast-channel.mjs +44 -0
- package/dist/client/config.d.mts +90 -0
- package/dist/client/config.mjs +113 -0
- package/dist/client/equality.d.mts +19 -0
- package/dist/client/equality.mjs +42 -0
- package/dist/client/fetch-plugins.mjs +17 -0
- package/dist/client/focus-manager.d.mts +10 -0
- package/dist/client/focus-manager.mjs +30 -0
- package/dist/client/index.d.mts +35 -0
- package/dist/client/index.mjs +22 -0
- package/dist/client/lynx/index.d.mts +43 -0
- package/dist/client/lynx/index.mjs +22 -0
- package/dist/client/lynx/lynx-store.d.mts +46 -0
- package/dist/client/lynx/lynx-store.mjs +44 -0
- package/dist/client/online-manager.d.mts +11 -0
- package/dist/client/online-manager.mjs +33 -0
- package/dist/client/parser.d.mts +10 -0
- package/dist/client/parser.mjs +70 -0
- package/dist/client/path-to-object.d.mts +113 -0
- package/dist/client/plugins/index.d.mts +44 -0
- package/dist/client/plugins/index.mjs +30 -0
- package/dist/client/plugins/infer-plugin.d.mts +16 -0
- package/dist/client/plugins/infer-plugin.mjs +11 -0
- package/dist/client/proxy.mjs +78 -0
- package/dist/client/query.d.mts +23 -0
- package/dist/client/query.mjs +124 -0
- package/dist/client/react/index.d.mts +44 -0
- package/dist/client/react/index.mjs +22 -0
- package/dist/client/react/react-store.d.mts +46 -0
- package/dist/client/react/react-store.mjs +44 -0
- package/dist/client/session-atom.d.mts +11 -0
- package/dist/client/session-atom.mjs +178 -0
- package/dist/client/session-refresh.d.mts +20 -0
- package/dist/client/session-refresh.mjs +131 -0
- package/dist/client/solid/index.d.mts +44 -0
- package/dist/client/solid/index.mjs +22 -0
- package/dist/client/solid/solid-store.mjs +21 -0
- package/dist/client/svelte/index.d.mts +44 -0
- package/dist/client/svelte/index.mjs +18 -0
- package/dist/client/types.d.mts +51 -0
- package/dist/client/vanilla.d.mts +42 -0
- package/dist/client/vanilla.mjs +18 -0
- package/dist/client/vue/index.d.mts +67 -0
- package/dist/client/vue/index.mjs +54 -0
- package/dist/client/vue/vue-store.mjs +23 -0
- package/dist/context/create-context.mjs +235 -0
- package/dist/context/helpers.mjs +158 -0
- package/dist/context/init-minimal.mjs +17 -0
- package/dist/context/init.mjs +19 -0
- package/dist/context/secret-utils.mjs +53 -0
- package/dist/context/store-capabilities.mjs +12 -0
- package/dist/cookies/cache.mjs +33 -0
- package/dist/cookies/cookie-utils.d.mts +72 -0
- package/dist/cookies/cookie-utils.mjs +203 -0
- package/dist/cookies/index.d.mts +124 -0
- package/dist/cookies/index.mjs +350 -0
- package/dist/cookies/jwt.mjs +44 -0
- package/dist/cookies/session-store.d.mts +32 -0
- package/dist/cookies/session-store.mjs +183 -0
- package/dist/crypto/buffer.d.mts +7 -0
- package/dist/crypto/buffer.mjs +16 -0
- package/dist/crypto/index.d.mts +32 -0
- package/dist/crypto/index.mjs +69 -0
- package/dist/crypto/jwt.d.mts +9 -0
- package/dist/crypto/jwt.mjs +141 -0
- package/dist/crypto/password.d.mts +13 -0
- package/dist/crypto/password.mjs +14 -0
- package/dist/crypto/random.d.mts +4 -0
- package/dist/crypto/random.mjs +5 -0
- package/dist/db/adapter-base.d.mts +7 -0
- package/dist/db/adapter-base.mjs +25 -0
- package/dist/db/adapter-kysely.d.mts +7 -0
- package/dist/db/adapter-kysely.mjs +17 -0
- package/dist/db/field-converter.d.mts +7 -0
- package/dist/db/field-converter.mjs +19 -0
- package/dist/db/field.d.mts +41 -0
- package/dist/db/get-migration.d.mts +56 -0
- package/dist/db/get-migration.mjs +685 -0
- package/dist/db/get-schema.d.mts +13 -0
- package/dist/db/get-schema.mjs +39 -0
- package/dist/db/index.d.mts +10 -0
- package/dist/db/index.mjs +35 -0
- package/dist/db/internal-adapter.d.mts +14 -0
- package/dist/db/internal-adapter.mjs +951 -0
- package/dist/db/revoke-unproven-account-access.d.mts +21 -0
- package/dist/db/revoke-unproven-account-access.mjs +58 -0
- package/dist/db/schema.d.mts +62 -0
- package/dist/db/schema.mjs +161 -0
- package/dist/db/to-zod.d.mts +35 -0
- package/dist/db/to-zod.mjs +23 -0
- package/dist/db/verification-token-storage.mjs +25 -0
- package/dist/db/with-hooks.d.mts +37 -0
- package/dist/db/with-hooks.mjs +255 -0
- package/dist/index.d.mts +30 -0
- package/dist/index.mjs +17 -0
- package/dist/integrations/cookie-plugin-guard.mjs +18 -0
- package/dist/integrations/next-js.d.mts +29 -0
- package/dist/integrations/next-js.mjs +105 -0
- package/dist/integrations/node.d.mts +11 -0
- package/dist/integrations/node.mjs +13 -0
- package/dist/integrations/solid-start.d.mts +22 -0
- package/dist/integrations/solid-start.mjs +15 -0
- package/dist/integrations/svelte-kit.d.mts +38 -0
- package/dist/integrations/svelte-kit.mjs +57 -0
- package/dist/integrations/tanstack-start-solid.d.mts +33 -0
- package/dist/integrations/tanstack-start-solid.mjs +57 -0
- package/dist/integrations/tanstack-start.d.mts +33 -0
- package/dist/integrations/tanstack-start.mjs +57 -0
- package/dist/oauth2/account-key.mjs +43 -0
- package/dist/oauth2/errors.mjs +49 -0
- package/dist/oauth2/index.d.mts +5 -0
- package/dist/oauth2/index.mjs +5 -0
- package/dist/oauth2/link-account.d.mts +96 -0
- package/dist/oauth2/link-account.mjs +329 -0
- package/dist/oauth2/state.d.mts +54 -0
- package/dist/oauth2/state.mjs +67 -0
- package/dist/oauth2/utils.d.mts +11 -0
- package/dist/oauth2/utils.mjs +33 -0
- package/dist/package.mjs +4 -0
- package/dist/plugins/access/access.d.mts +17 -0
- package/dist/plugins/access/access.mjs +78 -0
- package/dist/plugins/access/index.d.mts +3 -0
- package/dist/plugins/access/index.mjs +2 -0
- package/dist/plugins/access/types.d.mts +24 -0
- package/dist/plugins/additional-fields/client.d.mts +100 -0
- package/dist/plugins/additional-fields/client.mjs +11 -0
- package/dist/plugins/admin/access/index.d.mts +2 -0
- package/dist/plugins/admin/access/index.mjs +2 -0
- package/dist/plugins/admin/access/statement.d.mts +51 -0
- package/dist/plugins/admin/access/statement.mjs +52 -0
- package/dist/plugins/admin/admin.d.mts +911 -0
- package/dist/plugins/admin/admin.mjs +89 -0
- package/dist/plugins/admin/client.d.mts +81 -0
- package/dist/plugins/admin/client.mjs +39 -0
- package/dist/plugins/admin/error-codes.d.mts +30 -0
- package/dist/plugins/admin/error-codes.mjs +29 -0
- package/dist/plugins/admin/has-permission.mjs +12 -0
- package/dist/plugins/admin/index.d.mts +3 -0
- package/dist/plugins/admin/index.mjs +2 -0
- package/dist/plugins/admin/routes.mjs +919 -0
- package/dist/plugins/admin/schema.d.mts +40 -0
- package/dist/plugins/admin/schema.mjs +33 -0
- package/dist/plugins/admin/types.d.mts +88 -0
- package/dist/plugins/anonymous/client.d.mts +32 -0
- package/dist/plugins/anonymous/client.mjs +21 -0
- package/dist/plugins/anonymous/error-codes.d.mts +15 -0
- package/dist/plugins/anonymous/error-codes.mjs +14 -0
- package/dist/plugins/anonymous/index.d.mts +175 -0
- package/dist/plugins/anonymous/index.mjs +219 -0
- package/dist/plugins/anonymous/schema.d.mts +15 -0
- package/dist/plugins/anonymous/schema.mjs +9 -0
- package/dist/plugins/anonymous/types.d.mts +65 -0
- package/dist/plugins/bearer/index.d.mts +45 -0
- package/dist/plugins/bearer/index.mjs +74 -0
- package/dist/plugins/captcha/constants.d.mts +9 -0
- package/dist/plugins/captcha/constants.mjs +27 -0
- package/dist/plugins/captcha/error-codes.mjs +13 -0
- package/dist/plugins/captcha/index.d.mts +27 -0
- package/dist/plugins/captcha/index.mjs +79 -0
- package/dist/plugins/captcha/types.d.mts +52 -0
- package/dist/plugins/captcha/utils.mjs +9 -0
- package/dist/plugins/captcha/verify-handlers/captchafox.mjs +27 -0
- package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs +47 -0
- package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs +32 -0
- package/dist/plugins/captcha/verify-handlers/h-captcha.mjs +27 -0
- package/dist/plugins/custom-session/client.d.mts +17 -0
- package/dist/plugins/custom-session/client.mjs +7 -0
- package/dist/plugins/custom-session/index.d.mts +73 -0
- package/dist/plugins/custom-session/index.mjs +65 -0
- package/dist/plugins/device-authorization/client.d.mts +17 -0
- package/dist/plugins/device-authorization/client.mjs +18 -0
- package/dist/plugins/device-authorization/error-codes.mjs +19 -0
- package/dist/plugins/device-authorization/index.d.mts +558 -0
- package/dist/plugins/device-authorization/index.mjs +87 -0
- package/dist/plugins/device-authorization/routes.d.mts +32 -0
- package/dist/plugins/device-authorization/routes.mjs +725 -0
- package/dist/plugins/device-authorization/schema.d.mts +18 -0
- package/dist/plugins/device-authorization/schema.mjs +63 -0
- package/dist/plugins/email-otp/client.d.mts +21 -0
- package/dist/plugins/email-otp/client.mjs +17 -0
- package/dist/plugins/email-otp/error-codes.d.mts +10 -0
- package/dist/plugins/email-otp/error-codes.mjs +9 -0
- package/dist/plugins/email-otp/index.d.mts +551 -0
- package/dist/plugins/email-otp/index.mjs +145 -0
- package/dist/plugins/email-otp/otp-token.mjs +55 -0
- package/dist/plugins/email-otp/routes.mjs +784 -0
- package/dist/plugins/email-otp/types.d.mts +109 -0
- package/dist/plugins/email-otp/utils.mjs +17 -0
- package/dist/plugins/generic-oauth/error-codes.mjs +8 -0
- package/dist/plugins/generic-oauth/index.d.mts +52 -0
- package/dist/plugins/generic-oauth/index.mjs +279 -0
- package/dist/plugins/generic-oauth/providers/auth0.d.mts +36 -0
- package/dist/plugins/generic-oauth/providers/auth0.mjs +49 -0
- package/dist/plugins/generic-oauth/providers/gumroad.d.mts +31 -0
- package/dist/plugins/generic-oauth/providers/gumroad.mjs +62 -0
- package/dist/plugins/generic-oauth/providers/hubspot.d.mts +36 -0
- package/dist/plugins/generic-oauth/providers/hubspot.mjs +62 -0
- package/dist/plugins/generic-oauth/providers/index.d.mts +10 -0
- package/dist/plugins/generic-oauth/providers/keycloak.d.mts +36 -0
- package/dist/plugins/generic-oauth/providers/keycloak.mjs +47 -0
- package/dist/plugins/generic-oauth/providers/line.d.mts +54 -0
- package/dist/plugins/generic-oauth/providers/line.mjs +93 -0
- package/dist/plugins/generic-oauth/providers/microsoft-entra-id.d.mts +39 -0
- package/dist/plugins/generic-oauth/providers/microsoft-entra-id.mjs +104 -0
- package/dist/plugins/generic-oauth/providers/okta.d.mts +36 -0
- package/dist/plugins/generic-oauth/providers/okta.mjs +47 -0
- package/dist/plugins/generic-oauth/providers/patreon.d.mts +29 -0
- package/dist/plugins/generic-oauth/providers/patreon.mjs +61 -0
- package/dist/plugins/generic-oauth/providers/slack.d.mts +29 -0
- package/dist/plugins/generic-oauth/providers/slack.mjs +63 -0
- package/dist/plugins/generic-oauth/providers/yandex.d.mts +29 -0
- package/dist/plugins/generic-oauth/providers/yandex.mjs +67 -0
- package/dist/plugins/generic-oauth/types.d.mts +268 -0
- package/dist/plugins/haveibeenpwned/index.d.mts +63 -0
- package/dist/plugins/haveibeenpwned/index.mjs +81 -0
- package/dist/plugins/index.d.mts +69 -0
- package/dist/plugins/index.mjs +49 -0
- package/dist/plugins/jwt/adapter.mjs +68 -0
- package/dist/plugins/jwt/client.d.mts +41 -0
- package/dist/plugins/jwt/client.mjs +19 -0
- package/dist/plugins/jwt/cookie-cache.mjs +77 -0
- package/dist/plugins/jwt/index.d.mts +246 -0
- package/dist/plugins/jwt/index.mjs +214 -0
- package/dist/plugins/jwt/schema.d.mts +33 -0
- package/dist/plugins/jwt/schema.mjs +29 -0
- package/dist/plugins/jwt/sign.d.mts +128 -0
- package/dist/plugins/jwt/sign.mjs +130 -0
- package/dist/plugins/jwt/types.d.mts +256 -0
- package/dist/plugins/jwt/utils.d.mts +41 -0
- package/dist/plugins/jwt/utils.mjs +64 -0
- package/dist/plugins/jwt/verify.d.mts +11 -0
- package/dist/plugins/jwt/verify.mjs +45 -0
- package/dist/plugins/last-login-method/client.d.mts +48 -0
- package/dist/plugins/last-login-method/client.mjs +48 -0
- package/dist/plugins/last-login-method/index.d.mts +127 -0
- package/dist/plugins/last-login-method/index.mjs +98 -0
- package/dist/plugins/magic-link/client.d.mts +10 -0
- package/dist/plugins/magic-link/client.mjs +11 -0
- package/dist/plugins/magic-link/index.d.mts +213 -0
- package/dist/plugins/magic-link/index.mjs +208 -0
- package/dist/plugins/magic-link/utils.mjs +9 -0
- package/dist/plugins/multi-session/client.d.mts +19 -0
- package/dist/plugins/multi-session/client.mjs +19 -0
- package/dist/plugins/multi-session/error-codes.d.mts +8 -0
- package/dist/plugins/multi-session/error-codes.mjs +5 -0
- package/dist/plugins/multi-session/index.d.mts +212 -0
- package/dist/plugins/multi-session/index.mjs +217 -0
- package/dist/plugins/oauth-popup/client.d.mts +82 -0
- package/dist/plugins/oauth-popup/client.mjs +203 -0
- package/dist/plugins/oauth-popup/constants.d.mts +11 -0
- package/dist/plugins/oauth-popup/constants.mjs +11 -0
- package/dist/plugins/oauth-popup/error-codes.d.mts +11 -0
- package/dist/plugins/oauth-popup/error-codes.mjs +10 -0
- package/dist/plugins/oauth-popup/index.d.mts +67 -0
- package/dist/plugins/oauth-popup/index.mjs +232 -0
- package/dist/plugins/oauth-popup/types.d.mts +30 -0
- package/dist/plugins/oauth-proxy/index.d.mts +130 -0
- package/dist/plugins/oauth-proxy/index.mjs +407 -0
- package/dist/plugins/oauth-proxy/utils.mjs +55 -0
- package/dist/plugins/one-tap/client.d.mts +174 -0
- package/dist/plugins/one-tap/client.mjs +208 -0
- package/dist/plugins/one-tap/index.d.mts +82 -0
- package/dist/plugins/one-tap/index.mjs +100 -0
- package/dist/plugins/one-time-token/client.d.mts +10 -0
- package/dist/plugins/one-time-token/client.mjs +11 -0
- package/dist/plugins/one-time-token/index.d.mts +132 -0
- package/dist/plugins/one-time-token/index.mjs +107 -0
- package/dist/plugins/one-time-token/utils.mjs +9 -0
- package/dist/plugins/open-api/generator.d.mts +126 -0
- package/dist/plugins/open-api/generator.mjs +557 -0
- package/dist/plugins/open-api/index.d.mts +97 -0
- package/dist/plugins/open-api/index.mjs +65 -0
- package/dist/plugins/open-api/logo.mjs +13 -0
- package/dist/plugins/organization/access/index.d.mts +2 -0
- package/dist/plugins/organization/access/index.mjs +2 -0
- package/dist/plugins/organization/access/statement.d.mts +113 -0
- package/dist/plugins/organization/access/statement.mjs +77 -0
- package/dist/plugins/organization/adapter.d.mts +815 -0
- package/dist/plugins/organization/adapter.mjs +813 -0
- package/dist/plugins/organization/call.mjs +15 -0
- package/dist/plugins/organization/client.d.mts +375 -0
- package/dist/plugins/organization/client.mjs +104 -0
- package/dist/plugins/organization/error-codes.d.mts +66 -0
- package/dist/plugins/organization/error-codes.mjs +65 -0
- package/dist/plugins/organization/has-permission.d.mts +17 -0
- package/dist/plugins/organization/has-permission.mjs +34 -0
- package/dist/plugins/organization/index.d.mts +6 -0
- package/dist/plugins/organization/index.mjs +4 -0
- package/dist/plugins/organization/organization.d.mts +420 -0
- package/dist/plugins/organization/organization.mjs +886 -0
- package/dist/plugins/organization/permission.d.mts +15 -0
- package/dist/plugins/organization/permission.mjs +14 -0
- package/dist/plugins/organization/routes/crud-access-control.d.mts +511 -0
- package/dist/plugins/organization/routes/crud-access-control.mjs +674 -0
- package/dist/plugins/organization/routes/crud-invites.d.mts +1154 -0
- package/dist/plugins/organization/routes/crud-invites.mjs +602 -0
- package/dist/plugins/organization/routes/crud-members.d.mts +1057 -0
- package/dist/plugins/organization/routes/crud-members.mjs +518 -0
- package/dist/plugins/organization/routes/crud-org.d.mts +918 -0
- package/dist/plugins/organization/routes/crud-org.mjs +455 -0
- package/dist/plugins/organization/routes/crud-team.d.mts +1238 -0
- package/dist/plugins/organization/routes/crud-team.mjs +766 -0
- package/dist/plugins/organization/schema.d.mts +390 -0
- package/dist/plugins/organization/schema.mjs +65 -0
- package/dist/plugins/organization/types.d.mts +691 -0
- package/dist/plugins/phone-number/client.d.mts +31 -0
- package/dist/plugins/phone-number/client.mjs +19 -0
- package/dist/plugins/phone-number/error-codes.d.mts +19 -0
- package/dist/plugins/phone-number/error-codes.mjs +18 -0
- package/dist/plugins/phone-number/index.d.mts +360 -0
- package/dist/plugins/phone-number/index.mjs +57 -0
- package/dist/plugins/phone-number/routes.mjs +529 -0
- package/dist/plugins/phone-number/schema.d.mts +22 -0
- package/dist/plugins/phone-number/schema.mjs +18 -0
- package/dist/plugins/phone-number/types.d.mts +116 -0
- package/dist/plugins/siwe/client.d.mts +14 -0
- package/dist/plugins/siwe/client.mjs +15 -0
- package/dist/plugins/siwe/index.d.mts +62 -0
- package/dist/plugins/siwe/index.mjs +272 -0
- package/dist/plugins/siwe/parse-message.mjs +60 -0
- package/dist/plugins/siwe/schema.d.mts +35 -0
- package/dist/plugins/siwe/schema.mjs +30 -0
- package/dist/plugins/siwe/types.d.mts +43 -0
- package/dist/plugins/test-utils/auth-helpers.mjs +33 -0
- package/dist/plugins/test-utils/cookie-builder.mjs +55 -0
- package/dist/plugins/test-utils/db-helpers.mjs +65 -0
- package/dist/plugins/test-utils/factories.mjs +38 -0
- package/dist/plugins/test-utils/index.d.mts +73 -0
- package/dist/plugins/test-utils/index.mjs +97 -0
- package/dist/plugins/test-utils/otp-sink.mjs +21 -0
- package/dist/plugins/test-utils/types.d.mts +51 -0
- package/dist/plugins/two-factor/backup-codes/index.d.mts +291 -0
- package/dist/plugins/two-factor/backup-codes/index.mjs +341 -0
- package/dist/plugins/two-factor/client.d.mts +76 -0
- package/dist/plugins/two-factor/client.mjs +41 -0
- package/dist/plugins/two-factor/constant.mjs +6 -0
- package/dist/plugins/two-factor/error-code.d.mts +20 -0
- package/dist/plugins/two-factor/error-code.mjs +19 -0
- package/dist/plugins/two-factor/index.d.mts +720 -0
- package/dist/plugins/two-factor/index.mjs +349 -0
- package/dist/plugins/two-factor/otp/index.d.mts +216 -0
- package/dist/plugins/two-factor/otp/index.mjs +252 -0
- package/dist/plugins/two-factor/schema.d.mts +59 -0
- package/dist/plugins/two-factor/schema.mjs +53 -0
- package/dist/plugins/two-factor/totp/index.d.mts +219 -0
- package/dist/plugins/two-factor/totp/index.mjs +230 -0
- package/dist/plugins/two-factor/types.d.mts +111 -0
- package/dist/plugins/two-factor/utils.mjs +9 -0
- package/dist/plugins/two-factor/verify-two-factor.mjs +205 -0
- package/dist/plugins/username/client.d.mts +38 -0
- package/dist/plugins/username/client.mjs +17 -0
- package/dist/plugins/username/error-codes.d.mts +16 -0
- package/dist/plugins/username/error-codes.mjs +15 -0
- package/dist/plugins/username/index.d.mts +326 -0
- package/dist/plugins/username/index.mjs +312 -0
- package/dist/plugins/username/schema.d.mts +50 -0
- package/dist/plugins/username/schema.mjs +25 -0
- package/dist/social-providers/index.d.mts +1 -0
- package/dist/social-providers/index.mjs +2 -0
- package/dist/state.d.mts +48 -0
- package/dist/state.mjs +149 -0
- package/dist/test-utils/headers.d.mts +8 -0
- package/dist/test-utils/headers.mjs +17 -0
- package/dist/test-utils/http-test-instance.d.mts +413 -0
- package/dist/test-utils/http-test-instance.mjs +107 -0
- package/dist/test-utils/index.d.mts +4 -0
- package/dist/test-utils/index.mjs +4 -0
- package/dist/test-utils/test-instance.d.mts +56 -0
- package/dist/test-utils/test-instance.mjs +242 -0
- package/dist/types/adapter.d.mts +2 -0
- package/dist/types/api.d.mts +28 -0
- package/dist/types/auth.d.mts +32 -0
- package/dist/types/helper.d.mts +26 -0
- package/dist/types/index.d.mts +10 -0
- package/dist/types/index.mjs +1 -0
- package/dist/types/models.d.mts +10 -0
- package/dist/types/plugins.d.mts +19 -0
- package/dist/utils/boolean.mjs +6 -0
- package/dist/utils/constants.mjs +4 -0
- package/dist/utils/date.mjs +6 -0
- package/dist/utils/hashing.mjs +18 -0
- package/dist/utils/hide-metadata.d.mts +6 -0
- package/dist/utils/hide-metadata.mjs +4 -0
- package/dist/utils/index.d.mts +4 -0
- package/dist/utils/is-api-error.d.mts +2 -0
- package/dist/utils/is-api-error.mjs +2 -0
- package/dist/utils/is-atom.mjs +6 -0
- package/dist/utils/is-promise.mjs +6 -0
- package/dist/utils/middleware-response.mjs +7 -0
- package/dist/utils/password.mjs +32 -0
- package/dist/utils/plugin-helper.mjs +14 -0
- package/dist/utils/request.mjs +23 -0
- package/dist/utils/shim.mjs +22 -0
- package/dist/utils/time.d.mts +48 -0
- package/dist/utils/time.mjs +98 -0
- package/dist/utils/url.d.mts +78 -0
- package/dist/utils/url.mjs +238 -0
- package/dist/utils/validate-user-info.mjs +44 -0
- package/dist/utils/wildcard.mjs +106 -0
- package/dist/version.mjs +5 -0
- package/package.json +595 -3
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
2
|
+
//#region src/utils/password.ts
|
|
3
|
+
async function validatePassword(ctx, data) {
|
|
4
|
+
const credentialAccount = await ctx.context.internalAdapter.findCredentialAccount(data.userId);
|
|
5
|
+
const currentPassword = credentialAccount?.password;
|
|
6
|
+
if (!credentialAccount || !currentPassword) return false;
|
|
7
|
+
return await ctx.context.password.verify({
|
|
8
|
+
hash: currentPassword,
|
|
9
|
+
password: data.password
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
async function checkPassword(userId, c) {
|
|
13
|
+
const credentialAccount = await c.context.internalAdapter.findCredentialAccount(userId);
|
|
14
|
+
const currentPassword = credentialAccount?.password;
|
|
15
|
+
const password = c.body.password;
|
|
16
|
+
if (!credentialAccount || !currentPassword || !password) {
|
|
17
|
+
if (password) await c.context.password.hash(password);
|
|
18
|
+
throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.INVALID_PASSWORD);
|
|
19
|
+
}
|
|
20
|
+
if (!await c.context.password.verify({
|
|
21
|
+
hash: currentPassword,
|
|
22
|
+
password
|
|
23
|
+
})) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.INVALID_PASSWORD);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
async function shouldRequirePassword(ctx, userId, allowPasswordless) {
|
|
27
|
+
if (!allowPasswordless) return true;
|
|
28
|
+
const credentialAccount = await ctx.context.internalAdapter.findCredentialAccount(userId);
|
|
29
|
+
return Boolean(credentialAccount?.password);
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { checkPassword, shouldRequirePassword, validatePassword };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { isAPIError } from "./is-api-error.mjs";
|
|
2
|
+
//#region src/utils/plugin-helper.ts
|
|
3
|
+
const getEndpointResponse = async (ctx) => {
|
|
4
|
+
const returned = ctx.context.returned;
|
|
5
|
+
if (!returned) return null;
|
|
6
|
+
if (returned instanceof Response) {
|
|
7
|
+
if (returned.status !== 200) return null;
|
|
8
|
+
return await returned.clone().json();
|
|
9
|
+
}
|
|
10
|
+
if (isAPIError(returned)) return null;
|
|
11
|
+
return returned;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { getEndpointResponse };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/utils/request.ts
|
|
2
|
+
function safeCloneRequest(request) {
|
|
3
|
+
if (!request) return;
|
|
4
|
+
try {
|
|
5
|
+
return request.clone();
|
|
6
|
+
} catch {
|
|
7
|
+
return new Request(request.url, {
|
|
8
|
+
cache: request.cache,
|
|
9
|
+
credentials: request.credentials,
|
|
10
|
+
headers: request.headers,
|
|
11
|
+
integrity: request.integrity,
|
|
12
|
+
keepalive: request.keepalive,
|
|
13
|
+
method: request.method,
|
|
14
|
+
mode: request.mode,
|
|
15
|
+
redirect: request.redirect,
|
|
16
|
+
referrer: request.referrer,
|
|
17
|
+
referrerPolicy: request.referrerPolicy,
|
|
18
|
+
signal: request.signal
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { safeCloneRequest };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/utils/shim.ts
|
|
2
|
+
const shimContext = (originalObject, newContext) => {
|
|
3
|
+
const shimmedObj = {};
|
|
4
|
+
for (const [key, value] of Object.entries(originalObject)) {
|
|
5
|
+
shimmedObj[key] = (ctx) => {
|
|
6
|
+
return value({
|
|
7
|
+
...ctx,
|
|
8
|
+
context: {
|
|
9
|
+
...newContext,
|
|
10
|
+
...ctx.context
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
shimmedObj[key].path = value.path;
|
|
15
|
+
shimmedObj[key].method = value.method;
|
|
16
|
+
shimmedObj[key].options = value.options;
|
|
17
|
+
shimmedObj[key].headers = value.headers;
|
|
18
|
+
}
|
|
19
|
+
return shimmedObj;
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { shimContext };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//#region src/utils/time.d.ts
|
|
2
|
+
type Years = "years" | "year" | "yrs" | "yr" | "y";
|
|
3
|
+
type Months = "months" | "month" | "mo";
|
|
4
|
+
type Weeks = "weeks" | "week" | "w";
|
|
5
|
+
type Days = "days" | "day" | "d";
|
|
6
|
+
type Hours = "hours" | "hour" | "hrs" | "hr" | "h";
|
|
7
|
+
type Minutes = "minutes" | "minute" | "mins" | "min" | "m";
|
|
8
|
+
type Seconds = "seconds" | "second" | "secs" | "sec" | "s";
|
|
9
|
+
type Unit = Years | Months | Weeks | Days | Hours | Minutes | Seconds;
|
|
10
|
+
type UnitAnyCase = Capitalize<Unit> | Uppercase<Unit> | Unit;
|
|
11
|
+
type Suffix = " ago" | " from now";
|
|
12
|
+
type Prefix = "+" | "-" | "+ " | "- ";
|
|
13
|
+
type BaseTimeString = `${number}${UnitAnyCase}` | `${number} ${UnitAnyCase}`;
|
|
14
|
+
/**
|
|
15
|
+
* A typed string representing a time duration.
|
|
16
|
+
* Supports formats like "7d", "30m", "1 hour", "2 hours ago", "-5m", etc.
|
|
17
|
+
*/
|
|
18
|
+
type TimeString = BaseTimeString | `${BaseTimeString}${Suffix}` | `${Prefix}${BaseTimeString}`;
|
|
19
|
+
/**
|
|
20
|
+
* Parse a time string and return the value in milliseconds.
|
|
21
|
+
*
|
|
22
|
+
* @param value - A time string like "7d", "30m", "1 hour", "2 hours ago"
|
|
23
|
+
* @returns The parsed value in milliseconds
|
|
24
|
+
* @throws TypeError if the string format is invalid
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ms("1d") // 86400000
|
|
28
|
+
* ms("2 hours") // 7200000
|
|
29
|
+
* ms("30s") // 30000
|
|
30
|
+
* ms("2 hours ago") // -7200000
|
|
31
|
+
*/
|
|
32
|
+
declare function ms(value: TimeString): number;
|
|
33
|
+
/**
|
|
34
|
+
* Parse a time string and return the value in seconds.
|
|
35
|
+
*
|
|
36
|
+
* @param value - A time string like "7d", "30m", "1 hour", "2 hours ago"
|
|
37
|
+
* @returns The parsed value in seconds (rounded)
|
|
38
|
+
* @throws TypeError if the string format is invalid
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* sec("1d") // 86400
|
|
42
|
+
* sec("2 hours") // 7200
|
|
43
|
+
* sec("-30s") // -30
|
|
44
|
+
* sec("2 hours ago") // -7200
|
|
45
|
+
*/
|
|
46
|
+
declare function sec(value: TimeString): number;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { TimeString, ms, sec };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
//#region src/utils/time.ts
|
|
2
|
+
const SEC = 1e3;
|
|
3
|
+
const MIN = SEC * 60;
|
|
4
|
+
const HOUR = MIN * 60;
|
|
5
|
+
const DAY = HOUR * 24;
|
|
6
|
+
const WEEK = DAY * 7;
|
|
7
|
+
const MONTH = DAY * 30;
|
|
8
|
+
const YEAR = DAY * 365.25;
|
|
9
|
+
const REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|months?|mo|years?|yrs?|y)(?: (ago|from now))?$/i;
|
|
10
|
+
function parse(value) {
|
|
11
|
+
const match = REGEX.exec(value);
|
|
12
|
+
if (!match || match[4] && match[1]) throw new TypeError(`Invalid time string format: "${value}". Use formats like "7d", "30m", "1 hour", etc.`);
|
|
13
|
+
const n = parseFloat(match[2]);
|
|
14
|
+
const unit = match[3].toLowerCase();
|
|
15
|
+
let result;
|
|
16
|
+
switch (unit) {
|
|
17
|
+
case "years":
|
|
18
|
+
case "year":
|
|
19
|
+
case "yrs":
|
|
20
|
+
case "yr":
|
|
21
|
+
case "y":
|
|
22
|
+
result = n * YEAR;
|
|
23
|
+
break;
|
|
24
|
+
case "months":
|
|
25
|
+
case "month":
|
|
26
|
+
case "mo":
|
|
27
|
+
result = n * MONTH;
|
|
28
|
+
break;
|
|
29
|
+
case "weeks":
|
|
30
|
+
case "week":
|
|
31
|
+
case "w":
|
|
32
|
+
result = n * WEEK;
|
|
33
|
+
break;
|
|
34
|
+
case "days":
|
|
35
|
+
case "day":
|
|
36
|
+
case "d":
|
|
37
|
+
result = n * DAY;
|
|
38
|
+
break;
|
|
39
|
+
case "hours":
|
|
40
|
+
case "hour":
|
|
41
|
+
case "hrs":
|
|
42
|
+
case "hr":
|
|
43
|
+
case "h":
|
|
44
|
+
result = n * HOUR;
|
|
45
|
+
break;
|
|
46
|
+
case "minutes":
|
|
47
|
+
case "minute":
|
|
48
|
+
case "mins":
|
|
49
|
+
case "min":
|
|
50
|
+
case "m":
|
|
51
|
+
result = n * MIN;
|
|
52
|
+
break;
|
|
53
|
+
case "seconds":
|
|
54
|
+
case "second":
|
|
55
|
+
case "secs":
|
|
56
|
+
case "sec":
|
|
57
|
+
case "s":
|
|
58
|
+
result = n * SEC;
|
|
59
|
+
break;
|
|
60
|
+
default: throw new TypeError(`Unknown time unit: "${unit}"`);
|
|
61
|
+
}
|
|
62
|
+
if (match[1] === "-" || match[4] === "ago") return -result;
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Parse a time string and return the value in milliseconds.
|
|
67
|
+
*
|
|
68
|
+
* @param value - A time string like "7d", "30m", "1 hour", "2 hours ago"
|
|
69
|
+
* @returns The parsed value in milliseconds
|
|
70
|
+
* @throws TypeError if the string format is invalid
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ms("1d") // 86400000
|
|
74
|
+
* ms("2 hours") // 7200000
|
|
75
|
+
* ms("30s") // 30000
|
|
76
|
+
* ms("2 hours ago") // -7200000
|
|
77
|
+
*/
|
|
78
|
+
function ms(value) {
|
|
79
|
+
return parse(value);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Parse a time string and return the value in seconds.
|
|
83
|
+
*
|
|
84
|
+
* @param value - A time string like "7d", "30m", "1 hour", "2 hours ago"
|
|
85
|
+
* @returns The parsed value in seconds (rounded)
|
|
86
|
+
* @throws TypeError if the string format is invalid
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* sec("1d") // 86400
|
|
90
|
+
* sec("2 hours") // 7200
|
|
91
|
+
* sec("-30s") // -30
|
|
92
|
+
* sec("2 hours ago") // -7200
|
|
93
|
+
*/
|
|
94
|
+
function sec(value) {
|
|
95
|
+
return Math.round(parse(value) / 1e3);
|
|
96
|
+
}
|
|
97
|
+
//#endregion
|
|
98
|
+
export { ms, sec };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { BaseURLConfig, DynamicBaseURLConfig } from "@better-auth/core";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/url.d.ts
|
|
4
|
+
declare function trimTrailingSlashes(value: string): string;
|
|
5
|
+
declare function getBaseURL(url?: string, path?: string, request?: Request, loadEnv?: boolean, trustedProxyHeaders?: boolean | undefined): string | undefined;
|
|
6
|
+
declare function getOrigin(url: string): string | null;
|
|
7
|
+
declare function getProtocol(url: string): string | null;
|
|
8
|
+
declare function getHost(url: string): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Checks if the baseURL config is a dynamic config object
|
|
11
|
+
*/
|
|
12
|
+
declare function isDynamicBaseURLConfig(config: BaseURLConfig | undefined): config is DynamicBaseURLConfig;
|
|
13
|
+
/**
|
|
14
|
+
* Check if a value is a `Request`
|
|
15
|
+
* - `instanceof`: works for native Request instances
|
|
16
|
+
* - `toString`: handles where instanceof check fails but the object is still a
|
|
17
|
+
* valid Request (e.g. cross-realm, polyfills). Paired with a shape check so
|
|
18
|
+
* an object that only spoofs `Symbol.toStringTag` without the real shape is
|
|
19
|
+
* rejected before downstream code tries to read `.headers` / `.url`.
|
|
20
|
+
*
|
|
21
|
+
* @param value The value to check
|
|
22
|
+
* @returns `true` if the value is a Request instance
|
|
23
|
+
*/
|
|
24
|
+
declare function isRequestLike(value: unknown): value is Request;
|
|
25
|
+
/**
|
|
26
|
+
* Extracts the host from a `Request` or `Headers`.
|
|
27
|
+
* Honors `x-forwarded-host` only when `trustedProxyHeaders` is enabled,
|
|
28
|
+
* then falls back to the `host` header and finally the request URL.
|
|
29
|
+
*/
|
|
30
|
+
declare function getHostFromSource(source: Request | Headers, trustedProxyHeaders?: boolean): string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Extracts the protocol from a `Request` or `Headers`.
|
|
33
|
+
* Honors `x-forwarded-proto` only when `trustedProxyHeaders` is enabled,
|
|
34
|
+
* then falls back to the request URL, then to "https".
|
|
35
|
+
*/
|
|
36
|
+
declare function getProtocolFromSource(source: Request | Headers, configProtocol?: "http" | "https" | "auto" | undefined, trustedProxyHeaders?: boolean): "http" | "https";
|
|
37
|
+
/**
|
|
38
|
+
* Matches a hostname against a host pattern.
|
|
39
|
+
* Supports wildcard patterns like `*.vercel.app` or `preview-*.myapp.com`.
|
|
40
|
+
*
|
|
41
|
+
* @param host The hostname to test (e.g., "myapp.com", "preview-123.vercel.app")
|
|
42
|
+
* @param pattern The host pattern (e.g., "myapp.com", "*.vercel.app")
|
|
43
|
+
* @returns {boolean} true if the host matches the pattern, false otherwise.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* matchesHostPattern("myapp.com", "myapp.com") // true
|
|
48
|
+
* matchesHostPattern("preview-123.vercel.app", "*.vercel.app") // true
|
|
49
|
+
* matchesHostPattern("preview-123.myapp.com", "preview-*.myapp.com") // true
|
|
50
|
+
* matchesHostPattern("evil.com", "myapp.com") // false
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
declare const matchesHostPattern: (host: string, pattern: string) => boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Resolves the base URL from a dynamic config based on the incoming request.
|
|
56
|
+
* Validates the derived host against the allowedHosts allowlist.
|
|
57
|
+
*
|
|
58
|
+
* @param config The dynamic base URL config
|
|
59
|
+
* @param request The incoming request
|
|
60
|
+
* @param basePath The base path to append
|
|
61
|
+
* @returns The resolved base URL with path
|
|
62
|
+
* @throws BetterAuthError if host is not in allowedHosts and no fallback is set
|
|
63
|
+
*/
|
|
64
|
+
declare function resolveDynamicBaseURL(config: DynamicBaseURLConfig, source: Request | Headers, basePath: string, trustedProxyHeaders?: boolean): string;
|
|
65
|
+
/**
|
|
66
|
+
* Resolves the base URL from any config type (static string or dynamic object).
|
|
67
|
+
* This is the main entry point for base URL resolution.
|
|
68
|
+
*
|
|
69
|
+
* @param config The base URL config (string or object)
|
|
70
|
+
* @param basePath The base path to append
|
|
71
|
+
* @param request Optional request for dynamic resolution
|
|
72
|
+
* @param loadEnv Whether to load from environment variables
|
|
73
|
+
* @param trustedProxyHeaders Whether to trust proxy headers (for legacy behavior)
|
|
74
|
+
* @returns The resolved base URL with path
|
|
75
|
+
*/
|
|
76
|
+
declare function resolveBaseURL(config: BaseURLConfig | undefined, basePath: string, source?: Request | Headers, loadEnv?: boolean, trustedProxyHeaders?: boolean): string | undefined;
|
|
77
|
+
//#endregion
|
|
78
|
+
export { getBaseURL, getHost, getHostFromSource, getOrigin, getProtocol, getProtocolFromSource, isDynamicBaseURLConfig, isRequestLike, matchesHostPattern, resolveBaseURL, resolveDynamicBaseURL, trimTrailingSlashes };
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { wildcardMatch } from "./wildcard.mjs";
|
|
2
|
+
import { env } from "@better-auth/core/env";
|
|
3
|
+
import { BetterAuthError } from "@better-auth/core/error";
|
|
4
|
+
//#region src/utils/url.ts
|
|
5
|
+
const SLASH_CHAR_CODE = "/".charCodeAt(0);
|
|
6
|
+
/**
|
|
7
|
+
* Minimal loopback check for dev scheme inference only. Reachable from
|
|
8
|
+
* `client/config.ts` via `getBaseURL`, so we MUST NOT import the full
|
|
9
|
+
* `@better-auth/core/utils/host` classifier here: its `utils/ip` dependency
|
|
10
|
+
* on zod would leak into the client bundle (see `e2e/smoke/test/vite.spec.ts`).
|
|
11
|
+
*
|
|
12
|
+
* Server-side SSRF/loopback checks (oauth redirect matching, trusted-origin
|
|
13
|
+
* resolution, electron fetch gate) continue to use the authoritative
|
|
14
|
+
* `isLoopbackHost` from `@better-auth/core/utils/host`. This helper's only
|
|
15
|
+
* job is picking `http` vs `https` for dev ergonomics.
|
|
16
|
+
*/
|
|
17
|
+
function isLoopbackForDevScheme(host) {
|
|
18
|
+
const hostname = host.replace(/:\d+$/, "").replace(/^\[|\]$/g, "").toLowerCase();
|
|
19
|
+
return hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "::1" || hostname.startsWith("127.");
|
|
20
|
+
}
|
|
21
|
+
function trimTrailingSlashes(value) {
|
|
22
|
+
let end = value.length;
|
|
23
|
+
while (end > 0 && value.charCodeAt(end - 1) === SLASH_CHAR_CODE) end--;
|
|
24
|
+
return end === value.length ? value : value.slice(0, end);
|
|
25
|
+
}
|
|
26
|
+
function checkHasPath(url) {
|
|
27
|
+
try {
|
|
28
|
+
return (trimTrailingSlashes(new URL(url).pathname) || "/") !== "/";
|
|
29
|
+
} catch {
|
|
30
|
+
throw new BetterAuthError(`Invalid base URL: ${url}. Please provide a valid base URL.`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function assertHasProtocol(url) {
|
|
34
|
+
try {
|
|
35
|
+
const parsedUrl = new URL(url);
|
|
36
|
+
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new BetterAuthError(`Invalid base URL: ${url}. URL must include 'http://' or 'https://'`);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (error instanceof BetterAuthError) throw error;
|
|
39
|
+
throw new BetterAuthError(`Invalid base URL: ${url}. Please provide a valid base URL.`, { cause: error });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function withPath(url, path = "/api/auth") {
|
|
43
|
+
assertHasProtocol(url);
|
|
44
|
+
if (checkHasPath(url)) return url;
|
|
45
|
+
const trimmedUrl = trimTrailingSlashes(url);
|
|
46
|
+
if (!path || path === "/") return trimmedUrl;
|
|
47
|
+
path = path.startsWith("/") ? path : `/${path}`;
|
|
48
|
+
return `${trimmedUrl}${path}`;
|
|
49
|
+
}
|
|
50
|
+
function validateProxyHeader(header, type) {
|
|
51
|
+
if (!header || header.trim() === "") return false;
|
|
52
|
+
if (type === "proto") return header === "http" || header === "https";
|
|
53
|
+
if (type === "host") {
|
|
54
|
+
if ([
|
|
55
|
+
/\.\./,
|
|
56
|
+
/\0/,
|
|
57
|
+
/[\s]/,
|
|
58
|
+
/^[.]/,
|
|
59
|
+
/[<>'"]/,
|
|
60
|
+
/javascript:/i,
|
|
61
|
+
/file:/i,
|
|
62
|
+
/data:/i
|
|
63
|
+
].some((pattern) => pattern.test(header))) return false;
|
|
64
|
+
return /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*(:[0-9]{1,5})?$/.test(header) || /^(\d{1,3}\.){3}\d{1,3}(:[0-9]{1,5})?$/.test(header) || /^\[[0-9a-fA-F:]+\](:[0-9]{1,5})?$/.test(header) || /^localhost(:[0-9]{1,5})?$/i.test(header);
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
function getBaseURL(url, path, request, loadEnv, trustedProxyHeaders) {
|
|
69
|
+
if (url) return withPath(url, path);
|
|
70
|
+
if (loadEnv !== false) {
|
|
71
|
+
const fromEnv = env.BETTER_AUTH_URL || env.NEXT_PUBLIC_BETTER_AUTH_URL || env.PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_AUTH_URL || (env.BASE_URL !== "/" ? env.BASE_URL : void 0);
|
|
72
|
+
if (fromEnv) return withPath(fromEnv, path);
|
|
73
|
+
}
|
|
74
|
+
const fromRequest = request?.headers.get("x-forwarded-host");
|
|
75
|
+
const fromRequestProto = request?.headers.get("x-forwarded-proto");
|
|
76
|
+
if (fromRequest && fromRequestProto && trustedProxyHeaders) {
|
|
77
|
+
if (validateProxyHeader(fromRequestProto, "proto") && validateProxyHeader(fromRequest, "host")) try {
|
|
78
|
+
return withPath(`${fromRequestProto}://${fromRequest}`, path);
|
|
79
|
+
} catch (_error) {}
|
|
80
|
+
}
|
|
81
|
+
if (request) {
|
|
82
|
+
const url = getOrigin(request.url);
|
|
83
|
+
if (!url) throw new BetterAuthError("Could not get origin from request. Please provide a valid base URL.");
|
|
84
|
+
return withPath(url, path);
|
|
85
|
+
}
|
|
86
|
+
if (typeof window !== "undefined" && window.location) return withPath(window.location.origin, path);
|
|
87
|
+
}
|
|
88
|
+
function getOrigin(url) {
|
|
89
|
+
try {
|
|
90
|
+
const parsedUrl = new URL(url);
|
|
91
|
+
return parsedUrl.origin === "null" ? null : parsedUrl.origin;
|
|
92
|
+
} catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function getProtocol(url) {
|
|
97
|
+
try {
|
|
98
|
+
return new URL(url).protocol;
|
|
99
|
+
} catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function getHost(url) {
|
|
104
|
+
try {
|
|
105
|
+
return new URL(url).host;
|
|
106
|
+
} catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Checks if the baseURL config is a dynamic config object
|
|
112
|
+
*/
|
|
113
|
+
function isDynamicBaseURLConfig(config) {
|
|
114
|
+
return typeof config === "object" && config !== null && "allowedHosts" in config && Array.isArray(config.allowedHosts);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Check if a value is a `Request`
|
|
118
|
+
* - `instanceof`: works for native Request instances
|
|
119
|
+
* - `toString`: handles where instanceof check fails but the object is still a
|
|
120
|
+
* valid Request (e.g. cross-realm, polyfills). Paired with a shape check so
|
|
121
|
+
* an object that only spoofs `Symbol.toStringTag` without the real shape is
|
|
122
|
+
* rejected before downstream code tries to read `.headers` / `.url`.
|
|
123
|
+
*
|
|
124
|
+
* @param value The value to check
|
|
125
|
+
* @returns `true` if the value is a Request instance
|
|
126
|
+
*/
|
|
127
|
+
function isRequestLike(value) {
|
|
128
|
+
if (value instanceof Request) return true;
|
|
129
|
+
if (typeof value !== "object" || value === null || Object.prototype.toString.call(value) !== "[object Request]") return false;
|
|
130
|
+
const v = value;
|
|
131
|
+
return typeof v.url === "string" && typeof v.headers === "object" && v.headers !== null && typeof v.headers.get === "function";
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Extracts the host from a `Request` or `Headers`.
|
|
135
|
+
* Honors `x-forwarded-host` only when `trustedProxyHeaders` is enabled,
|
|
136
|
+
* then falls back to the `host` header and finally the request URL.
|
|
137
|
+
*/
|
|
138
|
+
function getHostFromSource(source, trustedProxyHeaders) {
|
|
139
|
+
const headers = isRequestLike(source) ? source.headers : source;
|
|
140
|
+
if (trustedProxyHeaders) {
|
|
141
|
+
const forwardedHost = headers.get("x-forwarded-host");
|
|
142
|
+
if (forwardedHost && validateProxyHeader(forwardedHost, "host")) return forwardedHost;
|
|
143
|
+
}
|
|
144
|
+
const host = headers.get("host");
|
|
145
|
+
if (host && validateProxyHeader(host, "host")) return host;
|
|
146
|
+
if (isRequestLike(source)) try {
|
|
147
|
+
return new URL(source.url).host;
|
|
148
|
+
} catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Extracts the protocol from a `Request` or `Headers`.
|
|
155
|
+
* Honors `x-forwarded-proto` only when `trustedProxyHeaders` is enabled,
|
|
156
|
+
* then falls back to the request URL, then to "https".
|
|
157
|
+
*/
|
|
158
|
+
function getProtocolFromSource(source, configProtocol, trustedProxyHeaders) {
|
|
159
|
+
if (configProtocol === "http" || configProtocol === "https") return configProtocol;
|
|
160
|
+
const headers = isRequestLike(source) ? source.headers : source;
|
|
161
|
+
if (trustedProxyHeaders) {
|
|
162
|
+
const forwardedProto = headers.get("x-forwarded-proto");
|
|
163
|
+
if (forwardedProto && validateProxyHeader(forwardedProto, "proto")) return forwardedProto;
|
|
164
|
+
}
|
|
165
|
+
if (isRequestLike(source)) try {
|
|
166
|
+
const url = new URL(source.url);
|
|
167
|
+
if (url.protocol === "http:" || url.protocol === "https:") return url.protocol.slice(0, -1);
|
|
168
|
+
} catch {}
|
|
169
|
+
const host = getHostFromSource(source, trustedProxyHeaders);
|
|
170
|
+
if (host && isLoopbackForDevScheme(host)) return "http";
|
|
171
|
+
return "https";
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Matches a hostname against a host pattern.
|
|
175
|
+
* Supports wildcard patterns like `*.vercel.app` or `preview-*.myapp.com`.
|
|
176
|
+
*
|
|
177
|
+
* @param host The hostname to test (e.g., "myapp.com", "preview-123.vercel.app")
|
|
178
|
+
* @param pattern The host pattern (e.g., "myapp.com", "*.vercel.app")
|
|
179
|
+
* @returns {boolean} true if the host matches the pattern, false otherwise.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* matchesHostPattern("myapp.com", "myapp.com") // true
|
|
184
|
+
* matchesHostPattern("preview-123.vercel.app", "*.vercel.app") // true
|
|
185
|
+
* matchesHostPattern("preview-123.myapp.com", "preview-*.myapp.com") // true
|
|
186
|
+
* matchesHostPattern("evil.com", "myapp.com") // false
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
const matchesHostPattern = (host, pattern) => {
|
|
190
|
+
if (!host || !pattern) return false;
|
|
191
|
+
const normalizedHost = host.replace(/^https?:\/\//, "").split("/")[0].toLowerCase();
|
|
192
|
+
const normalizedPattern = pattern.replace(/^https?:\/\//, "").split("/")[0].toLowerCase();
|
|
193
|
+
if (normalizedPattern.includes("*") || normalizedPattern.includes("?")) return wildcardMatch(normalizedPattern)(normalizedHost);
|
|
194
|
+
return normalizedHost.toLowerCase() === normalizedPattern.toLowerCase();
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Resolves the base URL from a dynamic config based on the incoming request.
|
|
198
|
+
* Validates the derived host against the allowedHosts allowlist.
|
|
199
|
+
*
|
|
200
|
+
* @param config The dynamic base URL config
|
|
201
|
+
* @param request The incoming request
|
|
202
|
+
* @param basePath The base path to append
|
|
203
|
+
* @returns The resolved base URL with path
|
|
204
|
+
* @throws BetterAuthError if host is not in allowedHosts and no fallback is set
|
|
205
|
+
*/
|
|
206
|
+
function resolveDynamicBaseURL(config, source, basePath, trustedProxyHeaders) {
|
|
207
|
+
const host = getHostFromSource(source, trustedProxyHeaders);
|
|
208
|
+
if (!host) {
|
|
209
|
+
if (config.fallback) return withPath(config.fallback, basePath);
|
|
210
|
+
throw new BetterAuthError("Could not determine host from request headers. Please provide a fallback URL in your baseURL config.");
|
|
211
|
+
}
|
|
212
|
+
if (config.allowedHosts.some((pattern) => matchesHostPattern(host, pattern))) return withPath(`${getProtocolFromSource(source, config.protocol, trustedProxyHeaders)}://${host}`, basePath);
|
|
213
|
+
if (config.fallback) return withPath(config.fallback, basePath);
|
|
214
|
+
throw new BetterAuthError(`Host "${host}" is not in the allowed hosts list. Allowed hosts: ${config.allowedHosts.join(", ")}. Add this host to your allowedHosts config or provide a fallback URL.`);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Resolves the base URL from any config type (static string or dynamic object).
|
|
218
|
+
* This is the main entry point for base URL resolution.
|
|
219
|
+
*
|
|
220
|
+
* @param config The base URL config (string or object)
|
|
221
|
+
* @param basePath The base path to append
|
|
222
|
+
* @param request Optional request for dynamic resolution
|
|
223
|
+
* @param loadEnv Whether to load from environment variables
|
|
224
|
+
* @param trustedProxyHeaders Whether to trust proxy headers (for legacy behavior)
|
|
225
|
+
* @returns The resolved base URL with path
|
|
226
|
+
*/
|
|
227
|
+
function resolveBaseURL(config, basePath, source, loadEnv, trustedProxyHeaders) {
|
|
228
|
+
if (isDynamicBaseURLConfig(config)) {
|
|
229
|
+
if (source) return resolveDynamicBaseURL(config, source, basePath, trustedProxyHeaders);
|
|
230
|
+
if (config.fallback) return withPath(config.fallback, basePath);
|
|
231
|
+
return getBaseURL(void 0, basePath, void 0, loadEnv, trustedProxyHeaders);
|
|
232
|
+
}
|
|
233
|
+
const request = isRequestLike(source) ? source : void 0;
|
|
234
|
+
if (typeof config === "string") return getBaseURL(config, basePath, request, loadEnv, trustedProxyHeaders);
|
|
235
|
+
return getBaseURL(void 0, basePath, request, loadEnv, trustedProxyHeaders);
|
|
236
|
+
}
|
|
237
|
+
//#endregion
|
|
238
|
+
export { getBaseURL, getHost, getHostFromSource, getOrigin, getProtocol, getProtocolFromSource, isDynamicBaseURLConfig, isRequestLike, matchesHostPattern, resolveBaseURL, resolveDynamicBaseURL, trimTrailingSlashes };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { APIError } from "@better-auth/core/error";
|
|
2
|
+
//#region src/utils/validate-user-info.ts
|
|
3
|
+
function assertValidUserInfoSource(source) {
|
|
4
|
+
if (!source?.method) throw new APIError("FORBIDDEN", {
|
|
5
|
+
code: "validation_source_missing",
|
|
6
|
+
message: "User validation source is required"
|
|
7
|
+
});
|
|
8
|
+
if (source.method === "oauth" && !source.oauth?.providerId) throw new APIError("FORBIDDEN", {
|
|
9
|
+
code: "validation_source_missing",
|
|
10
|
+
message: "OAuth user validation source requires oauth.providerId"
|
|
11
|
+
});
|
|
12
|
+
if ((source.method === "sso-oidc" || source.method === "sso-saml") && !source.sso?.providerId) throw new APIError("FORBIDDEN", {
|
|
13
|
+
code: "validation_source_missing",
|
|
14
|
+
message: "SSO user validation source requires sso.providerId"
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Invoke the application's `user.validateUserInfo` gate and throw a `403`
|
|
19
|
+
* {@link APIError} if it rejects.
|
|
20
|
+
*
|
|
21
|
+
* Fails closed: if the hook throws, provisioning is rejected rather than
|
|
22
|
+
* silently allowed.
|
|
23
|
+
*/
|
|
24
|
+
async function assertValidUserInfo(ctx, data) {
|
|
25
|
+
const validate = ctx.context.options.user?.validateUserInfo;
|
|
26
|
+
if (!validate) return;
|
|
27
|
+
assertValidUserInfoSource(data.source);
|
|
28
|
+
let result;
|
|
29
|
+
try {
|
|
30
|
+
result = await validate(data, ctx);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
ctx.context.logger.error("validateUserInfo callback threw", error);
|
|
33
|
+
throw new APIError("FORBIDDEN", {
|
|
34
|
+
code: "validation_failed",
|
|
35
|
+
message: "User validation failed"
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (result?.error) throw new APIError("FORBIDDEN", {
|
|
39
|
+
code: result.error,
|
|
40
|
+
message: result.errorDescription || result.error
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { assertValidUserInfo, assertValidUserInfoSource };
|