Truncate Notion document titles to fit validation limits (#9041)

closes #9040
This commit is contained in:
codegen-sh[bot]
2025-04-24 11:57:19 +00:00
committed by GitHub
parent de6c1735d9
commit 2cc5846f1b

View File

@@ -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) {