UNPKG

@langchain/community

Version:
1 lines 20.8 kB
{"version":3,"file":"notionapi.cjs","names":["BaseDocumentLoader","AsyncCaller","Client","NotionToMarkdown","isFullBlock","yaml","Document","APIErrorCode"],"sources":["../../../src/document_loaders/web/notionapi.ts"],"sourcesContent":["import {\n APIResponseError,\n Client,\n isFullBlock,\n isFullPage,\n iteratePaginatedAPI,\n APIErrorCode,\n isNotionClientError,\n isFullDatabase,\n} from \"@notionhq/client\";\nimport { NotionToMarkdown } from \"notion-to-md\";\nimport { getBlockChildren } from \"notion-to-md/build/utils/notion.js\";\nimport type {\n ListBlockChildrenResponseResults,\n MdBlock,\n} from \"notion-to-md/build/types\";\nimport yaml from \"js-yaml\";\n\nimport { Document } from \"@langchain/core/documents\";\nimport { AsyncCaller } from \"@langchain/core/utils/async_caller\";\nimport { BaseDocumentLoader } from \"@langchain/core/document_loaders/base\";\n\n// oxlint-disable-next-line typescript/no-explicit-any\ntype GuardType<T> = T extends ((x: any, ...rest: any) => x is infer U)\n ? U\n : never;\n\nexport type GetBlockResponse = Parameters<typeof isFullBlock>[0];\nexport type GetPageResponse = Parameters<typeof isFullPage>[0];\nexport type GetDatabaseResponse = Parameters<typeof isFullDatabase>[0];\n\nexport type BlockObjectResponse = GuardType<typeof isFullBlock>;\nexport type PageObjectResponse = GuardType<typeof isFullPage>;\nexport type DatabaseObjectResponse = GuardType<typeof isFullDatabase>;\n\nexport type GetResponse =\n | GetBlockResponse\n | GetPageResponse\n | GetDatabaseResponse\n | APIResponseError;\n\nexport type PagePropertiesType = PageObjectResponse[\"properties\"];\nexport type PagePropertiesValue = PagePropertiesType[keyof PagePropertiesType];\n\nexport const isPageResponse = (res: GetResponse): res is GetPageResponse =>\n !isNotionClientError(res) && res.object === \"page\";\nexport const isDatabaseResponse = (\n res: GetResponse\n): res is GetDatabaseResponse =>\n !isNotionClientError(res) && res.object === \"database\";\nexport const isErrorResponse = (res: GetResponse): res is APIResponseError =>\n isNotionClientError(res);\n\nexport const isPage = (res: GetResponse): res is PageObjectResponse =>\n isPageResponse(res) && isFullPage(res);\nexport const isDatabase = (res: GetResponse): res is DatabaseObjectResponse =>\n isDatabaseResponse(res) && isFullDatabase(res);\n\nexport type OnDocumentLoadedCallback = (\n current: number,\n total: number,\n currentTitle?: string,\n rootTitle?: string\n) => void;\n\nexport type NotionAPILoaderOptions = {\n clientOptions: ConstructorParameters<typeof Client>[0];\n id: string;\n callerOptions?: ConstructorParameters<typeof AsyncCaller>[0];\n onDocumentLoaded?: OnDocumentLoadedCallback;\n propertiesAsHeader?: boolean;\n};\n\n/**\n * A class that extends the BaseDocumentLoader class. It represents a\n * document loader for loading documents from Notion using the Notion API.\n * @example\n * ```typescript\n * const pageLoader = new NotionAPILoader({\n * clientOptions: { auth: \"<NOTION_INTEGRATION_TOKEN>\" },\n * id: \"<PAGE_ID>\",\n * type: \"page\",\n * });\n * const pageDocs = await pageLoader.load();\n * const splitDocs = await splitter.splitDocuments(pageDocs);\n *\n * const dbLoader = new NotionAPILoader({\n * clientOptions: { auth: \"<NOTION_INTEGRATION_TOKEN>\" },\n * id: \"<DATABASE_ID>\",\n * type: \"database\",\n * propertiesAsHeader: true,\n * });\n * const dbDocs = await dbLoader.load();\n * ```\n */\nexport class NotionAPILoader extends BaseDocumentLoader {\n private caller: AsyncCaller;\n\n private notionClient: Client;\n\n private n2mClient: NotionToMarkdown;\n\n private id: string;\n\n private pageQueue: string[];\n\n private pageCompleted: string[];\n\n public pageQueueTotal: number;\n\n private documents: Document[];\n\n private rootTitle: string;\n\n private onDocumentLoaded: OnDocumentLoadedCallback;\n\n private propertiesAsHeader: boolean;\n\n constructor(options: NotionAPILoaderOptions) {\n super();\n\n this.caller = new AsyncCaller({\n maxConcurrency: 64,\n ...options.callerOptions,\n });\n this.notionClient = new Client({\n logger: () => {}, // Suppress Notion SDK logger\n ...options.clientOptions,\n });\n this.n2mClient = new NotionToMarkdown({\n notionClient: this.notionClient,\n config: { parseChildPages: false, convertImagesToBase64: false },\n });\n this.id = options.id;\n this.pageQueue = [];\n this.pageCompleted = [];\n this.pageQueueTotal = 0;\n this.documents = [];\n this.rootTitle = \"\";\n this.onDocumentLoaded = options.onDocumentLoaded ?? ((_ti, _cu) => {});\n this.propertiesAsHeader = options.propertiesAsHeader || false;\n }\n\n /**\n * Adds a selection of page ids to the pageQueue and removes duplicates.\n * @param items An array of string ids\n */\n private addToQueue(...items: string[]) {\n const deDuped = items.filter(\n (item) => !this.pageCompleted.concat(this.pageQueue).includes(item)\n );\n this.pageQueue.push(...deDuped);\n this.pageQueueTotal += deDuped.length;\n }\n\n /**\n * Parses a Notion GetResponse object (page or database) and returns a string of the title.\n * @param obj The Notion GetResponse object to parse.\n * @returns The string of the title.\n */\n private getTitle(obj: GetResponse) {\n if (isPage(obj)) {\n const titleProp = Object.values(obj.properties).find(\n (prop) => prop.type === \"title\"\n );\n if (titleProp) return this.getPropValue(titleProp);\n }\n if (isDatabase(obj))\n return obj.title\n .map((v) =>\n this.n2mClient.annotatePlainText(v.plain_text, v.annotations)\n )\n .join(\"\");\n return null;\n }\n\n /**\n * Parses the property type and returns a string\n * @param page The Notion page property to parse.\n * @returns A string of parsed property.\n */\n private getPropValue(prop: PagePropertiesValue) {\n switch (prop.type) {\n case \"number\": {\n const propNumber = prop[prop.type];\n return propNumber !== null ? propNumber.toString() : \"\";\n }\n case \"url\":\n return prop[prop.type] || \"\";\n case \"select\":\n return prop[prop.type]?.name ?? \"\";\n case \"multi_select\":\n return `[${prop[prop.type].map((v) => `\"${v.name}\"`).join(\", \")}]`;\n case \"status\":\n return prop[prop.type]?.name ?? \"\";\n case \"date\":\n return `${prop[prop.type]?.start ?? \"\"}${\n prop[prop.type]?.end ? ` - ${prop[prop.type]?.end}` : \"\"\n }`;\n case \"email\":\n return prop[prop.type] || \"\";\n case \"phone_number\":\n return prop[prop.type] || \"\";\n case \"checkbox\":\n return prop[prop.type].toString();\n case \"files\":\n return `[${prop[prop.type].map((v) => `\"${v.name}\"`).join(\", \")}]`;\n case \"created_by\":\n return `[\"${prop[prop.type].object}\", \"${prop[prop.type].id}\"]`;\n case \"created_time\":\n return prop[prop.type];\n case \"last_edited_by\":\n return `[\"${prop[prop.type].object}\", \"${prop[prop.type].id}\"]`;\n case \"last_edited_time\":\n return prop[prop.type];\n case \"title\":\n return prop[prop.type]\n .map((v) =>\n this.n2mClient.annotatePlainText(v.plain_text, v.annotations)\n )\n .join(\"\");\n case \"rich_text\":\n return prop[prop.type]\n .map((v) =>\n this.n2mClient.annotatePlainText(v.plain_text, v.annotations)\n )\n .join(\"\");\n case \"people\":\n return `[${prop[prop.type]\n .map((v) => `[\"${v.object}\", \"${v.id}\"]`)\n .join(\", \")}]`;\n case \"unique_id\":\n return `${prop[prop.type].prefix || \"\"}${prop[prop.type].number}`;\n case \"relation\":\n return `[${prop[prop.type].map((v) => `\"${v.id}\"`).join(\", \")}]`;\n default:\n return `Unsupported type: ${prop.type}`;\n }\n }\n\n /**\n * Parses the properties of a Notion page and returns them as key-value\n * pairs.\n * @param page The Notion page to parse.\n * @returns An object containing the parsed properties as key-value pairs.\n */\n private parsePageProperties(page: PageObjectResponse) {\n return Object.entries(page.properties).reduce(\n (accum, [propName, prop]) => {\n const value = this.getPropValue(prop);\n const props = { ...accum, [propName]: value };\n return prop.type === \"title\" ? { ...props, _title: value } : props;\n },\n {} as { [key: string]: string }\n );\n }\n\n /**\n * Parses the details of a Notion page and returns them as an object.\n * @param page The Notion page to parse.\n * @returns An object containing the parsed details of the page.\n */\n private parsePageDetails(page: PageObjectResponse) {\n const { id, ...rest } = page;\n return {\n ...rest,\n notionId: id,\n properties: this.parsePageProperties(page),\n };\n }\n\n /**\n * Loads a Notion block and returns it as an MdBlock object.\n * @param block The Notion block to load.\n * @returns A Promise that resolves to an MdBlock object.\n */\n private async loadBlock(block: BlockObjectResponse): Promise<MdBlock> {\n const mdBlock: MdBlock = {\n type: block.type,\n blockId: block.id,\n parent: await this.caller.call(() =>\n this.n2mClient.blockToMarkdown(block)\n ),\n children: [],\n };\n\n if (block.has_children) {\n const block_id =\n block.type === \"synced_block\" &&\n block.synced_block?.synced_from?.block_id\n ? block.synced_block.synced_from.block_id\n : block.id;\n\n const childBlocks = await this.loadBlocks(\n await this.caller.call(() =>\n getBlockChildren(this.notionClient, block_id, null)\n )\n );\n\n mdBlock.children = childBlocks;\n }\n\n return mdBlock;\n }\n\n /**\n * Loads Notion blocks and their children recursively.\n * @param blocksResponse The response from the Notion API containing the blocks to load.\n * @returns A Promise that resolves to an array containing the loaded MdBlocks.\n */\n private async loadBlocks(\n blocksResponse: ListBlockChildrenResponseResults\n ): Promise<MdBlock[]> {\n const blocks = blocksResponse.filter(isFullBlock);\n\n // Add child pages to queue\n const childPages = blocks\n .filter((block) => block.type.includes(\"child_page\"))\n .map((block) => block.id);\n if (childPages.length > 0) this.addToQueue(...childPages);\n\n // Add child database pages to queue\n const childDatabases = blocks\n .filter((block) => block.type.includes(\"child_database\"))\n .map((block) => this.caller.call(() => this.loadDatabase(block.id)));\n\n // Load this block and child blocks\n const loadingMdBlocks = blocks\n .filter((block) => ![\"child_page\", \"child_database\"].includes(block.type))\n .map((block) => this.loadBlock(block));\n\n const [mdBlocks] = await Promise.all([\n Promise.all(loadingMdBlocks),\n Promise.all(childDatabases),\n ]);\n\n return mdBlocks;\n }\n\n /**\n * Loads a Notion page and its child documents, then adds it to the completed documents array.\n * @param page The Notion page or page ID to load.\n */\n private async loadPage(page: string | PageObjectResponse) {\n // Check page is a page ID or a PageObjectResponse\n const [pageData, pageId] =\n typeof page === \"string\"\n ? [\n this.caller.call(() =>\n this.notionClient.pages.retrieve({ page_id: page })\n ),\n page,\n ]\n : [page, page.id];\n\n const [pageDetails, pageBlocks] = await Promise.all([\n pageData,\n this.caller.call(() => getBlockChildren(this.notionClient, pageId, null)),\n ]);\n\n if (!isFullPage(pageDetails)) {\n this.pageCompleted.push(pageId);\n return;\n }\n\n const mdBlocks = await this.loadBlocks(pageBlocks);\n const mdStringObject = this.n2mClient.toMarkdownString(mdBlocks);\n\n let pageContent = mdStringObject.parent;\n const metadata = this.parsePageDetails(pageDetails);\n\n if (this.propertiesAsHeader) {\n pageContent =\n `---\\n` +\n `${yaml.dump(metadata.properties)}` +\n `---\\n\\n` +\n `${pageContent ?? \"\"}`;\n }\n\n if (!pageContent) {\n this.pageCompleted.push(pageId);\n return;\n }\n\n const pageDocument = new Document({ pageContent, metadata });\n\n this.documents.push(pageDocument);\n this.pageCompleted.push(pageId);\n this.onDocumentLoaded(\n this.documents.length,\n this.pageQueueTotal,\n this.getTitle(pageDetails) || undefined,\n this.rootTitle\n );\n }\n\n /**\n * Loads a Notion database and adds it's pages to the queue.\n * @param id The ID of the Notion database to load.\n */\n private async loadDatabase(id: string) {\n try {\n for await (const page of iteratePaginatedAPI(\n this.notionClient.databases.query,\n {\n database_id: id,\n page_size: 50,\n }\n )) {\n this.addToQueue(page.id);\n }\n } catch (e) {\n console.log(e);\n // TODO: Catch and report api request errors\n }\n }\n\n /**\n * Loads the documents from Notion based on the specified options.\n * @returns A Promise that resolves to an array of Documents.\n */\n async load(): Promise<Document[]> {\n const resPagePromise = this.notionClient.pages\n .retrieve({ page_id: this.id })\n .then((res) => {\n this.addToQueue(this.id);\n return res;\n })\n .catch((error: APIResponseError) => error);\n\n const resDatabasePromise = this.notionClient.databases\n .retrieve({ database_id: this.id })\n .then(async (res) => {\n await this.loadDatabase(this.id);\n return res;\n })\n .catch((error: APIResponseError) => error);\n\n const [resPage, resDatabase] = await Promise.all([\n resPagePromise,\n resDatabasePromise,\n ]);\n\n // Check if both resPage and resDatabase resulted in error responses\n const errors = [resPage, resDatabase].filter(isErrorResponse);\n if (errors.length === 2) {\n if (errors.every((e) => e.code === APIErrorCode.ObjectNotFound)) {\n throw new AggregateError([\n Error(\n `Could not find object with ID: ${this.id}. Make sure the relevant pages and databases are shared with your integration.`\n ),\n ...errors,\n ]);\n }\n throw new AggregateError(errors);\n }\n\n this.rootTitle =\n this.getTitle(resPage) || this.getTitle(resDatabase) || this.id;\n\n let pageId = this.pageQueue.shift();\n while (pageId) {\n await this.loadPage(pageId);\n pageId = this.pageQueue.shift();\n }\n return this.documents;\n }\n}\n"],"mappings":"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"}