better-auth 1.4.8-beta.1 → 1.4.8-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/api/index.d.mts +393 -393
  2. package/dist/api/middlewares/origin-check.d.mts +3 -3
  3. package/dist/api/routes/account.d.mts +11 -11
  4. package/dist/api/routes/callback.d.mts +2 -2
  5. package/dist/api/routes/email-verification.d.mts +4 -4
  6. package/dist/api/routes/error.d.mts +2 -2
  7. package/dist/api/routes/ok.d.mts +2 -2
  8. package/dist/api/routes/reset-password.d.mts +5 -5
  9. package/dist/api/routes/session.d.mts +14 -14
  10. package/dist/api/routes/sign-in.d.mts +3 -3
  11. package/dist/api/routes/sign-out.d.mts +2 -2
  12. package/dist/api/routes/sign-up.d.mts +2 -2
  13. package/dist/api/routes/update-user.d.mts +13 -13
  14. package/dist/client/lynx/index.d.mts +15 -15
  15. package/dist/client/react/index.d.mts +13 -13
  16. package/dist/client/solid/index.d.mts +13 -13
  17. package/dist/client/svelte/index.d.mts +13 -13
  18. package/dist/client/vue/index.d.mts +15 -15
  19. package/dist/db/field.d.mts +6 -6
  20. package/dist/integrations/next-js.d.mts +4 -4
  21. package/dist/integrations/svelte-kit.d.mts +2 -2
  22. package/dist/integrations/tanstack-start.d.mts +4 -4
  23. package/dist/plugins/anonymous/index.d.mts +6 -5
  24. package/dist/plugins/anonymous/index.mjs +1 -0
  25. package/dist/plugins/anonymous/index.mjs.map +1 -1
  26. package/dist/plugins/api-key/index.d.mts +18 -18
  27. package/dist/plugins/bearer/index.d.mts +8 -7
  28. package/dist/plugins/bearer/index.mjs +2 -1
  29. package/dist/plugins/bearer/index.mjs.map +1 -1
  30. package/dist/plugins/captcha/index.d.mts +3 -2
  31. package/dist/plugins/captcha/index.mjs +2 -1
  32. package/dist/plugins/captcha/index.mjs.map +1 -1
  33. package/dist/plugins/custom-session/index.d.mts +6 -5
  34. package/dist/plugins/custom-session/index.mjs +2 -1
  35. package/dist/plugins/custom-session/index.mjs.map +1 -1
  36. package/dist/plugins/device-authorization/index.d.mts +35 -8
  37. package/dist/plugins/device-authorization/index.mjs +2 -1
  38. package/dist/plugins/device-authorization/index.mjs.map +1 -1
  39. package/dist/plugins/email-otp/index.d.mts +49 -48
  40. package/dist/plugins/email-otp/index.mjs +2 -1
  41. package/dist/plugins/email-otp/index.mjs.map +1 -1
  42. package/dist/plugins/generic-oauth/index.d.mts +1 -0
  43. package/dist/plugins/generic-oauth/index.mjs +1 -0
  44. package/dist/plugins/generic-oauth/index.mjs.map +1 -1
  45. package/dist/plugins/haveibeenpwned/index.d.mts +4 -3
  46. package/dist/plugins/haveibeenpwned/index.mjs +1 -0
  47. package/dist/plugins/haveibeenpwned/index.mjs.map +1 -1
  48. package/dist/plugins/index.d.mts +4 -3
  49. package/dist/plugins/jwt/index.d.mts +9 -9
  50. package/dist/plugins/last-login-method/index.d.mts +3 -2
  51. package/dist/plugins/last-login-method/index.mjs +2 -1
  52. package/dist/plugins/last-login-method/index.mjs.map +1 -1
  53. package/dist/plugins/magic-link/index.d.mts +5 -4
  54. package/dist/plugins/magic-link/index.mjs +2 -1
  55. package/dist/plugins/magic-link/index.mjs.map +1 -1
  56. package/dist/plugins/mcp/index.d.mts +11 -10
  57. package/dist/plugins/mcp/index.mjs +2 -1
  58. package/dist/plugins/mcp/index.mjs.map +1 -1
  59. package/dist/plugins/multi-session/index.d.mts +10 -9
  60. package/dist/plugins/multi-session/index.mjs +1 -0
  61. package/dist/plugins/multi-session/index.mjs.map +1 -1
  62. package/dist/plugins/oauth-proxy/index.d.mts +8 -8
  63. package/dist/plugins/oidc-provider/index.d.mts +13 -13
  64. package/dist/plugins/one-tap/index.d.mts +4 -3
  65. package/dist/plugins/one-tap/index.mjs +2 -1
  66. package/dist/plugins/one-tap/index.mjs.map +1 -1
  67. package/dist/plugins/one-time-token/index.d.mts +6 -5
  68. package/dist/plugins/one-time-token/index.mjs +2 -1
  69. package/dist/plugins/one-time-token/index.mjs.map +1 -1
  70. package/dist/plugins/open-api/index.d.mts +4 -3
  71. package/dist/plugins/open-api/index.mjs +2 -1
  72. package/dist/plugins/open-api/index.mjs.map +1 -1
  73. package/dist/plugins/organization/organization.d.mts +4 -4
  74. package/dist/plugins/organization/organization.mjs.map +1 -1
  75. package/dist/plugins/organization/routes/crud-access-control.d.mts +22 -22
  76. package/dist/plugins/organization/routes/crud-invites.d.mts +58 -58
  77. package/dist/plugins/organization/routes/crud-members.d.mts +62 -62
  78. package/dist/plugins/organization/routes/crud-org.d.mts +51 -51
  79. package/dist/plugins/organization/routes/crud-team.d.mts +76 -76
  80. package/dist/plugins/phone-number/index.d.mts +10 -9
  81. package/dist/plugins/phone-number/index.mjs +1 -0
  82. package/dist/plugins/phone-number/index.mjs.map +1 -1
  83. package/dist/plugins/siwe/index.d.mts +4 -3
  84. package/dist/plugins/siwe/index.mjs +2 -1
  85. package/dist/plugins/siwe/index.mjs.map +1 -1
  86. package/dist/plugins/two-factor/backup-codes/index.d.mts +5 -5
  87. package/dist/plugins/two-factor/index.d.mts +18 -18
  88. package/dist/plugins/two-factor/otp/index.d.mts +3 -3
  89. package/dist/plugins/two-factor/totp/index.d.mts +5 -5
  90. package/dist/plugins/username/index.d.mts +10 -9
  91. package/dist/plugins/username/index.mjs +1 -0
  92. package/dist/plugins/username/index.mjs.map +1 -1
  93. package/dist/test-utils/test-instance.d.mts +271 -271
  94. package/dist/utils/time.d.mts +29 -1
  95. package/package.json +7 -7
@@ -9,9 +9,10 @@ import "./admin/index.mjs";
9
9
  import { anonymous } from "./anonymous/index.mjs";
10
10
  import { ApiKey, ApiKeyOptions } from "./api-key/types.mjs";
11
11
  import { API_KEY_TABLE_NAME, ERROR_CODES, apiKey, defaultKeyHasher } from "./api-key/index.mjs";
12
- import { bearer } from "./bearer/index.mjs";
12
+ import { BearerOptions, bearer } from "./bearer/index.mjs";
13
13
  import { captcha } from "./captcha/index.mjs";
14
14
  import { CustomSessionPluginOptions, customSession } from "./custom-session/index.mjs";
15
+ import { TimeString, ms, sec } from "../utils/time.mjs";
15
16
  import { DeviceAuthorizationOptions, deviceAuthorization, deviceAuthorizationOptionsSchema } from "./device-authorization/index.mjs";
16
17
  import { EmailOTPOptions } from "./email-otp/types.mjs";
17
18
  import { emailOTP } from "./email-otp/index.mjs";
@@ -38,7 +39,7 @@ import { getClient, getMetadata, oidcProvider } from "./oidc-provider/index.mjs"
38
39
  import { getMCPProtectedResourceMetadata, getMCPProviderMetadata, mcp, oAuthDiscoveryMetadata, oAuthProtectedResourceMetadata, withMcpAuth } from "./mcp/index.mjs";
39
40
  import { MultiSessionConfig, multiSession } from "./multi-session/index.mjs";
40
41
  import { OAuthProxyOptions, oAuthProxy } from "./oauth-proxy/index.mjs";
41
- import { oneTap } from "./one-tap/index.mjs";
42
+ import { OneTapOptions, oneTap } from "./one-tap/index.mjs";
42
43
  import { OneTimeTokenOptions, oneTimeToken } from "./one-time-token/index.mjs";
43
44
  import { FieldSchema, OpenAPIModelSchema, Path, generator } from "./open-api/generator.mjs";
44
45
  import { OpenAPIOptions, openAPI } from "./open-api/index.mjs";
@@ -61,4 +62,4 @@ import { getOrgAdapter } from "./organization/adapter.mjs";
61
62
  import { DynamicAccessControlEndpoints, OrganizationEndpoints, OrganizationPlugin, TeamEndpoints, organization, parseRoles } from "./organization/organization.mjs";
62
63
  import "./organization/index.mjs";
63
64
  import { AuthEndpoint, AuthMiddleware, createAuthEndpoint, createAuthMiddleware, optionsMiddleware } from "@better-auth/core/api";
