diff --git a/plugins/notion/server/notion.ts b/plugins/notion/server/notion.ts index 22a7783517..9508399407 100644 --- a/plugins/notion/server/notion.ts +++ b/plugins/notion/server/notion.ts @@ -15,9 +15,11 @@ import { import { RateLimit } from "async-sema"; import emojiRegex from "emoji-regex"; import compact from "lodash/compact"; +import truncate from "lodash/truncate"; import { z } from "zod"; import { Second } from "@shared/utils/time"; import { isUrl } from "@shared/utils/urls"; +import { CollectionValidation, DocumentValidation } from "@shared/validations"; import { NotionUtils } from "../shared/NotionUtils"; import { Block, Page, PageType } from "../shared/types"; import env from "./env"; @@ -116,7 +118,9 @@ export class NotionClient { pages.push({ type: item.object === "page" ? PageType.Page : PageType.Database, id: item.id, - name: this.parseTitle(item), + name: this.parseTitle(item, { + maxLength: CollectionValidation.maxNameLength, + }), emoji: this.parseEmoji(item), }); } @@ -162,7 +166,6 @@ export class NotionClient { cursor = response.next_cursor ?? undefined; } - // Recursive fetch when direct children have their own children. await Promise.all( blocks.map(async (block) => { if ( @@ -203,7 +206,9 @@ export class NotionClient { return { type: PageType.Page, id: item.id, - name: this.parseTitle(item), + name: this.parseTitle(item, { + maxLength: DocumentValidation.maxTitleLength, + }), emoji: this.parseEmoji(item), }; }) @@ -227,7 +232,9 @@ export class NotionClient { const author = await this.fetchUsername(page.created_by.id); return { - title: this.parseTitle(page), + title: this.parseTitle(page, { + maxLength: DocumentValidation.maxTitleLength, + }), emoji: this.parseEmoji(page), author: author ?? undefined, createdAt: !page.created_time ? undefined : new Date(page.created_time), @@ -246,7 +253,9 @@ export class NotionClient { const author = await this.fetchUsername(database.created_by.id); return { - title: this.parseTitle(database), + title: this.parseTitle(database, { + maxLength: DocumentValidation.maxTitleLength, + }), emoji: this.parseEmoji(database), author: author ?? undefined, createdAt: !database.created_time @@ -267,12 +276,12 @@ export class NotionClient { return user.name; } - // bot belongs to a user, get the user's name. + // bot belongs to a user, get the user's name if (user.bot.owner.type === "user" && isFullUser(user.bot.owner.user)) { return user.bot.owner.user.name; } - // bot belongs to a workspace, fallback to bot's name. + // bot belongs to a workspace, fallback to bot's name return user.name; } catch (error) { // Handle the case where a user can't be found @@ -286,7 +295,12 @@ export class NotionClient { } } - private parseTitle(item: PageObjectResponse | DatabaseObjectResponse) { + private parseTitle( + item: PageObjectResponse | DatabaseObjectResponse, + { + maxLength = DocumentValidation.maxTitleLength, + }: { maxLength?: number } = {} + ) { let richTexts: RichTextItemResponse[]; if (item.object === "page") { @@ -298,7 +312,10 @@ export class NotionClient { richTexts = item.title; } - return richTexts.map((richText) => richText.plain_text).join(""); + const title = richTexts.map((richText) => richText.plain_text).join(""); + + // Truncate title to fit within validation limits + return truncate(title, { length: maxLength }); } private parseEmoji(item: PageObjectResponse | DatabaseObjectResponse) {