better-auth 1.7.0-rc.0 → 1.7.0-rc.1

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.
@@ -274,17 +274,22 @@ async function getMigrations(config) {
274
274
  if (toBeAdded.length) for (const table of toBeAdded) for (const [fieldName, field] of Object.entries(table.fields)) {
275
275
  const type = getType(field, fieldName);
276
276
  const builder = db.schema.alterTable(table.table);
277
- if (field.index) {
277
+ if (field.index || field.unique) {
278
278
  const indexName = `${table.table}_${fieldName}_${field.unique ? "uidx" : "idx"}`;
279
- const indexBuilder = db.schema.createIndex(indexName).on(table.table).columns([fieldName]);
280
- deferredIndexes.push(field.unique ? indexBuilder.unique() : indexBuilder);
279
+ let indexBuilder = db.schema.createIndex(indexName).on(table.table).columns([fieldName]);
280
+ if (field.unique) {
281
+ indexBuilder = indexBuilder.unique();
282
+ if (field.required === false && dbType === "mssql") indexBuilder = indexBuilder.where(fieldName, "is not", null);
283
+ if (field.required !== false && field.defaultValue !== void 0 && field.defaultValue !== null && typeof field.defaultValue !== "function") logger.warn(`Adding unique column "${fieldName}" to existing table "${table.table}" backfills every existing row with its default value. If the table has more than one row, creating the unique index "${indexName}" will fail; backfill distinct values manually, then re-run the migration or create the index yourself.`);
284
+ }
285
+ deferredIndexes.push(indexBuilder);
281
286
  }
282
287
  const built = builder.addColumn(fieldName, type, (col) => {
283
288
  col = field.required !== false ? col.notNull() : col;
284
289
  if (field.references) col = col.references(getReferencePath(field.references.model, field.references.field)).onDelete(field.references.onDelete || "cascade");
285
- if (field.unique) col = col.unique();
286
290
  if (field.type === "date" && typeof field.defaultValue === "function" && (dbType === "postgres" || dbType === "mysql" || dbType === "mssql")) if (dbType === "mysql") col = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`);
287
291
  else col = col.defaultTo(sql`CURRENT_TIMESTAMP`);
292
+ else if (!(field.unique && field.required === false) && (field.type === "string" || field.type === "number" || field.type === "boolean") && field.defaultValue !== void 0 && field.defaultValue !== null && typeof field.defaultValue !== "function") col = col.defaultTo(typeof field.defaultValue === "boolean" && (dbType === "sqlite" || dbType === "mssql") ? field.defaultValue ? 1 : 0 : field.defaultValue);
288
293
  return col;
289
294
  });
290
295
  migrations.push(built);
package/dist/package.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "1.7.0-rc.0";
2
+ var version = "1.7.0-rc.1";
3
3
  //#endregion
4
4
  export { version };
@@ -8,6 +8,7 @@ import { MicrosoftEntraIdOptions, microsoftEntraId } from "./providers/microsoft
8
8
  import { OktaOptions, okta } from "./providers/okta.mjs";
9
9
  import { PatreonOptions, patreon } from "./providers/patreon.mjs";
10
10
  import { SlackOptions, slack } from "./providers/slack.mjs";
11
+ import { YandexOptions, yandex } from "./providers/yandex.mjs";
11
12
  import { AuthContext } from "@better-auth/core";
12
13
  import * as _better_auth_core_oauth20 from "@better-auth/core/oauth2";
13
14
  import { OAuthProvider } from "@better-auth/core/oauth2";
@@ -48,4 +49,4 @@ declare const genericOAuth: <const ID extends string>(options: GenericOAuthOptio
48
49
  };
49
50
  };
50
51
  //#endregion
51
- export { Auth0Options, BaseOAuthProviderOptions, type GenericOAuthConfig, type GenericOAuthOptions, type GenericOAuthUserInfo, GumroadOptions, HubSpotOptions, KeycloakOptions, LineOptions, MicrosoftEntraIdOptions, OktaOptions, PatreonOptions, SlackOptions, auth0, genericOAuth, gumroad, hubspot, keycloak, line, microsoftEntraId, okta, patreon, slack };
52
+ export { Auth0Options, BaseOAuthProviderOptions, type GenericOAuthConfig, type GenericOAuthOptions, type GenericOAuthUserInfo, GumroadOptions, HubSpotOptions, KeycloakOptions, LineOptions, MicrosoftEntraIdOptions, OktaOptions, PatreonOptions, SlackOptions, YandexOptions, auth0, genericOAuth, gumroad, hubspot, keycloak, line, microsoftEntraId, okta, patreon, slack, yandex };
@@ -9,6 +9,7 @@ import { microsoftEntraId } from "./providers/microsoft-entra-id.mjs";
9
9
  import { okta } from "./providers/okta.mjs";
10
10
  import { patreon } from "./providers/patreon.mjs";
11
11
  import { slack } from "./providers/slack.mjs";
12
+ import { yandex } from "./providers/yandex.mjs";
12
13
  import { APIError } from "@better-auth/core/error";
13
14
  import { applyDefaultAccessTokenExpiry, createAuthorizationURL, refreshAccessToken, validateAuthorizationCode, verifyProviderIdToken } from "@better-auth/core/oauth2";
14
15
  import { createRemoteJWKSet, decodeJwt } from "jose";
@@ -238,4 +239,4 @@ const genericOAuth = (options) => {
238
239
  };
239
240
  };
240
241
  //#endregion
241
- export { auth0, genericOAuth, gumroad, hubspot, keycloak, line, microsoftEntraId, okta, patreon, slack };
242
+ export { auth0, genericOAuth, gumroad, hubspot, keycloak, line, microsoftEntraId, okta, patreon, slack, yandex };
@@ -6,4 +6,5 @@ import { LineOptions, line } from "./line.mjs";
6
6
  import { MicrosoftEntraIdOptions, microsoftEntraId } from "./microsoft-entra-id.mjs";
7
7
  import { OktaOptions, okta } from "./okta.mjs";
8
8
  import { PatreonOptions, patreon } from "./patreon.mjs";
9
- import { SlackOptions, slack } from "./slack.mjs";
9
+ import { SlackOptions, slack } from "./slack.mjs";
10
+ import { YandexOptions, yandex } from "./yandex.mjs";
@@ -0,0 +1,29 @@
1
+ import { GenericOAuthConfig } from "../types.mjs";
2
+ import { BaseOAuthProviderOptions } from "../index.mjs";
3
+
4
+ //#region src/plugins/generic-oauth/providers/yandex.d.ts
5
+ interface YandexOptions extends BaseOAuthProviderOptions {}
6
+ /**
7
+ * Yandex OAuth provider helper
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { genericOAuth, yandex } from "better-auth/plugins/generic-oauth";
12
+ *
13
+ * export const auth = betterAuth({
14
+ * plugins: [
15
+ * genericOAuth({
16
+ * config: [
17
+ * yandex({
18
+ * clientId: process.env.YANDEX_CLIENT_ID,
19
+ * clientSecret: process.env.YANDEX_CLIENT_SECRET,
20
+ * }),
21
+ * ],
22
+ * }),
23
+ * ],
24
+ * });
25
+ * ```
26
+ */
27
+ declare function yandex(options: YandexOptions): GenericOAuthConfig;
28
+ //#endregion
29
+ export { YandexOptions, yandex };
@@ -0,0 +1,63 @@
1
+ import { betterFetch } from "@better-fetch/fetch";
2
+ //#region src/plugins/generic-oauth/providers/yandex.ts
3
+ /**
4
+ * Yandex OAuth provider helper
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { genericOAuth, yandex } from "better-auth/plugins/generic-oauth";
9
+ *
10
+ * export const auth = betterAuth({
11
+ * plugins: [
12
+ * genericOAuth({
13
+ * config: [
14
+ * yandex({
15
+ * clientId: process.env.YANDEX_CLIENT_ID,
16
+ * clientSecret: process.env.YANDEX_CLIENT_SECRET,
17
+ * }),
18
+ * ],
19
+ * }),
20
+ * ],
21
+ * });
22
+ * ```
23
+ */
24
+ function yandex(options) {
25
+ const defaultScopes = [
26
+ "login:info",
27
+ "login:email",
28
+ "login:avatar"
29
+ ];
30
+ const getUserInfo = async (tokens) => {
31
+ const { data: profile, error } = await betterFetch("https://login.yandex.ru/info?format=json", {
32
+ method: "GET",
33
+ headers: { Authorization: `OAuth ${tokens.accessToken}` }
34
+ });
35
+ if (error || !profile) return null;
36
+ const email = profile.default_email ?? profile.emails?.[0];
37
+ if (!email) return null;
38
+ return {
39
+ id: profile.id,
40
+ name: profile.display_name ?? profile.real_name ?? profile.first_name ?? profile.login,
41
+ email,
42
+ emailVerified: false,
43
+ image: !profile.is_avatar_empty && profile.default_avatar_id ? `https://avatars.yandex.net/get-yapic/${profile.default_avatar_id}/islands-200` : void 0
44
+ };
45
+ };
46
+ return {
47
+ providerId: "yandex",
48
+ authorizationUrl: "https://oauth.yandex.com/authorize",
49
+ tokenUrl: "https://oauth.yandex.com/token",
50
+ clientId: options.clientId,
51
+ clientSecret: options.clientSecret,
52
+ tokenEndpointAuth: options.tokenEndpointAuth,
53
+ scopes: options.scopes ?? defaultScopes,
54
+ redirectURI: options.redirectURI,
55
+ pkce: options.pkce,
56
+ disableImplicitSignUp: options.disableImplicitSignUp,
57
+ disableSignUp: options.disableSignUp,
58
+ overrideUserInfo: options.overrideUserInfo,
59
+ getUserInfo
60
+ };
61
+ }
62
+ //#endregion
63
+ export { yandex };
@@ -27,6 +27,7 @@ import { MicrosoftEntraIdOptions, microsoftEntraId } from "./generic-oauth/provi
27
27
  import { OktaOptions, okta } from "./generic-oauth/providers/okta.mjs";
28
28
  import { PatreonOptions, patreon } from "./generic-oauth/providers/patreon.mjs";
29
29
  import { SlackOptions, slack } from "./generic-oauth/providers/slack.mjs";
30
+ import { YandexOptions, yandex } from "./generic-oauth/providers/yandex.mjs";
30
31
  import { BaseOAuthProviderOptions, genericOAuth } from "./generic-oauth/index.mjs";
31
32
  import { HaveIBeenPwnedOptions, haveIBeenPwned } from "./haveibeenpwned/index.mjs";
32
33
  import { JWKOptions, JWSAlgorithms, Jwk, JwtOptions, ResolvedSigningKey } from "./jwt/types.mjs";
@@ -63,4 +64,4 @@ import { USERNAME_ERROR_CODES } from "./username/error-codes.mjs";
63
64
  import { UsernameOptions, username } from "./username/index.mjs";
64
65
  import { hasPermission } from "./organization/has-permission.mjs";
65
66
  import { DefaultOrganizationPlugin, DynamicAccessControlEndpoints, OrganizationCreator, OrganizationEndpoints, OrganizationPlugin, TeamEndpoints, organization, parseRoles } from "./organization/organization.mjs";
66
- export { AccessControl, AdminOptions, AnonymousOptions, AnonymousSession, ArrayElement, Auth0Options, AuthorizeResponse, BackupCodeOptions, BaseCaptchaOptions, BaseOAuthProviderOptions, BearerOptions, CaptchaFoxOptions, CaptchaOptions, CloudflareTurnstileOptions, CustomSessionPluginOptions, DefaultOrganizationPlugin, DeviceAuthorizationOptions, DynamicAccessControlEndpoints, MULTI_SESSION_ERROR_CODES as ERROR_CODES, EmailOTPOptions, ExactRoleStatements, FieldSchema, GenericOAuthConfig, GenericOAuthOptions, GenericOAuthUserInfo, GoogleRecaptchaOptions, GumroadOptions, HCaptchaOptions, HIDE_METADATA, HaveIBeenPwnedOptions, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOptionSchema, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginContext, InferPluginErrorCodes, InferPluginIDs, InferTeam, Invitation, InvitationInput, InvitationStatus, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodOptions, LineOptions, LoginResult, MagicLinkOptions, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, OAuthPopupData, OAuthPopupMessage, OAuthProxyOptions, OTPOptions, OktaOptions, OneTapOptions, OneTimeTokenOptions, OpenAPIModelSchema, OpenAPIOptions, OpenAPIParameter, OpenAPISchema, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, POPUP_MARKER_COOKIE, Path, PatreonOptions, PhoneNumberOptions, Provider, ResolvedSigningKey, Role, RoleAuthorizeRequest, RoleInput, RoleStatements, SIWEPluginOptions, SessionWithImpersonatedBy, SlackOptions, Statements, SubArray, Subset, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, TestCookie, TestHelpers, TestUtilsOptions, TimeString, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UserWithAnonymous, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, UsernameOptions, admin, anonymous, auth0, backupCode2fa, bearer, captcha, createAccessControl, createJwk, customSession, defaultRolesSchema, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, encodeBackupCodes, generateBackupCodes, generateExportedKeyPair, generator, genericOAuth, getBackupCodes, getJwtToken, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, invitationSchema, invitationStatus, jwt, keycloak, lastLoginMethod, line, magicLink, memberSchema, microsoftEntraId, ms, multiSession, oAuthProxy, oauthPopup, okta, oneTap, oneTimeToken, openAPI, organization, organizationRoleSchema, organizationSchema, otp2fa, parseRoles, patreon, phoneNumber, resolveSigningKey, role, roleSchema, sec, signJWT, siwe, slack, teamMemberSchema, teamSchema, testUtils, toExpJWT, totp2fa, twoFactor, twoFactorClient, username, verifyBackupCode, verifyJWT };
67
+ export { AccessControl, AdminOptions, AnonymousOptions, AnonymousSession, ArrayElement, Auth0Options, AuthorizeResponse, BackupCodeOptions, BaseCaptchaOptions, BaseOAuthProviderOptions, BearerOptions, CaptchaFoxOptions, CaptchaOptions, CloudflareTurnstileOptions, CustomSessionPluginOptions, DefaultOrganizationPlugin, DeviceAuthorizationOptions, DynamicAccessControlEndpoints, MULTI_SESSION_ERROR_CODES as ERROR_CODES, EmailOTPOptions, ExactRoleStatements, FieldSchema, GenericOAuthConfig, GenericOAuthOptions, GenericOAuthUserInfo, GoogleRecaptchaOptions, GumroadOptions, HCaptchaOptions, HIDE_METADATA, HaveIBeenPwnedOptions, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOptionSchema, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginContext, InferPluginErrorCodes, InferPluginIDs, InferTeam, Invitation, InvitationInput, InvitationStatus, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodOptions, LineOptions, LoginResult, MagicLinkOptions, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, OAuthPopupData, OAuthPopupMessage, OAuthProxyOptions, OTPOptions, OktaOptions, OneTapOptions, OneTimeTokenOptions, OpenAPIModelSchema, OpenAPIOptions, OpenAPIParameter, OpenAPISchema, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, POPUP_MARKER_COOKIE, Path, PatreonOptions, PhoneNumberOptions, Provider, ResolvedSigningKey, Role, RoleAuthorizeRequest, RoleInput, RoleStatements, SIWEPluginOptions, SessionWithImpersonatedBy, SlackOptions, Statements, SubArray, Subset, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, TestCookie, TestHelpers, TestUtilsOptions, TimeString, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UserWithAnonymous, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, UsernameOptions, YandexOptions, admin, anonymous, auth0, backupCode2fa, bearer, captcha, createAccessControl, createJwk, customSession, defaultRolesSchema, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, encodeBackupCodes, generateBackupCodes, generateExportedKeyPair, generator, genericOAuth, getBackupCodes, getJwtToken, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, invitationSchema, invitationStatus, jwt, keycloak, lastLoginMethod, line, magicLink, memberSchema, microsoftEntraId, ms, multiSession, oAuthProxy, oauthPopup, okta, oneTap, oneTimeToken, openAPI, organization, organizationRoleSchema, organizationSchema, otp2fa, parseRoles, patreon, phoneNumber, resolveSigningKey, role, roleSchema, sec, signJWT, siwe, slack, teamMemberSchema, teamSchema, testUtils, toExpJWT, totp2fa, twoFactor, twoFactorClient, username, verifyBackupCode, verifyJWT, yandex };
@@ -24,6 +24,7 @@ import { microsoftEntraId } from "./generic-oauth/providers/microsoft-entra-id.m
24
24
  import { okta } from "./generic-oauth/providers/okta.mjs";
25
25
  import { patreon } from "./generic-oauth/providers/patreon.mjs";
26
26
  import { slack } from "./generic-oauth/providers/slack.mjs";
27
+ import { yandex } from "./generic-oauth/providers/yandex.mjs";
27
28
  import { genericOAuth } from "./generic-oauth/index.mjs";
28
29
  import { haveIBeenPwned } from "./haveibeenpwned/index.mjs";
29
30
  import { verifyJWT } from "./jwt/verify.mjs";
@@ -44,4 +45,4 @@ import { siwe } from "./siwe/index.mjs";
44
45
  import { testUtils } from "./test-utils/index.mjs";
45
46
  import { twoFactor } from "./two-factor/index.mjs";
46
47
  import { username } from "./username/index.mjs";
47
- export { MULTI_SESSION_ERROR_CODES as ERROR_CODES, HIDE_METADATA, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, POPUP_MARKER_COOKIE, TWO_FACTOR_ERROR_CODES, USERNAME_ERROR_CODES, admin, anonymous, auth0, bearer, captcha, createAccessControl, createJwk, customSession, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, generateExportedKeyPair, genericOAuth, getJwtToken, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, jwt, keycloak, lastLoginMethod, line, magicLink, microsoftEntraId, multiSession, oAuthProxy, oauthPopup, okta, oneTap, oneTimeToken, openAPI, organization, parseRoles, patreon, phoneNumber, resolveSigningKey, role, signJWT, siwe, slack, testUtils, toExpJWT, twoFactor, twoFactorClient, username, verifyJWT };
48
+ export { MULTI_SESSION_ERROR_CODES as ERROR_CODES, HIDE_METADATA, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, POPUP_MARKER_COOKIE, TWO_FACTOR_ERROR_CODES, USERNAME_ERROR_CODES, admin, anonymous, auth0, bearer, captcha, createAccessControl, createJwk, customSession, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, generateExportedKeyPair, genericOAuth, getJwtToken, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, jwt, keycloak, lastLoginMethod, line, magicLink, microsoftEntraId, multiSession, oAuthProxy, oauthPopup, okta, oneTap, oneTimeToken, openAPI, organization, parseRoles, patreon, phoneNumber, resolveSigningKey, role, signJWT, siwe, slack, testUtils, toExpJWT, twoFactor, twoFactorClient, username, verifyJWT, yandex };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-auth",
3
- "version": "1.7.0-rc.0",
3
+ "version": "1.7.0-rc.1",
4
4
  "description": "The most comprehensive authentication framework for TypeScript.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -465,13 +465,13 @@
465
465
  "kysely": "^0.28.17 || ^0.29.0",
466
466
  "nanostores": "^1.3.0",
467
467
  "zod": "^4.3.6",
468
- "@better-auth/core": "1.7.0-rc.0",
469
- "@better-auth/drizzle-adapter": "1.7.0-rc.0",
470
- "@better-auth/kysely-adapter": "1.7.0-rc.0",
471
- "@better-auth/memory-adapter": "1.7.0-rc.0",
472
- "@better-auth/mongo-adapter": "1.7.0-rc.0",
473
- "@better-auth/prisma-adapter": "1.7.0-rc.0",
474
- "@better-auth/telemetry": "1.7.0-rc.0"
468
+ "@better-auth/core": "1.7.0-rc.1",
469
+ "@better-auth/drizzle-adapter": "1.7.0-rc.1",
470
+ "@better-auth/kysely-adapter": "1.7.0-rc.1",
471
+ "@better-auth/memory-adapter": "1.7.0-rc.1",
472
+ "@better-auth/mongo-adapter": "1.7.0-rc.1",
473
+ "@better-auth/prisma-adapter": "1.7.0-rc.1",
474
+ "@better-auth/telemetry": "1.7.0-rc.1"
475
475
  },
476
476
  "devDependencies": {
477
477
  "@lynx-js/react": "^0.121.2",