64
- export { API_KEY_TABLE_NAME, AccessControl, AdminOptions, ApiKey, ApiKeyOptions, Auth0Options, type AuthEndpoint, type AuthMiddleware, AuthorizationQuery, AuthorizeResponse, BackupCodeOptions, BaseOAuthProviderOptions, Client, CodeVerificationValue, CustomSessionPluginOptions, DeviceAuthorizationOptions, DynamicAccessControlEndpoints, ERROR_CODES, EmailOTPOptions, FieldSchema, GenericOAuthConfig, GenericOAuthOptions, HIDE_METADATA, HaveIBeenPwnedOptions, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOptionSchema, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginErrorCodes, InferTeam, Invitation, InvitationInput, InvitationStatus, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodOptions, LineOptions, MagicLinkOptions, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAuthAccessToken, OAuthProxyOptions, OIDCMetadata, OIDCOptions, OTPOptions, OktaOptions, OneTimeTokenOptions, OpenAPIModelSchema, OpenAPIOptions, Organization, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, Path, PatreonOptions, PhoneNumberOptions, Role, SIWEPluginOptions, SessionWithImpersonatedBy, SlackOptions, Statements, SubArray, Subset, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, TokenBody, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, UsernameOptions, admin, adminAc, anonymous, apiKey, auth0, backupCode2fa, bearer, captcha, createAccessControl, createAuthEndpoint, createAuthMiddleware, createJwk, customSession, defaultAc, defaultKeyHasher, defaultRoles, defaultRolesSchema, defaultStatements, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, generateBackupCodes, generateExportedKeyPair, generator, genericOAuth, getBackupCodes, getClient, getJwtToken, getMCPProtectedResourceMetadata, getMCPProviderMetadata, getMetadata, getOrgAdapter, haveIBeenPwned, hubspot, invitationSchema, invitationStatus, jwt, keycloak, lastLoginMethod, line, magicLink, mcp, memberAc, memberSchema, microsoftEntraId, multiSession, oAuthDiscoveryMetadata, oAuthProtectedResourceMetadata, oAuthProxy, oidcProvider, okta, oneTap, oneTimeToken, openAPI, optionsMiddleware, organization, organizationRoleSchema, organizationSchema, otp2fa, ownerAc, parseRoles, patreon, phoneNumber, role, roleSchema, siwe, slack, teamMemberSchema, teamSchema, totp2fa, twoFactor, twoFactorClient, username, verifyBackupCode, verifyJWT, withMcpAuth };
65
+ export { API_KEY_TABLE_NAME, AccessControl, AdminOptions, ApiKey, ApiKeyOptions, Auth0Options, type AuthEndpoint, type AuthMiddleware, AuthorizationQuery, AuthorizeResponse, BackupCodeOptions, BaseOAuthProviderOptions, BearerOptions, Client, CodeVerificationValue, CustomSessionPluginOptions, DeviceAuthorizationOptions, DynamicAccessControlEndpoints, ERROR_CODES, EmailOTPOptions, FieldSchema, GenericOAuthConfig, GenericOAuthOptions, HIDE_METADATA, HaveIBeenPwnedOptions, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOptionSchema, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginErrorCodes, InferTeam, Invitation, InvitationInput, InvitationStatus, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodOptions, LineOptions, MagicLinkOptions, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAuthAccessToken, OAuthProxyOptions, OIDCMetadata, OIDCOptions, OTPOptions, OktaOptions, OneTapOptions, OneTimeTokenOptions, OpenAPIModelSchema, OpenAPIOptions, Organization, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, Path, PatreonOptions, PhoneNumberOptions, Role, SIWEPluginOptions, SessionWithImpersonatedBy, SlackOptions, Statements, SubArray, Subset, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, TimeString, TokenBody, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, UsernameOptions, admin, adminAc, anonymous, apiKey, auth0, backupCode2fa, bearer, captcha, createAccessControl, createAuthEndpoint, createAuthMiddleware, createJwk, customSession, defaultAc, defaultKeyHasher, defaultRoles, defaultRolesSchema, defaultStatements, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, generateBackupCodes, generateExportedKeyPair, generator, genericOAuth, getBackupCodes, getClient, getJwtToken, getMCPProtectedResourceMetadata, getMCPProviderMetadata, getMetadata, getOrgAdapter, haveIBeenPwned, hubspot, invitationSchema, invitationStatus, jwt, keycloak, lastLoginMethod, line, magicLink, mcp, memberAc, memberSchema, microsoftEntraId, ms, multiSession, oAuthDiscoveryMetadata, oAuthProtectedResourceMetadata, oAuthProxy, oidcProvider, okta, oneTap, oneTimeToken, openAPI, optionsMiddleware, organization, organizationRoleSchema, organizationSchema, otp2fa, ownerAc, parseRoles, patreon, phoneNumber, role, roleSchema, sec, siwe, slack, teamMemberSchema, teamSchema, totp2fa, twoFactor, twoFactorClient, username, verifyBackupCode, verifyJWT, withMcpAuth };
@@ -2,9 +2,9 @@ import { JWKOptions, JWSAlgorithms, Jwk, JwtOptions } from "./types.mjs";
2
2
  import { getJwtToken } from "./sign.mjs";
3
3
  import { createJwk, generateExportedKeyPair } from "./utils.mjs";
4
4
  import { verifyJWT } from "./verify.mjs";
5
- import * as _better_auth_core7 from "@better-auth/core";
5
+ import * as _better_auth_core14 from "@better-auth/core";
6
6
  import * as z from "zod";
7
- import * as better_call157 from "better-call";
7
+ import * as better_call186 from "better-call";
8
8
  import { JSONWebKeySet, JWTPayload } from "jose";
9
9
 
10
10
  //#region src/plugins/jwt/index.d.ts
