fix(notion)!: align person owner and verification claims

This commit is contained in:
Taesu
2026-10-17 05:53:09 +09:00
parent b245cbcc4a
commit 1deed434bb
3 changed files with 29 additions and 8 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
"@better-auth/core": minor
---
Allow partial Notion owner profiles and nullable display fields in `NotionProfile`, and leave the local image unset when no owner avatar is returned. Existing user images are preserved when profile updates are enabled and the provider returns no image.
Notion profile mappings now handle partial person owners, nullable names and avatars, and the optional email verification claim. Missing avatars preserve stored images when profile updates are enabled; the default email trust policy is unchanged.
+2 -1
View File
@@ -10,12 +10,13 @@ import {
export interface NotionProfile {
object: "user";
id: string;
type?: "person" | "bot" | undefined;
type?: "person" | undefined;
name?: string | null | undefined;
avatar_url?: string | null | undefined;
person?:
| {
email?: string;
email_verified?: boolean;
}
| undefined;
}
@@ -461,6 +461,7 @@ describe("cognito provider", () => {
/**
* @see https://github.com/makenotion/notion-sdk-js/blob/v2.2.15/src/api-endpoints.ts
* @see https://github.com/makenotion/notion-sdk-js/blob/v2.2.15/src/Client.ts
* @see https://developers.notion.com/page/changelog#new-identity-fields-in-oauth-token-responses
*/
describe("notion owner profiles", () => {
it.each([null, "https://example.com/owner.png"])(
@@ -472,15 +473,21 @@ describe("notion owner profiles", () => {
type: "person",
name: null,
avatar_url,
person: { email: "owner@example.com" },
person: { email: "owner@example.com", email_verified: true },
} satisfies NotionProfile;
mockedBetterFetch.mockResolvedValueOnce({
data: {
object: "user",
type: "bot",
id: "notion-bot",
name: "Integration Bot",
avatar_url: "https://example.com/bot.png",
bot: { owner: { type: "user", user: owner } },
bot: {
owner: { type: "user", user: owner },
workspace_name: "Workspace",
workspace_icon: null,
workspace_id: "workspace-id",
},
},
error: null,
});
@@ -489,6 +496,9 @@ describe("notion owner profiles", () => {
expectTypeOf(profile.avatar_url).toEqualTypeOf<
string | null | undefined
>();
expectTypeOf(profile.person?.email_verified).toEqualTypeOf<
boolean | undefined
>();
return {};
});
const provider = notion({ ...credentials, mapProfileToUser });
@@ -521,15 +531,25 @@ describe("notion owner profiles", () => {
id: "notion-owner",
} satisfies NotionProfile;
mockedBetterFetch.mockResolvedValueOnce({
data: { bot: { owner: { type: "user", user: owner } } },
data: {
object: "user",
id: "notion-bot",
type: "bot",
name: "Integration Bot",
avatar_url: null,
bot: {
owner: { type: "user", user: owner },
workspace_name: "Workspace",
workspace_icon: null,
workspace_id: "workspace-id",
},
},
error: null,
});
const provider = notion({
...credentials,
mapProfileToUser(profile) {
expectTypeOf(profile.type).toEqualTypeOf<
"person" | "bot" | undefined
>();
expectTypeOf(profile.type).toEqualTypeOf<"person" | undefined>();
return {
name: profile.name ?? "Mapped Owner",
email: profile.person?.email ?? `${profile.id}@example.com`,