@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,21 @@
|
|
|
1
|
+
import { User } from "../types/models.mjs";
|
|
2
|
+
import { GenericEndpointContext } from "@better-auth/core";
|
|
3
|
+
|
|
4
|
+
//#region src/db/revoke-unproven-account-access.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Strip every account link and session a pre-existing account accrued before
|
|
7
|
+
* control of its email was proven.
|
|
8
|
+
*
|
|
9
|
+
* An `emailVerified: false` row carries no proof that linked access belongs
|
|
10
|
+
* to the mailbox owner. When an email-primary proof (magic link, email OTP)
|
|
11
|
+
* resolves to such a row, deleting accounts and revoking standing sessions
|
|
12
|
+
* makes the verified owner inherit no password, OAuth link, or session that
|
|
13
|
+
* predates the proof. This helper also flips `emailVerified` after cleanup and
|
|
14
|
+
* returns the current user for the caller to use when minting the owner's
|
|
15
|
+
* session.
|
|
16
|
+
*
|
|
17
|
+
* @param userId - The pre-existing, not-yet-verified user being promoted.
|
|
18
|
+
*/
|
|
19
|
+
declare function revokeUnprovenAccountAccess(ctx: GenericEndpointContext, userId: string): Promise<User | null>;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { revokeUnprovenAccountAccess };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { BetterAuthError } from "@better-auth/core/error";
|
|
2
|
+
//#region src/db/revoke-unproven-account-access.ts
|
|
3
|
+
const cleanupLockExpiresInMs = 5e3;
|
|
4
|
+
const cleanupLockWaitMs = 2e3;
|
|
5
|
+
const cleanupLockPollMs = 250;
|
|
6
|
+
const cleanupLockIdentifier = (userId) => `revoke-unproven-account-access:${userId}`;
|
|
7
|
+
async function waitForCleanupLock(ctx, identifier) {
|
|
8
|
+
const deadline = Date.now() + cleanupLockWaitMs;
|
|
9
|
+
while (Date.now() < deadline) {
|
|
10
|
+
const lock = await ctx.context.internalAdapter.findVerificationValue(identifier);
|
|
11
|
+
if (!lock) return;
|
|
12
|
+
if (lock.expiresAt <= /* @__PURE__ */ new Date()) {
|
|
13
|
+
await ctx.context.internalAdapter.deleteVerificationByIdentifier(identifier);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
await new Promise((resolve) => setTimeout(resolve, cleanupLockPollMs));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Strip every account link and session a pre-existing account accrued before
|
|
21
|
+
* control of its email was proven.
|
|
22
|
+
*
|
|
23
|
+
* An `emailVerified: false` row carries no proof that linked access belongs
|
|
24
|
+
* to the mailbox owner. When an email-primary proof (magic link, email OTP)
|
|
25
|
+
* resolves to such a row, deleting accounts and revoking standing sessions
|
|
26
|
+
* makes the verified owner inherit no password, OAuth link, or session that
|
|
27
|
+
* predates the proof. This helper also flips `emailVerified` after cleanup and
|
|
28
|
+
* returns the current user for the caller to use when minting the owner's
|
|
29
|
+
* session.
|
|
30
|
+
*
|
|
31
|
+
* @param userId - The pre-existing, not-yet-verified user being promoted.
|
|
32
|
+
*/
|
|
33
|
+
async function revokeUnprovenAccountAccess(ctx, userId) {
|
|
34
|
+
const lockIdentifier = cleanupLockIdentifier(userId);
|
|
35
|
+
if (!await ctx.context.internalAdapter.reserveVerificationValue({
|
|
36
|
+
identifier: lockIdentifier,
|
|
37
|
+
value: userId,
|
|
38
|
+
expiresAt: new Date(Date.now() + cleanupLockExpiresInMs)
|
|
39
|
+
}).catch((error) => {
|
|
40
|
+
if (error instanceof BetterAuthError && error.message.includes("requires database-backed verification storage")) return true;
|
|
41
|
+
throw error;
|
|
42
|
+
})) {
|
|
43
|
+
await waitForCleanupLock(ctx, lockIdentifier);
|
|
44
|
+
return ctx.context.internalAdapter.findUserById(userId);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const user = await ctx.context.internalAdapter.findUserById(userId);
|
|
48
|
+
if (!user || user.emailVerified) return user;
|
|
49
|
+
const accounts = await ctx.context.internalAdapter.findAccounts(userId);
|
|
50
|
+
for (const account of accounts) await ctx.context.internalAdapter.deleteAccount(account.id);
|
|
51
|
+
await ctx.context.internalAdapter.deleteUserSessions(userId);
|
|
52
|
+
return await ctx.context.internalAdapter.updateUser(userId, { emailVerified: true });
|
|
53
|
+
} finally {
|
|
54
|
+
await ctx.context.internalAdapter.deleteVerificationByIdentifier(lockIdentifier).catch(() => {});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { revokeUnprovenAccountAccess };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Account, Session as Session$1, User as User$1 } from "../types/models.mjs";
|
|
2
|
+
import { BetterAuthOptions } from "@better-auth/core";
|
|
3
|
+
import { BetterAuthPluginDBSchema, DBFieldAttribute } from "@better-auth/core/db";
|
|
4
|
+
|
|
5
|
+
//#region src/db/schema.d.ts
|
|
6
|
+
declare function parseUserOutput<T extends User$1>(options: BetterAuthOptions, user: T): T;
|
|
7
|
+
/**
|
|
8
|
+
* Builds a synthetic user object that matches the shape of a real user
|
|
9
|
+
* returned from the database. This ensures enumeration protection works
|
|
10
|
+
* correctly by making synthetic and real user responses indistinguishable.
|
|
11
|
+
*
|
|
12
|
+
* The function iterates over the user output schema and:
|
|
13
|
+
* - Includes all fields that should be returned (returned !== false)
|
|
14
|
+
* - Uses provided values when available
|
|
15
|
+
* - Sets optional fields to null when no value is provided
|
|
16
|
+
* - Applies default values where defined
|
|
17
|
+
* - Always includes the 'id' field (not part of schema but always present)
|
|
18
|
+
*/
|
|
19
|
+
declare function buildSyntheticUserOutput(options: BetterAuthOptions, data: Record<string, unknown>): Record<string, unknown>;
|
|
20
|
+
declare function parseSessionOutput<T extends Session$1>(options: BetterAuthOptions, session: T): T;
|
|
21
|
+
declare function parseAccountOutput<T extends Account>(options: BetterAuthOptions, account: T): Omit<T, "idToken" | "accessToken" | "refreshToken" | "accessTokenExpiresAt" | "refreshTokenExpiresAt" | "password">;
|
|
22
|
+
declare function parseInputData<T extends Record<string, any>>(data: T, schema: {
|
|
23
|
+
fields: Record<string, DBFieldAttribute>;
|
|
24
|
+
action?: ("create" | "update") | undefined;
|
|
25
|
+
}): Partial<T>;
|
|
26
|
+
declare function parseUserInput(options: BetterAuthOptions, user: Record<string, any> | undefined, action: "create" | "update"): Partial<Record<string, any>>;
|
|
27
|
+
declare function parseAdditionalUserInputFromProviderProfile(options: BetterAuthOptions, profile: Record<string, unknown> | undefined, action: "create" | "update"): Partial<Record<string, unknown>>;
|
|
28
|
+
declare function parseAdditionalUserInput(options: BetterAuthOptions, user?: Record<string, any> | undefined): Partial<Record<string, any>>;
|
|
29
|
+
declare function parseAccountInput(options: BetterAuthOptions, account: Partial<Account>): Partial<Partial<{
|
|
30
|
+
id: string;
|
|
31
|
+
createdAt: Date;
|
|
32
|
+
updatedAt: Date;
|
|
33
|
+
providerId: string;
|
|
34
|
+
accountId: string;
|
|
35
|
+
userId: string;
|
|
36
|
+
accessToken?: string | null | undefined;
|
|
37
|
+
refreshToken?: string | null | undefined;
|
|
38
|
+
idToken?: string | null | undefined;
|
|
39
|
+
accessTokenExpiresAt?: Date | null | undefined;
|
|
40
|
+
refreshTokenExpiresAt?: Date | null | undefined;
|
|
41
|
+
scope?: string | null | undefined;
|
|
42
|
+
password?: string | null | undefined;
|
|
43
|
+
}>>;
|
|
44
|
+
declare function parseSessionInput(options: BetterAuthOptions, session: Partial<Session$1>, action?: "create" | "update"): Partial<Partial<{
|
|
45
|
+
id: string;
|
|
46
|
+
createdAt: Date;
|
|
47
|
+
updatedAt: Date;
|
|
48
|
+
userId: string;
|
|
49
|
+
expiresAt: Date;
|
|
50
|
+
token: string;
|
|
51
|
+
ipAddress?: string | null | undefined;
|
|
52
|
+
userAgent?: string | null | undefined;
|
|
53
|
+
}>>;
|
|
54
|
+
declare function getSessionDefaultFields(options: BetterAuthOptions): Record<string, any>;
|
|
55
|
+
declare function mergeSchema<S extends BetterAuthPluginDBSchema>(schema: S, newSchema?: { [K in keyof S]?: {
|
|
56
|
+
modelName?: string | undefined;
|
|
57
|
+
fields?: {
|
|
58
|
+
[P: string]: string;
|
|
59
|
+
} | undefined;
|
|
60
|
+
} | undefined } | undefined): S;
|
|
61
|
+
//#endregion
|
|
62
|
+
export { buildSyntheticUserOutput, getSessionDefaultFields, mergeSchema, parseAccountInput, parseAccountOutput, parseAdditionalUserInput, parseAdditionalUserInputFromProviderProfile, parseInputData, parseSessionInput, parseSessionOutput, parseUserInput, parseUserOutput };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { getAuthTables } from "@better-auth/core/db";
|
|
2
|
+
import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
3
|
+
import { filterOutputFields } from "@better-auth/core/utils/db";
|
|
4
|
+
//#region src/db/schema.ts
|
|
5
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
function getFields(options, modelName, mode) {
|
|
7
|
+
const cacheKey = `${modelName}:${mode}`;
|
|
8
|
+
if (!cache.has(options)) cache.set(options, /* @__PURE__ */ new Map());
|
|
9
|
+
const tableCache = cache.get(options);
|
|
10
|
+
if (tableCache.has(cacheKey)) return tableCache.get(cacheKey);
|
|
11
|
+
const coreSchema = mode === "output" ? getAuthTables(options)[modelName]?.fields ?? {} : {};
|
|
12
|
+
const additionalFields = modelName === "user" || modelName === "session" || modelName === "account" ? options[modelName]?.additionalFields : void 0;
|
|
13
|
+
let schema = {
|
|
14
|
+
...coreSchema,
|
|
15
|
+
...additionalFields ?? {}
|
|
16
|
+
};
|
|
17
|
+
for (const plugin of options.plugins || []) if (plugin.schema && plugin.schema[modelName]) schema = {
|
|
18
|
+
...schema,
|
|
19
|
+
...plugin.schema[modelName].fields
|
|
20
|
+
};
|
|
21
|
+
tableCache.set(cacheKey, schema);
|
|
22
|
+
return schema;
|
|
23
|
+
}
|
|
24
|
+
function parseUserOutput(options, user) {
|
|
25
|
+
return filterOutputFields(user, getFields(options, "user", "output"));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Builds a synthetic user object that matches the shape of a real user
|
|
29
|
+
* returned from the database. This ensures enumeration protection works
|
|
30
|
+
* correctly by making synthetic and real user responses indistinguishable.
|
|
31
|
+
*
|
|
32
|
+
* The function iterates over the user output schema and:
|
|
33
|
+
* - Includes all fields that should be returned (returned !== false)
|
|
34
|
+
* - Uses provided values when available
|
|
35
|
+
* - Sets optional fields to null when no value is provided
|
|
36
|
+
* - Applies default values where defined
|
|
37
|
+
* - Always includes the 'id' field (not part of schema but always present)
|
|
38
|
+
*/
|
|
39
|
+
function buildSyntheticUserOutput(options, data) {
|
|
40
|
+
const schema = getFields(options, "user", "output");
|
|
41
|
+
const result = {};
|
|
42
|
+
for (const key in schema) {
|
|
43
|
+
const fieldAttr = schema[key];
|
|
44
|
+
if (fieldAttr.returned === false) continue;
|
|
45
|
+
if (key in data && data[key] !== void 0) result[key] = data[key];
|
|
46
|
+
else if (fieldAttr.defaultValue !== void 0) result[key] = typeof fieldAttr.defaultValue === "function" ? fieldAttr.defaultValue() : fieldAttr.defaultValue;
|
|
47
|
+
else if (!fieldAttr.required) result[key] = null;
|
|
48
|
+
}
|
|
49
|
+
if ("id" in data) result.id = data.id;
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
function parseSessionOutput(options, session) {
|
|
53
|
+
return filterOutputFields(session, getFields(options, "session", "output"));
|
|
54
|
+
}
|
|
55
|
+
function parseAccountOutput(options, account) {
|
|
56
|
+
const { accessToken: _accessToken, refreshToken: _refreshToken, idToken: _idToken, accessTokenExpiresAt: _accessTokenExpiresAt, refreshTokenExpiresAt: _refreshTokenExpiresAt, password: _password, ...rest } = filterOutputFields(account, getFields(options, "account", "output"));
|
|
57
|
+
return rest;
|
|
58
|
+
}
|
|
59
|
+
function parseInputData(data, schema) {
|
|
60
|
+
const action = schema.action || "create";
|
|
61
|
+
const fields = schema.fields;
|
|
62
|
+
const parsedData = Object.create(null);
|
|
63
|
+
for (const key in fields) {
|
|
64
|
+
if (key in data) {
|
|
65
|
+
if (fields[key].input === false) {
|
|
66
|
+
if (fields[key].defaultValue !== void 0) {
|
|
67
|
+
if (action !== "update") {
|
|
68
|
+
parsedData[key] = fields[key].defaultValue;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (data[key]) throw APIError.from("BAD_REQUEST", {
|
|
73
|
+
...BASE_ERROR_CODES.FIELD_NOT_ALLOWED,
|
|
74
|
+
message: `${key} is not allowed to be set`
|
|
75
|
+
});
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (fields[key].validator?.input && data[key] !== void 0) {
|
|
79
|
+
const result = fields[key].validator.input["~standard"].validate(data[key]);
|
|
80
|
+
if (result instanceof Promise) throw APIError.from("INTERNAL_SERVER_ERROR", BASE_ERROR_CODES.ASYNC_VALIDATION_NOT_SUPPORTED);
|
|
81
|
+
if ("issues" in result && result.issues) throw APIError.from("BAD_REQUEST", {
|
|
82
|
+
...BASE_ERROR_CODES.VALIDATION_ERROR,
|
|
83
|
+
message: result.issues[0]?.message || "Validation Error"
|
|
84
|
+
});
|
|
85
|
+
parsedData[key] = result.value;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (fields[key].transform?.input && data[key] !== void 0) {
|
|
89
|
+
parsedData[key] = fields[key].transform?.input(data[key]);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
parsedData[key] = data[key];
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (fields[key].defaultValue !== void 0 && action === "create") {
|
|
96
|
+
if (typeof fields[key].defaultValue === "function") {
|
|
97
|
+
parsedData[key] = fields[key].defaultValue();
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
parsedData[key] = fields[key].defaultValue;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (fields[key].required && action === "create") throw APIError.from("BAD_REQUEST", {
|
|
104
|
+
...BASE_ERROR_CODES.MISSING_FIELD,
|
|
105
|
+
message: `${key} is required`
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return parsedData;
|
|
109
|
+
}
|
|
110
|
+
function parseUserInput(options, user = {}, action) {
|
|
111
|
+
return parseInputData(user, {
|
|
112
|
+
fields: getFields(options, "user", "input"),
|
|
113
|
+
action
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function parseAdditionalUserInputFromProviderProfile(options, profile = {}, action) {
|
|
117
|
+
const schema = getFields(options, "user", "input");
|
|
118
|
+
const allowedProfileFields = Object.create(null);
|
|
119
|
+
for (const key of Object.keys(profile)) {
|
|
120
|
+
if (schema[key]?.input === false) continue;
|
|
121
|
+
allowedProfileFields[key] = profile[key];
|
|
122
|
+
}
|
|
123
|
+
return parseInputData(allowedProfileFields, {
|
|
124
|
+
fields: schema,
|
|
125
|
+
action
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function parseAdditionalUserInput(options, user) {
|
|
129
|
+
const schema = getFields(options, "user", "input");
|
|
130
|
+
return parseInputData(user || {}, { fields: schema });
|
|
131
|
+
}
|
|
132
|
+
function parseAccountInput(options, account) {
|
|
133
|
+
return parseInputData(account, { fields: getFields(options, "account", "input") });
|
|
134
|
+
}
|
|
135
|
+
function parseSessionInput(options, session, action) {
|
|
136
|
+
return parseInputData(session, {
|
|
137
|
+
fields: getFields(options, "session", "input"),
|
|
138
|
+
action
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function getSessionDefaultFields(options) {
|
|
142
|
+
const fields = getFields(options, "session", "input");
|
|
143
|
+
const defaults = {};
|
|
144
|
+
for (const key in fields) if (fields[key].defaultValue !== void 0) defaults[key] = typeof fields[key].defaultValue === "function" ? fields[key].defaultValue() : fields[key].defaultValue;
|
|
145
|
+
return defaults;
|
|
146
|
+
}
|
|
147
|
+
function mergeSchema(schema, newSchema) {
|
|
148
|
+
if (!newSchema) return schema;
|
|
149
|
+
for (const table in newSchema) {
|
|
150
|
+
const newModelName = newSchema[table]?.modelName;
|
|
151
|
+
if (newModelName) schema[table].modelName = newModelName;
|
|
152
|
+
for (const field in schema[table].fields) {
|
|
153
|
+
const newField = newSchema[table]?.fields?.[field];
|
|
154
|
+
if (!newField) continue;
|
|
155
|
+
schema[table].fields[field].fieldName = newField;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return schema;
|
|
159
|
+
}
|
|
160
|
+
//#endregion
|
|
161
|
+
export { buildSyntheticUserOutput, getSessionDefaultFields, mergeSchema, parseAccountInput, parseAccountOutput, parseAdditionalUserInput, parseAdditionalUserInputFromProviderProfile, parseInputData, parseSessionInput, parseSessionOutput, parseUserInput, parseUserOutput };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { DBFieldAttribute } from "@better-auth/core/db";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/db/to-zod.d.ts
|
|
5
|
+
declare function toZodSchema<Fields extends Record<string, DBFieldAttribute | never>, IsClientSide extends boolean>({
|
|
6
|
+
fields,
|
|
7
|
+
isClientSide
|
|
8
|
+
}: {
|
|
9
|
+
fields: Fields;
|
|
10
|
+
/**
|
|
11
|
+
* If true, then any fields that have `input: false` will be removed from the schema to prevent user input.
|
|
12
|
+
*/
|
|
13
|
+
isClientSide: IsClientSide;
|
|
14
|
+
}): z.ZodObject<RemoveNeverProps<{ [key in keyof Fields]: FieldAttributeToSchema<Fields[key], IsClientSide> }>, z.core.$strip>;
|
|
15
|
+
type FieldAttributeToSchema<Field extends DBFieldAttribute | Record<string, never>, isClientSide extends boolean = false> = Field extends {
|
|
16
|
+
type: any;
|
|
17
|
+
} ? GetInput<isClientSide, Field, GetRequired<Field, GetType<Field>>> : Record<string, never>;
|
|
18
|
+
type GetType<F extends DBFieldAttribute> = F extends {
|
|
19
|
+
type: "string";
|
|
20
|
+
} ? z.ZodString : F extends {
|
|
21
|
+
type: "number";
|
|
22
|
+
} ? z.ZodNumber : F extends {
|
|
23
|
+
type: "boolean";
|
|
24
|
+
} ? z.ZodBoolean : F extends {
|
|
25
|
+
type: "date";
|
|
26
|
+
} ? z.ZodDate : z.ZodAny;
|
|
27
|
+
type GetRequired<F extends DBFieldAttribute, Schema extends z.core.SomeType> = F extends {
|
|
28
|
+
required: false;
|
|
29
|
+
} ? z.ZodOptional<z.ZodNullable<Schema>> : Schema;
|
|
30
|
+
type GetInput<isClientSide extends boolean, Field extends DBFieldAttribute, Schema extends z.core.SomeType> = Field extends {
|
|
31
|
+
input: false;
|
|
32
|
+
} ? isClientSide extends true ? never : Schema : Schema;
|
|
33
|
+
type RemoveNeverProps<T> = { [K in keyof T as [T[K]] extends [never] ? never : K]: T[K] };
|
|
34
|
+
//#endregion
|
|
35
|
+
export { FieldAttributeToSchema, toZodSchema };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
//#region src/db/to-zod.ts
|
|
3
|
+
function toZodSchema({ fields, isClientSide }) {
|
|
4
|
+
const zodFields = Object.keys(fields).reduce((acc, key) => {
|
|
5
|
+
const field = fields[key];
|
|
6
|
+
if (!field) return acc;
|
|
7
|
+
if (isClientSide && field.input === false) return acc;
|
|
8
|
+
let schema;
|
|
9
|
+
if (field.type === "json") schema = z.json ? z.json() : z.any();
|
|
10
|
+
else if (field.type === "string[]" || field.type === "number[]") schema = z.array(field.type === "string[]" ? z.string() : z.number());
|
|
11
|
+
else if (Array.isArray(field.type)) schema = z.any();
|
|
12
|
+
else schema = z[field.type]();
|
|
13
|
+
if (field?.required === false) schema = schema.nullish();
|
|
14
|
+
if (!isClientSide && field?.returned === false) return acc;
|
|
15
|
+
return {
|
|
16
|
+
...acc,
|
|
17
|
+
[key]: schema
|
|
18
|
+
};
|
|
19
|
+
}, {});
|
|
20
|
+
return z.object(zodFields);
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { toZodSchema };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { base64Url } from "@better-auth/utils/base64";
|
|
2
|
+
import { createHash } from "@better-auth/utils/hash";
|
|
3
|
+
//#region src/db/verification-token-storage.ts
|
|
4
|
+
const defaultKeyHasher = async (identifier) => {
|
|
5
|
+
const hash = await createHash("SHA-256").digest(new TextEncoder().encode(identifier));
|
|
6
|
+
return base64Url.encode(new Uint8Array(hash), { padding: false });
|
|
7
|
+
};
|
|
8
|
+
async function processIdentifier(identifier, option) {
|
|
9
|
+
if (!option || option === "plain") return identifier;
|
|
10
|
+
if (option === "hashed") return defaultKeyHasher(identifier);
|
|
11
|
+
if (typeof option === "object" && "hash" in option) return option.hash(identifier);
|
|
12
|
+
return identifier;
|
|
13
|
+
}
|
|
14
|
+
function getStorageOption(identifier, config) {
|
|
15
|
+
if (!config) return;
|
|
16
|
+
if (typeof config === "object" && "default" in config) {
|
|
17
|
+
if (config.overrides) {
|
|
18
|
+
for (const [prefix, option] of Object.entries(config.overrides)) if (identifier.startsWith(prefix)) return option;
|
|
19
|
+
}
|
|
20
|
+
return config.default;
|
|
21
|
+
}
|
|
22
|
+
return config;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { getStorageOption, processIdentifier };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BetterAuthOptions } from "@better-auth/core";
|
|
2
|
+
import { BaseModelNames } from "@better-auth/core/db";
|
|
3
|
+
import { DBAdapter, Where } from "@better-auth/core/db/adapter";
|
|
4
|
+
|
|
5
|
+
//#region src/db/with-hooks.d.ts
|
|
6
|
+
type DatabaseHooksEntry = {
|
|
7
|
+
source: string;
|
|
8
|
+
hooks: Exclude<BetterAuthOptions["databaseHooks"], undefined>;
|
|
9
|
+
};
|
|
10
|
+
declare function getWithHooks(adapter: DBAdapter<BetterAuthOptions>, ctx: {
|
|
11
|
+
options: BetterAuthOptions;
|
|
12
|
+
hooks: DatabaseHooksEntry[];
|
|
13
|
+
}): {
|
|
14
|
+
createWithHooks: <T extends Record<string, any>>(data: T, model: BaseModelNames, customCreateFn?: {
|
|
15
|
+
fn: (data: Record<string, any>) => void | Promise<any>;
|
|
16
|
+
executeMainFn?: boolean;
|
|
17
|
+
} | undefined) => Promise<any>;
|
|
18
|
+
updateWithHooks: <T extends Record<string, any>>(data: any, where: Where[], model: BaseModelNames, customUpdateFn?: {
|
|
19
|
+
fn: (data: Record<string, any>) => void | Promise<any>;
|
|
20
|
+
executeMainFn?: boolean;
|
|
21
|
+
} | undefined) => Promise<any>;
|
|
22
|
+
updateManyWithHooks: <_T extends Record<string, any>>(data: any, where: Where[], model: BaseModelNames, customUpdateFn?: {
|
|
23
|
+
fn: (data: Record<string, any>) => void | Promise<any>;
|
|
24
|
+
executeMainFn?: boolean;
|
|
25
|
+
} | undefined) => Promise<any>;
|
|
26
|
+
deleteWithHooks: <T extends Record<string, any>>(where: Where[], model: BaseModelNames, customDeleteFn?: {
|
|
27
|
+
fn: (where: Where[]) => void | Promise<any>;
|
|
28
|
+
executeMainFn?: boolean;
|
|
29
|
+
} | undefined) => Promise<any>;
|
|
30
|
+
deleteManyWithHooks: <T extends Record<string, any>>(where: Where[], model: BaseModelNames, customDeleteFn?: {
|
|
31
|
+
fn: (where: Where[]) => void | Promise<any>;
|
|
32
|
+
executeMainFn?: boolean;
|
|
33
|
+
} | undefined) => Promise<any>;
|
|
34
|
+
consumeOneWithHooks: <T extends Record<string, any>>(model: BaseModelNames, hookWhere: Where[], consumeFn: () => Promise<T | null>, preSnapshot?: T | null) => Promise<T | null>;
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
export { DatabaseHooksEntry, getWithHooks };
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { getCurrentAdapter, queueAfterTransactionHook, tryGetCurrentAuthEndpointContext } from "@better-auth/core/context";
|
|
2
|
+
import { ATTR_CONTEXT, ATTR_DB_COLLECTION_NAME, ATTR_HOOK_TYPE, createWithSpan } from "@better-auth/core/instrumentation";
|
|
3
|
+
//#region src/db/with-hooks.ts
|
|
4
|
+
function getWithHooks(adapter, ctx) {
|
|
5
|
+
const withSpan = createWithSpan(ctx.options);
|
|
6
|
+
const hooksEntries = ctx.hooks;
|
|
7
|
+
async function createWithHooks(data, model, customCreateFn) {
|
|
8
|
+
const context = tryGetCurrentAuthEndpointContext();
|
|
9
|
+
let actualData = data;
|
|
10
|
+
for (const { source, hooks } of hooksEntries) {
|
|
11
|
+
const toRun = hooks[model]?.create?.before;
|
|
12
|
+
if (toRun) {
|
|
13
|
+
const result = await withSpan(`db create.before ${model}`, {
|
|
14
|
+
[ATTR_HOOK_TYPE]: "create.before",
|
|
15
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
16
|
+
[ATTR_CONTEXT]: source
|
|
17
|
+
}, () => toRun(actualData, context));
|
|
18
|
+
if (result === false) return null;
|
|
19
|
+
if (typeof result === "object" && "data" in result) actualData = {
|
|
20
|
+
...actualData,
|
|
21
|
+
...result.data
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
let created = null;
|
|
26
|
+
if (!customCreateFn || customCreateFn.executeMainFn) created = await (await getCurrentAdapter(adapter)).create({
|
|
27
|
+
model,
|
|
28
|
+
data: actualData,
|
|
29
|
+
forceAllowId: true
|
|
30
|
+
});
|
|
31
|
+
if (customCreateFn?.fn) created = await customCreateFn.fn(created ?? actualData);
|
|
32
|
+
for (const { source, hooks } of hooksEntries) {
|
|
33
|
+
const toRun = hooks[model]?.create?.after;
|
|
34
|
+
if (toRun) await queueAfterTransactionHook(async () => {
|
|
35
|
+
await withSpan(`db create.after ${model}`, {
|
|
36
|
+
[ATTR_HOOK_TYPE]: "create.after",
|
|
37
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
38
|
+
[ATTR_CONTEXT]: source
|
|
39
|
+
}, () => toRun(created, context));
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return created;
|
|
43
|
+
}
|
|
44
|
+
async function updateWithHooks(data, where, model, customUpdateFn) {
|
|
45
|
+
const context = tryGetCurrentAuthEndpointContext();
|
|
46
|
+
let actualData = data;
|
|
47
|
+
for (const { source, hooks } of hooksEntries) {
|
|
48
|
+
const toRun = hooks[model]?.update?.before;
|
|
49
|
+
if (toRun) {
|
|
50
|
+
const result = await withSpan(`db update.before ${model}`, {
|
|
51
|
+
[ATTR_HOOK_TYPE]: "update.before",
|
|
52
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
53
|
+
[ATTR_CONTEXT]: source
|
|
54
|
+
}, () => toRun(data, context));
|
|
55
|
+
if (result === false) return null;
|
|
56
|
+
if (typeof result === "object" && "data" in result) actualData = {
|
|
57
|
+
...actualData,
|
|
58
|
+
...result.data
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const customUpdated = customUpdateFn ? await customUpdateFn.fn(actualData) : null;
|
|
63
|
+
const updated = !customUpdateFn || customUpdateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).update({
|
|
64
|
+
model,
|
|
65
|
+
update: actualData,
|
|
66
|
+
where
|
|
67
|
+
}) : customUpdated;
|
|
68
|
+
for (const { source, hooks } of hooksEntries) {
|
|
69
|
+
const toRun = hooks[model]?.update?.after;
|
|
70
|
+
if (toRun) await queueAfterTransactionHook(async () => {
|
|
71
|
+
await withSpan(`db update.after ${model}`, {
|
|
72
|
+
[ATTR_HOOK_TYPE]: "update.after",
|
|
73
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
74
|
+
[ATTR_CONTEXT]: source
|
|
75
|
+
}, () => toRun(updated, context));
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return updated;
|
|
79
|
+
}
|
|
80
|
+
async function updateManyWithHooks(data, where, model, customUpdateFn) {
|
|
81
|
+
const context = tryGetCurrentAuthEndpointContext();
|
|
82
|
+
let actualData = data;
|
|
83
|
+
for (const { source, hooks } of hooksEntries) {
|
|
84
|
+
const toRun = hooks[model]?.update?.before;
|
|
85
|
+
if (toRun) {
|
|
86
|
+
const result = await withSpan(`db updateMany.before ${model}`, {
|
|
87
|
+
[ATTR_HOOK_TYPE]: "updateMany.before",
|
|
88
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
89
|
+
[ATTR_CONTEXT]: source
|
|
90
|
+
}, () => toRun(data, context));
|
|
91
|
+
if (result === false) return null;
|
|
92
|
+
if (typeof result === "object" && "data" in result) actualData = {
|
|
93
|
+
...actualData,
|
|
94
|
+
...result.data
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const customUpdated = customUpdateFn ? await customUpdateFn.fn(actualData) : null;
|
|
99
|
+
const updated = !customUpdateFn || customUpdateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).updateMany({
|
|
100
|
+
model,
|
|
101
|
+
update: actualData,
|
|
102
|
+
where
|
|
103
|
+
}) : customUpdated;
|
|
104
|
+
for (const { source, hooks } of hooksEntries) {
|
|
105
|
+
const toRun = hooks[model]?.update?.after;
|
|
106
|
+
if (toRun) await queueAfterTransactionHook(async () => {
|
|
107
|
+
await withSpan(`db updateMany.after ${model}`, {
|
|
108
|
+
[ATTR_HOOK_TYPE]: "updateMany.after",
|
|
109
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
110
|
+
[ATTR_CONTEXT]: source
|
|
111
|
+
}, () => toRun(updated, context));
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return updated;
|
|
115
|
+
}
|
|
116
|
+
async function deleteWithHooks(where, model, customDeleteFn) {
|
|
117
|
+
const context = tryGetCurrentAuthEndpointContext();
|
|
118
|
+
let entityToDelete = null;
|
|
119
|
+
try {
|
|
120
|
+
entityToDelete = (await (await getCurrentAdapter(adapter)).findMany({
|
|
121
|
+
model,
|
|
122
|
+
where,
|
|
123
|
+
limit: 1
|
|
124
|
+
}))[0] || null;
|
|
125
|
+
} catch {}
|
|
126
|
+
if (entityToDelete) for (const { source, hooks } of hooksEntries) {
|
|
127
|
+
const toRun = hooks[model]?.delete?.before;
|
|
128
|
+
if (toRun) {
|
|
129
|
+
if (await withSpan(`db delete.before ${model}`, {
|
|
130
|
+
[ATTR_HOOK_TYPE]: "delete.before",
|
|
131
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
132
|
+
[ATTR_CONTEXT]: source
|
|
133
|
+
}, () => toRun(entityToDelete, context)) === false) return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const customDeleted = customDeleteFn ? await customDeleteFn.fn(where) : null;
|
|
137
|
+
const deleted = (!customDeleteFn || customDeleteFn.executeMainFn) && entityToDelete ? await (await getCurrentAdapter(adapter)).delete({
|
|
138
|
+
model,
|
|
139
|
+
where
|
|
140
|
+
}) : customDeleted;
|
|
141
|
+
if (entityToDelete) for (const { source, hooks } of hooksEntries) {
|
|
142
|
+
const toRun = hooks[model]?.delete?.after;
|
|
143
|
+
if (toRun) await queueAfterTransactionHook(async () => {
|
|
144
|
+
await withSpan(`db delete.after ${model}`, {
|
|
145
|
+
[ATTR_HOOK_TYPE]: "delete.after",
|
|
146
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
147
|
+
[ATTR_CONTEXT]: source
|
|
148
|
+
}, () => toRun(entityToDelete, context));
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return deleted;
|
|
152
|
+
}
|
|
153
|
+
async function deleteManyWithHooks(where, model, customDeleteFn) {
|
|
154
|
+
const context = tryGetCurrentAuthEndpointContext();
|
|
155
|
+
let entitiesToDelete = [];
|
|
156
|
+
try {
|
|
157
|
+
entitiesToDelete = await (await getCurrentAdapter(adapter)).findMany({
|
|
158
|
+
model,
|
|
159
|
+
where
|
|
160
|
+
});
|
|
161
|
+
} catch {}
|
|
162
|
+
for (const entity of entitiesToDelete) for (const { source, hooks } of hooksEntries) {
|
|
163
|
+
const toRun = hooks[model]?.delete?.before;
|
|
164
|
+
if (toRun) {
|
|
165
|
+
if (await withSpan(`db delete.before ${model}`, {
|
|
166
|
+
[ATTR_HOOK_TYPE]: "delete.before",
|
|
167
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
168
|
+
[ATTR_CONTEXT]: source
|
|
169
|
+
}, () => toRun(entity, context)) === false) return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const customDeleted = customDeleteFn ? await customDeleteFn.fn(where) : null;
|
|
173
|
+
const deleted = !customDeleteFn || customDeleteFn.executeMainFn ? await (await getCurrentAdapter(adapter)).deleteMany({
|
|
174
|
+
model,
|
|
175
|
+
where
|
|
176
|
+
}) : customDeleted;
|
|
177
|
+
for (const entity of entitiesToDelete) for (const { source, hooks } of hooksEntries) {
|
|
178
|
+
const toRun = hooks[model]?.delete?.after;
|
|
179
|
+
if (toRun) await queueAfterTransactionHook(async () => {
|
|
180
|
+
await withSpan(`db delete.after ${model}`, {
|
|
181
|
+
[ATTR_HOOK_TYPE]: "delete.after",
|
|
182
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
183
|
+
[ATTR_CONTEXT]: source
|
|
184
|
+
}, () => toRun(entity, context));
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return deleted;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Wraps an atomic consume operation in the plugin `delete.before` and
|
|
191
|
+
* `delete.after` hook lifecycle. The caller supplies a `consumeFn` that
|
|
192
|
+
* performs the actual single-row delete-and-return (typically the
|
|
193
|
+
* adapter's `consumeOne`). The first concurrent caller wins, subsequent
|
|
194
|
+
* racers resolve to `null` without firing `delete.after` hooks.
|
|
195
|
+
*
|
|
196
|
+
* `preSnapshot` lets the caller hand in a row it already fetched so
|
|
197
|
+
* `delete.before` hooks don't trigger a second read. Without it, the
|
|
198
|
+
* helper falls back to a best-effort `findMany` against `hookWhere`.
|
|
199
|
+
* The snapshot only feeds `delete.before`; the `consumeFn` return value
|
|
200
|
+
* is the race gate.
|
|
201
|
+
*
|
|
202
|
+
* Returning `false` from a `delete.before` hook aborts the consume and
|
|
203
|
+
* the helper resolves to `null` (no `consumeFn` call, no after hooks).
|
|
204
|
+
*/
|
|
205
|
+
async function consumeOneWithHooks(model, hookWhere, consumeFn, preSnapshot) {
|
|
206
|
+
const context = tryGetCurrentAuthEndpointContext();
|
|
207
|
+
const beforeHooks = hooksEntries.flatMap(({ source, hooks }) => {
|
|
208
|
+
const fn = hooks[model]?.delete?.before;
|
|
209
|
+
return fn ? [{
|
|
210
|
+
source,
|
|
211
|
+
fn
|
|
212
|
+
}] : [];
|
|
213
|
+
});
|
|
214
|
+
let snapshot = preSnapshot ?? null;
|
|
215
|
+
if (beforeHooks.length) {
|
|
216
|
+
if (!snapshot) try {
|
|
217
|
+
snapshot = (await (await getCurrentAdapter(adapter)).findMany({
|
|
218
|
+
model,
|
|
219
|
+
where: hookWhere,
|
|
220
|
+
limit: 1
|
|
221
|
+
}))[0] || null;
|
|
222
|
+
} catch {}
|
|
223
|
+
if (snapshot) {
|
|
224
|
+
for (const { source, fn } of beforeHooks) if (await withSpan(`db delete.before ${model}`, {
|
|
225
|
+
[ATTR_HOOK_TYPE]: "delete.before",
|
|
226
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
227
|
+
[ATTR_CONTEXT]: source
|
|
228
|
+
}, () => fn(snapshot, context)) === false) return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const consumed = await consumeFn();
|
|
232
|
+
if (!consumed) return null;
|
|
233
|
+
for (const { source, hooks } of hooksEntries) {
|
|
234
|
+
const toRun = hooks[model]?.delete?.after;
|
|
235
|
+
if (toRun) await queueAfterTransactionHook(async () => {
|
|
236
|
+
await withSpan(`db delete.after ${model}`, {
|
|
237
|
+
[ATTR_HOOK_TYPE]: "delete.after",
|
|
238
|
+
[ATTR_DB_COLLECTION_NAME]: model,
|
|
239
|
+
[ATTR_CONTEXT]: source
|
|
240
|
+
}, () => toRun(consumed, context));
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return consumed;
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
createWithHooks,
|
|
247
|
+
updateWithHooks,
|
|
248
|
+
updateManyWithHooks,
|
|
249
|
+
deleteWithHooks,
|
|
250
|
+
deleteManyWithHooks,
|
|
251
|
+
consumeOneWithHooks
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
//#endregion
|
|
255
|
+
export { getWithHooks };
|