@@ -12,7 +12,7 @@ declare const jwt: <O extends JwtOptions>(options?: O) => {
12
12
  id: "jwt";
13
13
  options: NoInfer<O>;
14
14
  endpoints: {
15
- getJwks: better_call157.StrictEndpoint<string, {
15
+ getJwks: better_call186.StrictEndpoint<string, {
16
16
  method: "GET";
17
17
  metadata: {
18
18
  openapi: {
@@ -89,10 +89,10 @@ declare const jwt: <O extends JwtOptions>(options?: O) => {
89
89
  };
90
90
  };
91
91
  }, JSONWebKeySet>;
92
- getToken: better_call157.StrictEndpoint<"/token", {
92
+ getToken: better_call186.StrictEndpoint<"/token", {
93
93
  method: "GET";
94
94
  requireHeaders: true;
95
- use: ((inputContext: better_call157.MiddlewareInputContext<better_call157.MiddlewareOptions>) => Promise<{
95
+ use: ((inputContext: better_call186.MiddlewareInputContext<better_call186.MiddlewareOptions>) => Promise<{
96
96
  session: {
97
97
  session: Record<string, any> & {
98
98
  id: string;
@@ -141,7 +141,7 @@ declare const jwt: <O extends JwtOptions>(options?: O) => {
141
141
  }, {
142
142
  token: string;
143
143
  }>;
144
- signJWT: better_call157.StrictEndpoint<string, {
144
+ signJWT: better_call186.StrictEndpoint<string, {
145
145
  method: "POST";
146
146
  metadata: {
147
147
  $Infer: {
@@ -158,7 +158,7 @@ declare const jwt: <O extends JwtOptions>(options?: O) => {
158
158
  }, {
159
159
  token: string;
160
160
  }>;
161
- verifyJWT: better_call157.StrictEndpoint<string, {
161
+ verifyJWT: better_call186.StrictEndpoint<string, {
162
162
  method: "POST";
163
163
  metadata: {
164
164
  $Infer: {
@@ -185,8 +185,8 @@ declare const jwt: <O extends JwtOptions>(options?: O) => {
185
185
  };
186
186
  hooks: {
187
187
  after: {
188
- matcher(context: _better_auth_core7.HookEndpointContext): boolean;
189
- handler: (inputContext: better_call157.MiddlewareInputContext<better_call157.MiddlewareOptions>) => Promise<void>;
188
+ matcher(context: _better_auth_core14.HookEndpointContext): boolean;
189
+ handler: (inputContext: better_call186.MiddlewareInputContext<better_call186.MiddlewareOptions>) => Promise<void>;
190
190
  }[];
191
191
  };
192
192
  schema: {
@@ -1,4 +1,4 @@
1
- import * as _better_auth_core23 from "@better-auth/core";
1
+ import * as _better_auth_core21 from "@better-auth/core";
2
2
  import { GenericEndpointContext } from "@better-auth/core";
3
3
  import * as better_call242 from "better-call";
4
4
 
@@ -43,7 +43,7 @@ interface LastLoginMethodOptions {
43
43
  */
44
44
  declare const lastLoginMethod: <O extends LastLoginMethodOptions>(userConfig?: O | undefined) => {
45
45
  id: "last-login-method";
46
- init(ctx: _better_auth_core23.AuthContext): {
46
+ init(ctx: _better_auth_core21.AuthContext): {
47
47
  options: {
48
48
  databaseHooks: {
49
49
  user: {
@@ -104,6 +104,7 @@ declare const lastLoginMethod: <O extends LastLoginMethodOptions>(userConfig?: O
104
104
  };
105
105
  };
106
106
  } : undefined;
107
+ options: NoInfer<O>;
107
108
  };
108
109
  //#endregion
109
110
  export { LastLoginMethodOptions, lastLoginMethod };
@@ -72,7 +72,8 @@ const lastLoginMethod = (userConfig) => {
72
72
  input: false,
73
73
  required: false,
74
74
  fieldName: config.schema?.user?.lastLoginMethod || "lastLoginMethod"
75
- } } } } : void 0
75
+ } } } } : void 0,
76
+ options: userConfig
76
77
  };
77
78
  };
78
79
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/last-login-method/index.ts"],"sourcesContent":["import type {\n\tBetterAuthPlugin,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport { createAuthMiddleware } from \"@better-auth/core/api\";\n\n/**\n * Configuration for tracking different authentication methods\n */\nexport interface LastLoginMethodOptions {\n\t/**\n\t * Name of the cookie to store the last login method\n\t * @default \"better-auth.last_used_login_method\"\n\t */\n\tcookieName?: string | undefined;\n\t/**\n\t * Cookie expiration time in seconds\n\t * @default 2592000 (30 days)\n\t */\n\tmaxAge?: number | undefined;\n\t/**\n\t * Custom method to resolve the last login method\n\t * @param ctx - The context from the hook\n\t * @returns The last login method\n\t */\n\tcustomResolveMethod?:\n\t\t| ((ctx: GenericEndpointContext) => string | null)\n\t\t| undefined;\n\t/**\n\t * Store the last login method in the database. This will create a new field in the user table.\n\t * @default false\n\t */\n\tstoreInDatabase?: boolean | undefined;\n\t/**\n\t * Custom schema for the plugin\n\t * @default undefined\n\t */\n\tschema?:\n\t\t| {\n\t\t\t\tuser?: {\n\t\t\t\t\tlastLoginMethod?: string;\n\t\t\t\t};\n\t\t }\n\t\t| undefined;\n}\n\n/**\n * Plugin to track the last used login method\n */\nexport const lastLoginMethod = <O extends LastLoginMethodOptions>(\n\tuserConfig?: O | undefined,\n) => {\n\tconst paths = [\n\t\t\"/callback/:id\",\n\t\t\"/oauth2/callback/:providerId\",\n\t\t\"/sign-in/email\",\n\t\t\"/sign-up/email\",\n\t];\n\n\tconst defaultResolveMethod = (ctx: GenericEndpointContext) => {\n\t\tif (paths.includes(ctx.path)) {\n\t\t\treturn (\n\t\t\t\tctx.params?.id || ctx.params?.providerId || ctx.path.split(\"/\").pop()\n\t\t\t);\n\t\t}\n\t\tif (ctx.path.includes(\"siwe\")) return \"siwe\";\n\t\tif (ctx.path.includes(\"/passkey/verify-authentication\")) return \"passkey\";\n\t\treturn null;\n\t};\n\n\tconst config = {\n\t\tcookieName: \"better-auth.last_used_login_method\",\n\t\tmaxAge: 60 * 60 * 24 * 30,\n\t\t...userConfig,\n\t} satisfies LastLoginMethodOptions;\n\n\treturn {\n\t\tid: \"last-login-method\",\n\t\tinit(ctx) {\n\t\t\treturn {\n\t\t\t\toptions: {\n\t\t\t\t\tdatabaseHooks: {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync before(user, context) {\n\t\t\t\t\t\t\t\t\tif (!config.storeInDatabase) return;\n\t\t\t\t\t\t\t\t\tif (!context) return;\n\t\t\t\t\t\t\t\t\tconst lastUsedLoginMethod =\n\t\t\t\t\t\t\t\t\t\tconfig.customResolveMethod?.(context) ??\n\t\t\t\t\t\t\t\t\t\tdefaultResolveMethod(context);\n\t\t\t\t\t\t\t\t\tif (lastUsedLoginMethod) {\n\t\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\t\t...user,\n\t\t\t\t\t\t\t\t\t\t\t\tlastLoginMethod: lastUsedLoginMethod,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync after(session, context) {\n\t\t\t\t\t\t\t\t\tif (!config.storeInDatabase) return;\n\t\t\t\t\t\t\t\t\tif (!context) return;\n\t\t\t\t\t\t\t\t\tconst lastUsedLoginMethod =\n\t\t\t\t\t\t\t\t\t\tconfig.customResolveMethod?.(context) ??\n\t\t\t\t\t\t\t\t\t\tdefaultResolveMethod(context);\n\t\t\t\t\t\t\t\t\tif (lastUsedLoginMethod && session?.userId) {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tawait ctx.internalAdapter.updateUser(session.userId, {\n\t\t\t\t\t\t\t\t\t\t\t\tlastLoginMethod: lastUsedLoginMethod,\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\t\t\tctx.logger.error(\n\t\t\t\t\t\t\t\t\t\t\t\t\"Failed to update lastLoginMethod\",\n\t\t\t\t\t\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher() {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t},\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst lastUsedLoginMethod =\n\t\t\t\t\t\t\tconfig.customResolveMethod?.(ctx) ?? defaultResolveMethod(ctx);\n\t\t\t\t\t\tif (lastUsedLoginMethod) {\n\t\t\t\t\t\t\tconst setCookie = ctx.context.responseHeaders?.get(\"set-cookie\");\n\t\t\t\t\t\t\tconst sessionTokenName =\n\t\t\t\t\t\t\t\tctx.context.authCookies.sessionToken.name;\n\t\t\t\t\t\t\tconst hasSessionToken =\n\t\t\t\t\t\t\t\tsetCookie && setCookie.includes(sessionTokenName);\n\t\t\t\t\t\t\tif (hasSessionToken) {\n\t\t\t\t\t\t\t\t// Inherit cookie attributes from Better Auth's centralized cookie system\n\t\t\t\t\t\t\t\t// This ensures consistency with cross-origin, cross-subdomain, and security settings\n\t\t\t\t\t\t\t\tconst cookieAttributes = {\n\t\t\t\t\t\t\t\t\t...ctx.context.authCookies.sessionToken.options,\n\t\t\t\t\t\t\t\t\tmaxAge: config.maxAge,\n\t\t\t\t\t\t\t\t\thttpOnly: false, // Override: plugin cookies are not httpOnly\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tctx.setCookie(\n\t\t\t\t\t\t\t\t\tconfig.cookieName,\n\t\t\t\t\t\t\t\t\tlastUsedLoginMethod,\n\t\t\t\t\t\t\t\t\tcookieAttributes,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\tschema: (config.storeInDatabase\n\t\t\t? {\n\t\t\t\t\tuser: {\n\t\t\t\t\t\tfields: {\n\t\t\t\t\t\t\tlastLoginMethod: {\n\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\tinput: false,\n\t\t\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\t\t\tfieldName:\n\t\t\t\t\t\t\t\t\tconfig.schema?.user?.lastLoginMethod || \"lastLoginMethod\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: undefined) as O[\"storeInDatabase\"] extends true\n\t\t\t? {\n\t\t\t\t\tuser: {\n\t\t\t\t\t\tfields: {\n\t\t\t\t\t\t\tlastLoginMethod: {\n\t\t\t\t\t\t\t\ttype: \"string\";\n\t\t\t\t\t\t\t\trequired: false;\n\t\t\t\t\t\t\t\tinput: false;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t: undefined,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;AAiDA,MAAa,mBACZ,eACI;CACJ,MAAM,QAAQ;EACb;EACA;EACA;EACA;EACA;CAED,MAAM,wBAAwB,QAAgC;AAC7D,MAAI,MAAM,SAAS,IAAI,KAAK,CAC3B,QACC,IAAI,QAAQ,MAAM,IAAI,QAAQ,cAAc,IAAI,KAAK,MAAM,IAAI,CAAC,KAAK;AAGvE,MAAI,IAAI,KAAK,SAAS,OAAO,CAAE,QAAO;AACtC,MAAI,IAAI,KAAK,SAAS,iCAAiC,CAAE,QAAO;AAChE,SAAO;;CAGR,MAAM,SAAS;EACd,YAAY;EACZ,QAAQ,OAAU,KAAK;EACvB,GAAG;EACH;AAED,QAAO;EACN,IAAI;EACJ,KAAK,KAAK;AACT,UAAO,EACN,SAAS,EACR,eAAe;IACd,MAAM,EACL,QAAQ,EACP,MAAM,OAAO,MAAM,SAAS;AAC3B,SAAI,CAAC,OAAO,gBAAiB;AAC7B,SAAI,CAAC,QAAS;KACd,MAAM,sBACL,OAAO,sBAAsB,QAAQ,IACrC,qBAAqB,QAAQ;AAC9B,SAAI,oBACH,QAAO,EACN,MAAM;MACL,GAAG;MACH,iBAAiB;MACjB,EACD;OAGH,EACD;IACD,SAAS,EACR,QAAQ,EACP,MAAM,MAAM,SAAS,SAAS;AAC7B,SAAI,CAAC,OAAO,gBAAiB;AAC7B,SAAI,CAAC,QAAS;KACd,MAAM,sBACL,OAAO,sBAAsB,QAAQ,IACrC,qBAAqB,QAAQ;AAC9B,SAAI,uBAAuB,SAAS,OACnC,KAAI;AACH,YAAM,IAAI,gBAAgB,WAAW,QAAQ,QAAQ,EACpD,iBAAiB,qBACjB,CAAC;cACM,OAAO;AACf,UAAI,OAAO,MACV,oCACA,MACA;;OAIJ,EACD;IACD,EACD,EACD;;EAEF,OAAO,EACN,OAAO,CACN;GACC,UAAU;AACT,WAAO;;GAER,SAAS,qBAAqB,OAAO,QAAQ;IAC5C,MAAM,sBACL,OAAO,sBAAsB,IAAI,IAAI,qBAAqB,IAAI;AAC/D,QAAI,qBAAqB;KACxB,MAAM,YAAY,IAAI,QAAQ,iBAAiB,IAAI,aAAa;KAChE,MAAM,mBACL,IAAI,QAAQ,YAAY,aAAa;AAGtC,SADC,aAAa,UAAU,SAAS,iBAAiB,EAC7B;MAGpB,MAAM,mBAAmB;OACxB,GAAG,IAAI,QAAQ,YAAY,aAAa;OACxC,QAAQ,OAAO;OACf,UAAU;OACV;AAED,UAAI,UACH,OAAO,YACP,qBACA,iBACA;;;KAGF;GACF,CACD,EACD;EACD,QAAS,OAAO,kBACb,EACA,MAAM,EACL,QAAQ,EACP,iBAAiB;GAChB,MAAM;GACN,OAAO;GACP,UAAU;GACV,WACC,OAAO,QAAQ,MAAM,mBAAmB;GACzC,EACD,EACD,EACD,GACA;EAaH"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/last-login-method/index.ts"],"sourcesContent":["import type {\n\tBetterAuthPlugin,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport { createAuthMiddleware } from \"@better-auth/core/api\";\n\n/**\n * Configuration for tracking different authentication methods\n */\nexport interface LastLoginMethodOptions {\n\t/**\n\t * Name of the cookie to store the last login method\n\t * @default \"better-auth.last_used_login_method\"\n\t */\n\tcookieName?: string | undefined;\n\t/**\n\t * Cookie expiration time in seconds\n\t * @default 2592000 (30 days)\n\t */\n\tmaxAge?: number | undefined;\n\t/**\n\t * Custom method to resolve the last login method\n\t * @param ctx - The context from the hook\n\t * @returns The last login method\n\t */\n\tcustomResolveMethod?:\n\t\t| ((ctx: GenericEndpointContext) => string | null)\n\t\t| undefined;\n\t/**\n\t * Store the last login method in the database. This will create a new field in the user table.\n\t * @default false\n\t */\n\tstoreInDatabase?: boolean | undefined;\n\t/**\n\t * Custom schema for the plugin\n\t * @default undefined\n\t */\n\tschema?:\n\t\t| {\n\t\t\t\tuser?: {\n\t\t\t\t\tlastLoginMethod?: string;\n\t\t\t\t};\n\t\t }\n\t\t| undefined;\n}\n\n/**\n * Plugin to track the last used login method\n */\nexport const lastLoginMethod = <O extends LastLoginMethodOptions>(\n\tuserConfig?: O | undefined,\n) => {\n\tconst paths = [\n\t\t\"/callback/:id\",\n\t\t\"/oauth2/callback/:providerId\",\n\t\t\"/sign-in/email\",\n\t\t\"/sign-up/email\",\n\t];\n\n\tconst defaultResolveMethod = (ctx: GenericEndpointContext) => {\n\t\tif (paths.includes(ctx.path)) {\n\t\t\treturn (\n\t\t\t\tctx.params?.id || ctx.params?.providerId || ctx.path.split(\"/\").pop()\n\t\t\t);\n\t\t}\n\t\tif (ctx.path.includes(\"siwe\")) return \"siwe\";\n\t\tif (ctx.path.includes(\"/passkey/verify-authentication\")) return \"passkey\";\n\t\treturn null;\n\t};\n\n\tconst config = {\n\t\tcookieName: \"better-auth.last_used_login_method\",\n\t\tmaxAge: 60 * 60 * 24 * 30,\n\t\t...userConfig,\n\t} satisfies LastLoginMethodOptions;\n\n\treturn {\n\t\tid: \"last-login-method\",\n\t\tinit(ctx) {\n\t\t\treturn {\n\t\t\t\toptions: {\n\t\t\t\t\tdatabaseHooks: {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync before(user, context) {\n\t\t\t\t\t\t\t\t\tif (!config.storeInDatabase) return;\n\t\t\t\t\t\t\t\t\tif (!context) return;\n\t\t\t\t\t\t\t\t\tconst lastUsedLoginMethod =\n\t\t\t\t\t\t\t\t\t\tconfig.customResolveMethod?.(context) ??\n\t\t\t\t\t\t\t\t\t\tdefaultResolveMethod(context);\n\t\t\t\t\t\t\t\t\tif (lastUsedLoginMethod) {\n\t\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\t\t...user,\n\t\t\t\t\t\t\t\t\t\t\t\tlastLoginMethod: lastUsedLoginMethod,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync after(session, context) {\n\t\t\t\t\t\t\t\t\tif (!config.storeInDatabase) return;\n\t\t\t\t\t\t\t\t\tif (!context) return;\n\t\t\t\t\t\t\t\t\tconst lastUsedLoginMethod =\n\t\t\t\t\t\t\t\t\t\tconfig.customResolveMethod?.(context) ??\n\t\t\t\t\t\t\t\t\t\tdefaultResolveMethod(context);\n\t\t\t\t\t\t\t\t\tif (lastUsedLoginMethod && session?.userId) {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tawait ctx.internalAdapter.updateUser(session.userId, {\n\t\t\t\t\t\t\t\t\t\t\t\tlastLoginMethod: lastUsedLoginMethod,\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\t\t\tctx.logger.error(\n\t\t\t\t\t\t\t\t\t\t\t\t\"Failed to update lastLoginMethod\",\n\t\t\t\t\t\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher() {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t},\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst lastUsedLoginMethod =\n\t\t\t\t\t\t\tconfig.customResolveMethod?.(ctx) ?? defaultResolveMethod(ctx);\n\t\t\t\t\t\tif (lastUsedLoginMethod) {\n\t\t\t\t\t\t\tconst setCookie = ctx.context.responseHeaders?.get(\"set-cookie\");\n\t\t\t\t\t\t\tconst sessionTokenName =\n\t\t\t\t\t\t\t\tctx.context.authCookies.sessionToken.name;\n\t\t\t\t\t\t\tconst hasSessionToken =\n\t\t\t\t\t\t\t\tsetCookie && setCookie.includes(sessionTokenName);\n\t\t\t\t\t\t\tif (hasSessionToken) {\n\t\t\t\t\t\t\t\t// Inherit cookie attributes from Better Auth's centralized cookie system\n\t\t\t\t\t\t\t\t// This ensures consistency with cross-origin, cross-subdomain, and security settings\n\t\t\t\t\t\t\t\tconst cookieAttributes = {\n\t\t\t\t\t\t\t\t\t...ctx.context.authCookies.sessionToken.options,\n\t\t\t\t\t\t\t\t\tmaxAge: config.maxAge,\n\t\t\t\t\t\t\t\t\thttpOnly: false, // Override: plugin cookies are not httpOnly\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tctx.setCookie(\n\t\t\t\t\t\t\t\t\tconfig.cookieName,\n\t\t\t\t\t\t\t\t\tlastUsedLoginMethod,\n\t\t\t\t\t\t\t\t\tcookieAttributes,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\tschema: (config.storeInDatabase\n\t\t\t? {\n\t\t\t\t\tuser: {\n\t\t\t\t\t\tfields: {\n\t\t\t\t\t\t\tlastLoginMethod: {\n\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\tinput: false,\n\t\t\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\t\t\tfieldName:\n\t\t\t\t\t\t\t\t\tconfig.schema?.user?.lastLoginMethod || \"lastLoginMethod\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: undefined) as O[\"storeInDatabase\"] extends true\n\t\t\t? {\n\t\t\t\t\tuser: {\n\t\t\t\t\t\tfields: {\n\t\t\t\t\t\t\tlastLoginMethod: {\n\t\t\t\t\t\t\t\ttype: \"string\";\n\t\t\t\t\t\t\t\trequired: false;\n\t\t\t\t\t\t\t\tinput: false;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t: undefined,\n\t\toptions: userConfig as NoInfer<O>,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;AAiDA,MAAa,mBACZ,eACI;CACJ,MAAM,QAAQ;EACb;EACA;EACA;EACA;EACA;CAED,MAAM,wBAAwB,QAAgC;AAC7D,MAAI,MAAM,SAAS,IAAI,KAAK,CAC3B,QACC,IAAI,QAAQ,MAAM,IAAI,QAAQ,cAAc,IAAI,KAAK,MAAM,IAAI,CAAC,KAAK;AAGvE,MAAI,IAAI,KAAK,SAAS,OAAO,CAAE,QAAO;AACtC,MAAI,IAAI,KAAK,SAAS,iCAAiC,CAAE,QAAO;AAChE,SAAO;;CAGR,MAAM,SAAS;EACd,YAAY;EACZ,QAAQ,OAAU,KAAK;EACvB,GAAG;EACH;AAED,QAAO;EACN,IAAI;EACJ,KAAK,KAAK;AACT,UAAO,EACN,SAAS,EACR,eAAe;IACd,MAAM,EACL,QAAQ,EACP,MAAM,OAAO,MAAM,SAAS;AAC3B,SAAI,CAAC,OAAO,gBAAiB;AAC7B,SAAI,CAAC,QAAS;KACd,MAAM,sBACL,OAAO,sBAAsB,QAAQ,IACrC,qBAAqB,QAAQ;AAC9B,SAAI,oBACH,QAAO,EACN,MAAM;MACL,GAAG;MACH,iBAAiB;MACjB,EACD;OAGH,EACD;IACD,SAAS,EACR,QAAQ,EACP,MAAM,MAAM,SAAS,SAAS;AAC7B,SAAI,CAAC,OAAO,gBAAiB;AAC7B,SAAI,CAAC,QAAS;KACd,MAAM,sBACL,OAAO,sBAAsB,QAAQ,IACrC,qBAAqB,QAAQ;AAC9B,SAAI,uBAAuB,SAAS,OACnC,KAAI;AACH,YAAM,IAAI,gBAAgB,WAAW,QAAQ,QAAQ,EACpD,iBAAiB,qBACjB,CAAC;cACM,OAAO;AACf,UAAI,OAAO,MACV,oCACA,MACA;;OAIJ,EACD;IACD,EACD,EACD;;EAEF,OAAO,EACN,OAAO,CACN;GACC,UAAU;AACT,WAAO;;GAER,SAAS,qBAAqB,OAAO,QAAQ;IAC5C,MAAM,sBACL,OAAO,sBAAsB,IAAI,IAAI,qBAAqB,IAAI;AAC/D,QAAI,qBAAqB;KACxB,MAAM,YAAY,IAAI,QAAQ,iBAAiB,IAAI,aAAa;KAChE,MAAM,mBACL,IAAI,QAAQ,YAAY,aAAa;AAGtC,SADC,aAAa,UAAU,SAAS,iBAAiB,EAC7B;MAGpB,MAAM,mBAAmB;OACxB,GAAG,IAAI,QAAQ,YAAY,aAAa;OACxC,QAAQ,OAAO;OACf,UAAU;OACV;AAED,UAAI,UACH,OAAO,YACP,qBACA,iBACA;;;KAGF;GACF,CACD,EACD;EACD,QAAS,OAAO,kBACb,EACA,MAAM,EACL,QAAQ,EACP,iBAAiB;GAChB,MAAM;GACN,OAAO;GACP,UAAU;GACV,WACC,OAAO,QAAQ,MAAM,mBAAmB;GACzC,EACD,EACD,EACD,GACA;EAaH,SAAS;EACT"}
@@ -1,6 +1,6 @@
1
1
  import { Awaitable, GenericEndpointContext } from "@better-auth/core";
2
2
  import * as z from "zod";
3
- import * as better_call177 from "better-call";
3
+ import * as better_call182 from "better-call";
4
4
 
5
5
  //#region src/plugins/magic-link/index.d.ts
6
6
  interface MagicLinkOptions {
@@ -68,7 +68,7 @@ declare const magicLink: (options: MagicLinkOptions) => {
68
68
  *
69
69
  * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/sign-in#api-method-sign-in-magic-link)
70
70
  */
71
- signInMagicLink: better_call177.StrictEndpoint<"/sign-in/magic-link", {
71
+ signInMagicLink: better_call182.StrictEndpoint<"/sign-in/magic-link", {
72
72
  method: "POST";
73
73
  requireHeaders: true;
74
74
  body: z.ZodObject<{
@@ -119,7 +119,7 @@ declare const magicLink: (options: MagicLinkOptions) => {
119
119
  *
120
120
  * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/magic-link#api-method-magic-link-verify)
121
121
  */
122
- magicLinkVerify: better_call177.StrictEndpoint<"/magic-link/verify", {
122
+ magicLinkVerify: better_call182.StrictEndpoint<"/magic-link/verify", {
123
123
  method: "GET";
124
124
  query: z.ZodObject<{
125
125
  token: z.ZodString;
@@ -127,7 +127,7 @@ declare const magicLink: (options: MagicLinkOptions) => {
127
127
  errorCallbackURL: z.ZodOptional<z.ZodString>;
128
128
  newUserCallbackURL: z.ZodOptional<z.ZodString>;
129
129
  }, z.core.$strip>;
130
- use: ((inputContext: better_call177.MiddlewareInputContext<better_call177.MiddlewareOptions>) => Promise<void>)[];
130
+ use: ((inputContext: better_call182.MiddlewareInputContext<better_call182.MiddlewareOptions>) => Promise<void>)[];
131
131
  requireHeaders: true;
132
132
  metadata: {
133
133
  openapi: {
@@ -173,6 +173,7 @@ declare const magicLink: (options: MagicLinkOptions) => {
173
173
  window: number;
174
174
  max: number;
175
175
  }[];
176
+ options: MagicLinkOptions;
176
177
  };
177
178
  //#endregion
178
179
  export { MagicLinkOptions, magicLink };
@@ -164,7 +164,8 @@ const magicLink = (options) => {
164
164
  },
165
165
  window: opts.rateLimit?.window || 60,
166
166
  max: opts.rateLimit?.max || 5
167
- }]
167
+ }],
168
+ options
168
169
  };
169
170
  };
170
171
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/magic-link/index.ts"],"sourcesContent":["import type {\n\tAwaitable,\n\tBetterAuthPlugin,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport * as z from \"zod\";\nimport { originCheck } from \"../../api\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { generateRandomString } from \"../../crypto\";\nimport { defaultKeyHasher } from \"./utils\";\n\nexport interface MagicLinkOptions {\n\t/**\n\t * Time in seconds until the magic link expires.\n\t * @default (60 * 5) // 5 minutes\n\t */\n\texpiresIn?: number | undefined;\n\t/**\n\t * Send magic link implementation.\n\t */\n\tsendMagicLink: (\n\t\tdata: {\n\t\t\temail: string;\n\t\t\turl: string;\n\t\t\ttoken: string;\n\t\t},\n\t\tctx?: GenericEndpointContext | undefined,\n\t) => Awaitable<void>;\n\t/**\n\t * Disable sign up if user is not found.\n\t *\n\t * @default false\n\t */\n\tdisableSignUp?: boolean | undefined;\n\t/**\n\t * Rate limit configuration.\n\t *\n\t * @default {\n\t * window: 60,\n\t * max: 5,\n\t * }\n\t */\n\trateLimit?:\n\t\t| {\n\t\t\t\twindow: number;\n\t\t\t\tmax: number;\n\t\t }\n\t\t| undefined;\n\t/**\n\t * Custom function to generate a token\n\t */\n\tgenerateToken?: ((email: string) => Awaitable<string>) | undefined;\n\n\t/**\n\t * This option allows you to configure how the token is stored in your database.\n\t * Note: This will not affect the token that's sent, it will only affect the token stored in your database.\n\t *\n\t * @default \"plain\"\n\t */\n\tstoreToken?:\n\t\t| (\n\t\t\t\t| \"plain\"\n\t\t\t\t| \"hashed\"\n\t\t\t\t| { type: \"custom-hasher\"; hash: (token: string) => Promise<string> }\n\t\t )\n\t\t| undefined;\n}\n\nconst signInMagicLinkBodySchema = z.object({\n\temail: z.email().meta({\n\t\tdescription: \"Email address to send the magic link\",\n\t}),\n\tname: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'User display name. Only used if the user is registering for the first time. Eg: \"my-name\"',\n\t\t})\n\t\t.optional(),\n\tcallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"URL to redirect after magic link verification\",\n\t\t})\n\t\t.optional(),\n\tnewUserCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"URL to redirect after new user signup. Only used if the user is registering for the first time.\",\n\t\t})\n\t\t.optional(),\n\terrorCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"URL to redirect after error.\",\n\t\t})\n\t\t.optional(),\n});\nconst magicLinkVerifyQuerySchema = z.object({\n\ttoken: z.string().meta({\n\t\tdescription: \"Verification token\",\n\t}),\n\tcallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'URL to redirect after magic link verification, if not provided the user will be redirected to the root URL. Eg: \"/dashboard\"',\n\t\t})\n\t\t.optional(),\n\terrorCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"URL to redirect after error.\",\n\t\t})\n\t\t.optional(),\n\tnewUserCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"URL to redirect after new user signup. Only used if the user is registering for the first time.\",\n\t\t})\n\t\t.optional(),\n});\nexport const magicLink = (options: MagicLinkOptions) => {\n\tconst opts = {\n\t\tstoreToken: \"plain\",\n\t\t...options,\n\t} satisfies MagicLinkOptions;\n\n\tasync function storeToken(ctx: GenericEndpointContext, token: string) {\n\t\tif (opts.storeToken === \"hashed\") {\n\t\t\treturn await defaultKeyHasher(token);\n\t\t}\n\t\tif (\n\t\t\ttypeof opts.storeToken === \"object\" &&\n\t\t\t\"type\" in opts.storeToken &&\n\t\t\topts.storeToken.type === \"custom-hasher\"\n\t\t) {\n\t\t\treturn await opts.storeToken.hash(token);\n\t\t}\n\t\treturn token;\n\t}\n\n\treturn {\n\t\tid: \"magic-link\",\n\t\tendpoints: {\n\t\t\t/**\n\t\t\t * ### Endpoint\n\t\t\t *\n\t\t\t * POST `/sign-in/magic-link`\n\t\t\t *\n\t\t\t * ### API Methods\n\t\t\t *\n\t\t\t * **server:**\n\t\t\t * `auth.api.signInMagicLink`\n\t\t\t *\n\t\t\t * **client:**\n\t\t\t * `authClient.signIn.magicLink`\n\t\t\t *\n\t\t\t * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/sign-in#api-method-sign-in-magic-link)\n\t\t\t */\n\t\t\tsignInMagicLink: createAuthEndpoint(\n\t\t\t\t\"/sign-in/magic-link\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tbody: signInMagicLinkBodySchema,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\topenapi: {\n\t\t\t\t\t\t\toperationId: \"signInWithMagicLink\",\n\t\t\t\t\t\t\tdescription: \"Sign in with magic link\",\n\t\t\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\t\t200: {\n\t\t\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst { email } = ctx.body;\n\n\t\t\t\t\tconst verificationToken = opts?.generateToken\n\t\t\t\t\t\t? await opts.generateToken(email)\n\t\t\t\t\t\t: generateRandomString(32, \"a-z\", \"A-Z\");\n\t\t\t\t\tconst storedToken = await storeToken(ctx, verificationToken);\n\t\t\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\t\t\tidentifier: storedToken,\n\t\t\t\t\t\tvalue: JSON.stringify({ email, name: ctx.body.name }),\n\t\t\t\t\t\texpiresAt: new Date(Date.now() + (opts.expiresIn || 60 * 5) * 1000),\n\t\t\t\t\t});\n\t\t\t\t\tconst realBaseURL = new URL(ctx.context.baseURL);\n\t\t\t\t\tconst pathname =\n\t\t\t\t\t\trealBaseURL.pathname === \"/\" ? \"\" : realBaseURL.pathname;\n\t\t\t\t\tconst basePath = pathname ? \"\" : ctx.context.options.basePath || \"\";\n\t\t\t\t\tconst url = new URL(\n\t\t\t\t\t\t`${pathname}${basePath}/magic-link/verify`,\n\t\t\t\t\t\trealBaseURL.origin,\n\t\t\t\t\t);\n\t\t\t\t\turl.searchParams.set(\"token\", verificationToken);\n\t\t\t\t\turl.searchParams.set(\"callbackURL\", ctx.body.callbackURL || \"/\");\n\t\t\t\t\tif (ctx.body.newUserCallbackURL) {\n\t\t\t\t\t\turl.searchParams.set(\n\t\t\t\t\t\t\t\"newUserCallbackURL\",\n\t\t\t\t\t\t\tctx.body.newUserCallbackURL,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (ctx.body.errorCallbackURL) {\n\t\t\t\t\t\turl.searchParams.set(\"errorCallbackURL\", ctx.body.errorCallbackURL);\n\t\t\t\t\t}\n\t\t\t\t\tawait options.sendMagicLink(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t\turl: url.toString(),\n\t\t\t\t\t\t\ttoken: verificationToken,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx,\n\t\t\t\t\t);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tstatus: true,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\t/**\n\t\t\t * ### Endpoint\n\t\t\t *\n\t\t\t * GET `/magic-link/verify`\n\t\t\t *\n\t\t\t * ### API Methods\n\t\t\t *\n\t\t\t * **server:**\n\t\t\t * `auth.api.magicLinkVerify`\n\t\t\t *\n\t\t\t * **client:**\n\t\t\t * `authClient.magicLink.verify`\n\t\t\t *\n\t\t\t * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/magic-link#api-method-magic-link-verify)\n\t\t\t */\n\t\t\tmagicLinkVerify: createAuthEndpoint(\n\t\t\t\t\"/magic-link/verify\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tquery: magicLinkVerifyQuerySchema,\n\t\t\t\t\tuse: [\n\t\t\t\t\t\toriginCheck((ctx) => {\n\t\t\t\t\t\t\treturn ctx.query.callbackURL\n\t\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.callbackURL)\n\t\t\t\t\t\t\t\t: \"/\";\n\t\t\t\t\t\t}),\n\t\t\t\t\t\toriginCheck((ctx) => {\n\t\t\t\t\t\t\treturn ctx.query.newUserCallbackURL\n\t\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.newUserCallbackURL)\n\t\t\t\t\t\t\t\t: \"/\";\n\t\t\t\t\t\t}),\n\t\t\t\t\t\toriginCheck((ctx) => {\n\t\t\t\t\t\t\treturn ctx.query.errorCallbackURL\n\t\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.errorCallbackURL)\n\t\t\t\t\t\t\t\t: \"/\";\n\t\t\t\t\t\t}),\n\t\t\t\t\t],\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\topenapi: {\n\t\t\t\t\t\t\toperationId: \"verifyMagicLink\",\n\t\t\t\t\t\t\tdescription: \"Verify magic link\",\n\t\t\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\t\t200: {\n\t\t\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst token = ctx.query.token;\n\t\t\t\t\t// If the first argument provides the origin, it will ignore the second argument of `new URL`.\n\t\t\t\t\t// new URL(\"http://localhost:3001/hello\", \"http://localhost:3000\").toString()\n\t\t\t\t\t// Returns http://localhost:3001/hello\n\t\t\t\t\tconst callbackURL = new URL(\n\t\t\t\t\t\tctx.query.callbackURL\n\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.callbackURL)\n\t\t\t\t\t\t\t: \"/\",\n\t\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t\t).toString();\n\t\t\t\t\tconst errorCallbackURL = new URL(\n\t\t\t\t\t\tctx.query.errorCallbackURL\n\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.errorCallbackURL)\n\t\t\t\t\t\t\t: callbackURL,\n\t\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t\t);\n\n\t\t\t\t\tfunction redirectWithError(error: string): never {\n\t\t\t\t\t\terrorCallbackURL.searchParams.set(\"error\", error);\n\t\t\t\t\t\tthrow ctx.redirect(errorCallbackURL.toString());\n\t\t\t\t\t}\n\n\t\t\t\t\tconst newUserCallbackURL = new URL(\n\t\t\t\t\t\tctx.query.newUserCallbackURL\n\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.newUserCallbackURL)\n\t\t\t\t\t\t\t: callbackURL,\n\t\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t\t).toString();\n\t\t\t\t\tconst storedToken = await storeToken(ctx, token);\n\t\t\t\t\tconst tokenValue =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t\t\t\tstoredToken,\n\t\t\t\t\t\t);\n\t\t\t\t\tif (!tokenValue) {\n\t\t\t\t\t\tredirectWithError(\"INVALID_TOKEN\");\n\t\t\t\t\t}\n\t\t\t\t\tif (tokenValue.expiresAt < new Date()) {\n\t\t\t\t\t\tawait ctx.context.internalAdapter.deleteVerificationValue(\n\t\t\t\t\t\t\ttokenValue.id,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tredirectWithError(\"EXPIRED_TOKEN\");\n\t\t\t\t\t}\n\t\t\t\t\tawait ctx.context.internalAdapter.deleteVerificationValue(\n\t\t\t\t\t\ttokenValue.id,\n\t\t\t\t\t);\n\t\t\t\t\tconst { email, name } = JSON.parse(tokenValue.value) as {\n\t\t\t\t\t\temail: string;\n\t\t\t\t\t\tname?: string | undefined;\n\t\t\t\t\t};\n\t\t\t\t\tlet isNewUser = false;\n\t\t\t\t\tlet user = await ctx.context.internalAdapter\n\t\t\t\t\t\t.findUserByEmail(email)\n\t\t\t\t\t\t.then((res) => res?.user);\n\n\t\t\t\t\tif (!user) {\n\t\t\t\t\t\tif (!opts.disableSignUp) {\n\t\t\t\t\t\t\tconst newUser = await ctx.context.internalAdapter.createUser({\n\t\t\t\t\t\t\t\temail: email,\n\t\t\t\t\t\t\t\temailVerified: true,\n\t\t\t\t\t\t\t\tname: name || \"\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tisNewUser = true;\n\t\t\t\t\t\t\tuser = newUser;\n\t\t\t\t\t\t\tif (!user) {\n\t\t\t\t\t\t\t\tredirectWithError(\"failed_to_create_user\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tredirectWithError(\"new_user_signup_disabled\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!user.emailVerified) {\n\t\t\t\t\t\tuser = await ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\t\t\temailVerified: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\tuser.id,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\tredirectWithError(\"failed_to_create_session\");\n\t\t\t\t\t}\n\n\t\t\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\t\t\tsession,\n\t\t\t\t\t\tuser,\n\t\t\t\t\t});\n\t\t\t\t\tif (!ctx.query.callbackURL) {\n\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\ttoken: session.token,\n\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\tid: user.id,\n\t\t\t\t\t\t\t\temail: user.email,\n\t\t\t\t\t\t\t\temailVerified: user.emailVerified,\n\t\t\t\t\t\t\t\tname: user.name,\n\t\t\t\t\t\t\t\timage: user.image,\n\t\t\t\t\t\t\t\tcreatedAt: user.createdAt,\n\t\t\t\t\t\t\t\tupdatedAt: user.updatedAt,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (isNewUser) {\n\t\t\t\t\t\tthrow ctx.redirect(newUserCallbackURL);\n\t\t\t\t\t}\n\t\t\t\t\tthrow ctx.redirect(callbackURL);\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\trateLimit: [\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tpath.startsWith(\"/sign-in/magic-link\") ||\n\t\t\t\t\t\tpath.startsWith(\"/magic-link/verify\")\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\twindow: opts.rateLimit?.window || 60,\n\t\t\t\tmax: opts.rateLimit?.max || 5,\n\t\t\t},\n\t\t],\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/magic-link/index.ts"],"sourcesContent":["import type {\n\tAwaitable,\n\tBetterAuthPlugin,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport * as z from \"zod\";\nimport { originCheck } from \"../../api\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { generateRandomString } from \"../../crypto\";\nimport { defaultKeyHasher } from \"./utils\";\n\nexport interface MagicLinkOptions {\n\t/**\n\t * Time in seconds until the magic link expires.\n\t * @default (60 * 5) // 5 minutes\n\t */\n\texpiresIn?: number | undefined;\n\t/**\n\t * Send magic link implementation.\n\t */\n\tsendMagicLink: (\n\t\tdata: {\n\t\t\temail: string;\n\t\t\turl: string;\n\t\t\ttoken: string;\n\t\t},\n\t\tctx?: GenericEndpointContext | undefined,\n\t) => Awaitable<void>;\n\t/**\n\t * Disable sign up if user is not found.\n\t *\n\t * @default false\n\t */\n\tdisableSignUp?: boolean | undefined;\n\t/**\n\t * Rate limit configuration.\n\t *\n\t * @default {\n\t * window: 60,\n\t * max: 5,\n\t * }\n\t */\n\trateLimit?:\n\t\t| {\n\t\t\t\twindow: number;\n\t\t\t\tmax: number;\n\t\t }\n\t\t| undefined;\n\t/**\n\t * Custom function to generate a token\n\t */\n\tgenerateToken?: ((email: string) => Awaitable<string>) | undefined;\n\n\t/**\n\t * This option allows you to configure how the token is stored in your database.\n\t * Note: This will not affect the token that's sent, it will only affect the token stored in your database.\n\t *\n\t * @default \"plain\"\n\t */\n\tstoreToken?:\n\t\t| (\n\t\t\t\t| \"plain\"\n\t\t\t\t| \"hashed\"\n\t\t\t\t| { type: \"custom-hasher\"; hash: (token: string) => Promise<string> }\n\t\t )\n\t\t| undefined;\n}\n\nconst signInMagicLinkBodySchema = z.object({\n\temail: z.email().meta({\n\t\tdescription: \"Email address to send the magic link\",\n\t}),\n\tname: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'User display name. Only used if the user is registering for the first time. Eg: \"my-name\"',\n\t\t})\n\t\t.optional(),\n\tcallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"URL to redirect after magic link verification\",\n\t\t})\n\t\t.optional(),\n\tnewUserCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"URL to redirect after new user signup. Only used if the user is registering for the first time.\",\n\t\t})\n\t\t.optional(),\n\terrorCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"URL to redirect after error.\",\n\t\t})\n\t\t.optional(),\n});\nconst magicLinkVerifyQuerySchema = z.object({\n\ttoken: z.string().meta({\n\t\tdescription: \"Verification token\",\n\t}),\n\tcallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'URL to redirect after magic link verification, if not provided the user will be redirected to the root URL. Eg: \"/dashboard\"',\n\t\t})\n\t\t.optional(),\n\terrorCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"URL to redirect after error.\",\n\t\t})\n\t\t.optional(),\n\tnewUserCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"URL to redirect after new user signup. Only used if the user is registering for the first time.\",\n\t\t})\n\t\t.optional(),\n});\nexport const magicLink = (options: MagicLinkOptions) => {\n\tconst opts = {\n\t\tstoreToken: \"plain\",\n\t\t...options,\n\t} satisfies MagicLinkOptions;\n\n\tasync function storeToken(ctx: GenericEndpointContext, token: string) {\n\t\tif (opts.storeToken === \"hashed\") {\n\t\t\treturn await defaultKeyHasher(token);\n\t\t}\n\t\tif (\n\t\t\ttypeof opts.storeToken === \"object\" &&\n\t\t\t\"type\" in opts.storeToken &&\n\t\t\topts.storeToken.type === \"custom-hasher\"\n\t\t) {\n\t\t\treturn await opts.storeToken.hash(token);\n\t\t}\n\t\treturn token;\n\t}\n\n\treturn {\n\t\tid: \"magic-link\",\n\t\tendpoints: {\n\t\t\t/**\n\t\t\t * ### Endpoint\n\t\t\t *\n\t\t\t * POST `/sign-in/magic-link`\n\t\t\t *\n\t\t\t * ### API Methods\n\t\t\t *\n\t\t\t * **server:**\n\t\t\t * `auth.api.signInMagicLink`\n\t\t\t *\n\t\t\t * **client:**\n\t\t\t * `authClient.signIn.magicLink`\n\t\t\t *\n\t\t\t * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/sign-in#api-method-sign-in-magic-link)\n\t\t\t */\n\t\t\tsignInMagicLink: createAuthEndpoint(\n\t\t\t\t\"/sign-in/magic-link\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tbody: signInMagicLinkBodySchema,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\topenapi: {\n\t\t\t\t\t\t\toperationId: \"signInWithMagicLink\",\n\t\t\t\t\t\t\tdescription: \"Sign in with magic link\",\n\t\t\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\t\t200: {\n\t\t\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst { email } = ctx.body;\n\n\t\t\t\t\tconst verificationToken = opts?.generateToken\n\t\t\t\t\t\t? await opts.generateToken(email)\n\t\t\t\t\t\t: generateRandomString(32, \"a-z\", \"A-Z\");\n\t\t\t\t\tconst storedToken = await storeToken(ctx, verificationToken);\n\t\t\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\t\t\tidentifier: storedToken,\n\t\t\t\t\t\tvalue: JSON.stringify({ email, name: ctx.body.name }),\n\t\t\t\t\t\texpiresAt: new Date(Date.now() + (opts.expiresIn || 60 * 5) * 1000),\n\t\t\t\t\t});\n\t\t\t\t\tconst realBaseURL = new URL(ctx.context.baseURL);\n\t\t\t\t\tconst pathname =\n\t\t\t\t\t\trealBaseURL.pathname === \"/\" ? \"\" : realBaseURL.pathname;\n\t\t\t\t\tconst basePath = pathname ? \"\" : ctx.context.options.basePath || \"\";\n\t\t\t\t\tconst url = new URL(\n\t\t\t\t\t\t`${pathname}${basePath}/magic-link/verify`,\n\t\t\t\t\t\trealBaseURL.origin,\n\t\t\t\t\t);\n\t\t\t\t\turl.searchParams.set(\"token\", verificationToken);\n\t\t\t\t\turl.searchParams.set(\"callbackURL\", ctx.body.callbackURL || \"/\");\n\t\t\t\t\tif (ctx.body.newUserCallbackURL) {\n\t\t\t\t\t\turl.searchParams.set(\n\t\t\t\t\t\t\t\"newUserCallbackURL\",\n\t\t\t\t\t\t\tctx.body.newUserCallbackURL,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (ctx.body.errorCallbackURL) {\n\t\t\t\t\t\turl.searchParams.set(\"errorCallbackURL\", ctx.body.errorCallbackURL);\n\t\t\t\t\t}\n\t\t\t\t\tawait options.sendMagicLink(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t\turl: url.toString(),\n\t\t\t\t\t\t\ttoken: verificationToken,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx,\n\t\t\t\t\t);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tstatus: true,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\t/**\n\t\t\t * ### Endpoint\n\t\t\t *\n\t\t\t * GET `/magic-link/verify`\n\t\t\t *\n\t\t\t * ### API Methods\n\t\t\t *\n\t\t\t * **server:**\n\t\t\t * `auth.api.magicLinkVerify`\n\t\t\t *\n\t\t\t * **client:**\n\t\t\t * `authClient.magicLink.verify`\n\t\t\t *\n\t\t\t * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/magic-link#api-method-magic-link-verify)\n\t\t\t */\n\t\t\tmagicLinkVerify: createAuthEndpoint(\n\t\t\t\t\"/magic-link/verify\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tquery: magicLinkVerifyQuerySchema,\n\t\t\t\t\tuse: [\n\t\t\t\t\t\toriginCheck((ctx) => {\n\t\t\t\t\t\t\treturn ctx.query.callbackURL\n\t\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.callbackURL)\n\t\t\t\t\t\t\t\t: \"/\";\n\t\t\t\t\t\t}),\n\t\t\t\t\t\toriginCheck((ctx) => {\n\t\t\t\t\t\t\treturn ctx.query.newUserCallbackURL\n\t\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.newUserCallbackURL)\n\t\t\t\t\t\t\t\t: \"/\";\n\t\t\t\t\t\t}),\n\t\t\t\t\t\toriginCheck((ctx) => {\n\t\t\t\t\t\t\treturn ctx.query.errorCallbackURL\n\t\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.errorCallbackURL)\n\t\t\t\t\t\t\t\t: \"/\";\n\t\t\t\t\t\t}),\n\t\t\t\t\t],\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\topenapi: {\n\t\t\t\t\t\t\toperationId: \"verifyMagicLink\",\n\t\t\t\t\t\t\tdescription: \"Verify magic link\",\n\t\t\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\t\t200: {\n\t\t\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst token = ctx.query.token;\n\t\t\t\t\t// If the first argument provides the origin, it will ignore the second argument of `new URL`.\n\t\t\t\t\t// new URL(\"http://localhost:3001/hello\", \"http://localhost:3000\").toString()\n\t\t\t\t\t// Returns http://localhost:3001/hello\n\t\t\t\t\tconst callbackURL = new URL(\n\t\t\t\t\t\tctx.query.callbackURL\n\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.callbackURL)\n\t\t\t\t\t\t\t: \"/\",\n\t\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t\t).toString();\n\t\t\t\t\tconst errorCallbackURL = new URL(\n\t\t\t\t\t\tctx.query.errorCallbackURL\n\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.errorCallbackURL)\n\t\t\t\t\t\t\t: callbackURL,\n\t\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t\t);\n\n\t\t\t\t\tfunction redirectWithError(error: string): never {\n\t\t\t\t\t\terrorCallbackURL.searchParams.set(\"error\", error);\n\t\t\t\t\t\tthrow ctx.redirect(errorCallbackURL.toString());\n\t\t\t\t\t}\n\n\t\t\t\t\tconst newUserCallbackURL = new URL(\n\t\t\t\t\t\tctx.query.newUserCallbackURL\n\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.newUserCallbackURL)\n\t\t\t\t\t\t\t: callbackURL,\n\t\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t\t).toString();\n\t\t\t\t\tconst storedToken = await storeToken(ctx, token);\n\t\t\t\t\tconst tokenValue =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t\t\t\tstoredToken,\n\t\t\t\t\t\t);\n\t\t\t\t\tif (!tokenValue) {\n\t\t\t\t\t\tredirectWithError(\"INVALID_TOKEN\");\n\t\t\t\t\t}\n\t\t\t\t\tif (tokenValue.expiresAt < new Date()) {\n\t\t\t\t\t\tawait ctx.context.internalAdapter.deleteVerificationValue(\n\t\t\t\t\t\t\ttokenValue.id,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tredirectWithError(\"EXPIRED_TOKEN\");\n\t\t\t\t\t}\n\t\t\t\t\tawait ctx.context.internalAdapter.deleteVerificationValue(\n\t\t\t\t\t\ttokenValue.id,\n\t\t\t\t\t);\n\t\t\t\t\tconst { email, name } = JSON.parse(tokenValue.value) as {\n\t\t\t\t\t\temail: string;\n\t\t\t\t\t\tname?: string | undefined;\n\t\t\t\t\t};\n\t\t\t\t\tlet isNewUser = false;\n\t\t\t\t\tlet user = await ctx.context.internalAdapter\n\t\t\t\t\t\t.findUserByEmail(email)\n\t\t\t\t\t\t.then((res) => res?.user);\n\n\t\t\t\t\tif (!user) {\n\t\t\t\t\t\tif (!opts.disableSignUp) {\n\t\t\t\t\t\t\tconst newUser = await ctx.context.internalAdapter.createUser({\n\t\t\t\t\t\t\t\temail: email,\n\t\t\t\t\t\t\t\temailVerified: true,\n\t\t\t\t\t\t\t\tname: name || \"\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tisNewUser = true;\n\t\t\t\t\t\t\tuser = newUser;\n\t\t\t\t\t\t\tif (!user) {\n\t\t\t\t\t\t\t\tredirectWithError(\"failed_to_create_user\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tredirectWithError(\"new_user_signup_disabled\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!user.emailVerified) {\n\t\t\t\t\t\tuser = await ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\t\t\temailVerified: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\tuser.id,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\tredirectWithError(\"failed_to_create_session\");\n\t\t\t\t\t}\n\n\t\t\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\t\t\tsession,\n\t\t\t\t\t\tuser,\n\t\t\t\t\t});\n\t\t\t\t\tif (!ctx.query.callbackURL) {\n\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\ttoken: session.token,\n\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\tid: user.id,\n\t\t\t\t\t\t\t\temail: user.email,\n\t\t\t\t\t\t\t\temailVerified: user.emailVerified,\n\t\t\t\t\t\t\t\tname: user.name,\n\t\t\t\t\t\t\t\timage: user.image,\n\t\t\t\t\t\t\t\tcreatedAt: user.createdAt,\n\t\t\t\t\t\t\t\tupdatedAt: user.updatedAt,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (isNewUser) {\n\t\t\t\t\t\tthrow ctx.redirect(newUserCallbackURL);\n\t\t\t\t\t}\n\t\t\t\t\tthrow ctx.redirect(callbackURL);\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\trateLimit: [\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tpath.startsWith(\"/sign-in/magic-link\") ||\n\t\t\t\t\t\tpath.startsWith(\"/magic-link/verify\")\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\twindow: opts.rateLimit?.window || 60,\n\t\t\t\tmax: opts.rateLimit?.max || 5,\n\t\t\t},\n\t\t],\n\t\toptions,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { OAuthAccessToken, OIDCMetadata, OIDCOptions } from "../oidc-provider/ty
2
2
  import "../oidc-provider/index.mjs";
3
3
  import { BetterAuthOptions, GenericEndpointContext } from "@better-auth/core";
4
4
  import * as z from "zod";
5
- import * as better_call261 from "better-call";
5
+ import * as better_call244 from "better-call";
6
6
 
7
7
  //#region src/plugins/mcp/index.d.ts
8
8
  interface MCPOptions {
@@ -24,18 +24,18 @@ declare const mcp: (options: MCPOptions) => {
24
24
  hooks: {
25
25
  after: {
26
26
  matcher(): true;
27
- handler: (inputContext: better_call261.MiddlewareInputContext<better_call261.MiddlewareOptions>) => Promise<void>;
27
+ handler: (inputContext: better_call244.MiddlewareInputContext<better_call244.MiddlewareOptions>) => Promise<void>;
28
28
  }[];
29
29
  };
30
30
  endpoints: {
31
- oAuthConsent: better_call261.StrictEndpoint<"/oauth2/consent", {
31
+ oAuthConsent: better_call244.StrictEndpoint<"/oauth2/consent", {
32
32
  method: "POST";
33
33
  operationId: string;
34
34
  body: z.ZodObject<{
35
35
  accept: z.ZodBoolean;
36
36
  consent_code: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
37
37
  }, z.core.$strip>;
38
- use: ((inputContext: better_call261.MiddlewareInputContext<better_call261.MiddlewareOptions>) => Promise<{
38
+ use: ((inputContext: better_call244.MiddlewareInputContext<better_call244.MiddlewareOptions>) => Promise<{
39
39
  session: {
40
40
  session: Record<string, any> & {
41
41
  id: string;
@@ -107,13 +107,13 @@ declare const mcp: (options: MCPOptions) => {
107
107
  }, {
108
108
  redirectURI: string;
109
109
  }>;
110
- getMcpOAuthConfig: better_call261.StrictEndpoint<"/.well-known/oauth-authorization-server", {
110
+ getMcpOAuthConfig: better_call244.StrictEndpoint<"/.well-known/oauth-authorization-server", {
111
111
  method: "GET";
112
112
  metadata: {
113
113
  readonly scope: "server";
114
114
  };
115
115
  }, OIDCMetadata | null>;
116
- getMCPProtectedResource: better_call261.StrictEndpoint<"/.well-known/oauth-protected-resource", {
116
+ getMCPProtectedResource: better_call244.StrictEndpoint<"/.well-known/oauth-protected-resource", {
117
117
  method: "GET";
118
118
  metadata: {
119
119
  readonly scope: "server";
@@ -126,7 +126,7 @@ declare const mcp: (options: MCPOptions) => {
126
126
  bearer_methods_supported: string[];
127
127
  resource_signing_alg_values_supported: string[];
128
128
  }>;
129
- mcpOAuthAuthorize: better_call261.StrictEndpoint<"/mcp/authorize", {
129
+ mcpOAuthAuthorize: better_call244.StrictEndpoint<"/mcp/authorize", {
130
130
  method: "GET";
131
131
  query: z.ZodRecord<z.ZodString, z.ZodAny>;
132
132
  metadata: {
@@ -149,7 +149,7 @@ declare const mcp: (options: MCPOptions) => {
149
149
  };
150
150
  };
151
151
  }, void>;
152
- mcpOAuthToken: better_call261.StrictEndpoint<"/mcp/token", {
152
+ mcpOAuthToken: better_call244.StrictEndpoint<"/mcp/token", {
153
153
  method: "POST";
154
154
  body: z.ZodRecord<z.ZodAny, z.ZodAny>;
155
155
  metadata: {
@@ -170,7 +170,7 @@ declare const mcp: (options: MCPOptions) => {
170
170
  scope: string;
171
171
  id_token: string | undefined;
172
172
  }>;
173
- registerMcpClient: better_call261.StrictEndpoint<"/mcp/register", {
173
+ registerMcpClient: better_call244.StrictEndpoint<"/mcp/register", {
174
174
  method: "POST";
175
175
  body: z.ZodObject<{
176
176
  redirect_uris: z.ZodArray<z.ZodString>;
@@ -288,7 +288,7 @@ declare const mcp: (options: MCPOptions) => {
288
288
  };
289
289
  };
290
290
  }, Response>;
291
- getMcpSession: better_call261.StrictEndpoint<"/mcp/get-session", {
291
+ getMcpSession: better_call244.StrictEndpoint<"/mcp/get-session", {
292
292
  method: "GET";
293
293
  requireHeaders: true;
294
294
  }, OAuthAccessToken | null>;
@@ -428,6 +428,7 @@ declare const mcp: (options: MCPOptions) => {
428
428
  };
429
429
  };
430
430
  };
431
+ options: MCPOptions;
431
432
  };
432
433
  declare const withMcpAuth: <Auth extends {
433
434
  api: {
@@ -646,7 +646,8 @@ const mcp = (options) => {
646
646
  return c.json(accessTokenData);
647
647
  })
648
648
  },
649
- schema
649
+ schema,
650
+ options
650
651
  };
651
652
  };
652
653
  const withMcpAuth = (auth, handler) => {