@notionhq/client 5.25.0 → 5.25.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.
- package/build/package.json +1 -1
- package/build/src/helpers.js +2 -2
- package/build/src/helpers.js.map +1 -1
- package/package.json +1 -1
package/build/package.json
CHANGED
package/build/src/helpers.js
CHANGED
|
@@ -273,13 +273,13 @@ function isFullPage(response) {
|
|
|
273
273
|
* @returns `true` if `response` is a full `DataSourceObjectResponse`.
|
|
274
274
|
*/
|
|
275
275
|
function isFullDataSource(response) {
|
|
276
|
-
return response.object === "data_source";
|
|
276
|
+
return response.object === "data_source" && "title" in response;
|
|
277
277
|
}
|
|
278
278
|
/**
|
|
279
279
|
* @returns `true` if `response` is a full `DatabaseObjectResponse`.
|
|
280
280
|
*/
|
|
281
281
|
function isFullDatabase(response) {
|
|
282
|
-
return response.object === "database";
|
|
282
|
+
return response.object === "database" && "title" in response;
|
|
283
283
|
}
|
|
284
284
|
/**
|
|
285
285
|
* @returns `true` if `response` is a full `DataSourceObjectResponse` or a full
|
package/build/src/helpers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BlockObjectResponse,\n CommentObjectResponse,\n DatabaseObjectResponse,\n DataSourceObjectResponse,\n DataSourceViewObjectResponse,\n EquationRichTextItemResponse,\n GroupFilterOperatorArray,\n ListDataSourceTemplatesResponse,\n MentionRichTextItemResponse,\n PageObjectResponse,\n PartialBlockObjectResponse,\n PartialCommentObjectResponse,\n PartialDatabaseObjectResponse,\n PartialDataSourceObjectResponse,\n PartialDataSourceViewObjectResponse,\n PartialPageObjectResponse,\n PartialUserObjectResponse,\n PropertyFilter,\n QueryDataSourceParameters,\n QueryDataSourceResponse,\n RichTextItemResponse,\n RichTextItemResponseCommon,\n TextRichTextItemResponse,\n TimestampFilter,\n UserObjectResponse,\n} from \"./api-endpoints\"\nimport type Client from \"./Client\"\n\ntype PaginatedArgs = {\n start_cursor?: string | null\n}\n\ntype PaginatedList<T> = {\n object: \"list\"\n results: T[]\n next_cursor: string | null\n has_more: boolean\n}\n\n/**\n * Returns an async iterator over the results of any paginated Notion API.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * for await (const block of iteratePaginatedAPI(notion.blocks.children.list, {\n * block_id: parentBlockId,\n * })) {\n * // Do something with block.\n * }\n * ```\n *\n * @param listFn A bound function on the Notion client that represents a conforming paginated\n * API. Example: `notion.blocks.children.list`.\n * @param firstPageArgs Arguments that should be passed to the API on the first and subsequent\n * calls to the API. Any necessary `next_cursor` will be automatically populated by\n * this function. Example: `{ block_id: \"<my block id>\" }`\n */\nexport async function* iteratePaginatedAPI<Args extends PaginatedArgs, Item>(\n listFn: (args: Args) => Promise<PaginatedList<Item>>,\n firstPageArgs: Args\n): AsyncIterableIterator<Item> {\n let nextCursor: string | null | undefined = firstPageArgs.start_cursor\n do {\n const response: PaginatedList<Item> = await listFn({\n ...firstPageArgs,\n start_cursor: nextCursor,\n })\n yield* response.results\n nextCursor = response.next_cursor\n } while (nextCursor)\n}\n\n/**\n * Collect all of the results of paginating an API into an in-memory array.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * const blocks = await collectPaginatedAPI(notion.blocks.children.list, {\n * block_id: parentBlockId,\n * })\n * // Do something with blocks.\n * ```\n *\n * @param listFn A bound function on the Notion client that represents a conforming paginated\n * API. Example: `notion.blocks.children.list`.\n * @param firstPageArgs Arguments that should be passed to the API on the first and subsequent\n * calls to the API. Any necessary `next_cursor` will be automatically populated by\n * this function. Example: `{ block_id: \"<my block id>\" }`\n */\nexport async function collectPaginatedAPI<Args extends PaginatedArgs, Item>(\n listFn: (args: Args) => Promise<PaginatedList<Item>>,\n firstPageArgs: Args\n): Promise<Item[]> {\n const results: Item[] = []\n for await (const item of iteratePaginatedAPI(listFn, firstPageArgs)) {\n results.push(item)\n }\n return results\n}\n\ntype DataSourceTemplate = ListDataSourceTemplatesResponse[\"templates\"][number]\n\ntype ListDataSourceTemplatesArgs = PaginatedArgs & {\n data_source_id: string\n name?: string\n page_size?: number\n}\n\n/**\n * Returns an async iterator over data source templates.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * for await (const template of iterateDataSourceTemplates(notion, {\n * data_source_id: dataSourceId,\n * })) {\n * console.log(template.name, template.is_default)\n * }\n * ```\n *\n * @param client A Notion client instance.\n * @param args Arguments including the data_source_id and optional start_cursor.\n */\nexport async function* iterateDataSourceTemplates(\n client: Client,\n args: ListDataSourceTemplatesArgs\n): AsyncIterableIterator<DataSourceTemplate> {\n let nextCursor: string | null | undefined = args.start_cursor\n do {\n const response: ListDataSourceTemplatesResponse =\n await client.dataSources.listTemplates({\n ...args,\n start_cursor: nextCursor,\n })\n yield* response.templates\n nextCursor = response.next_cursor\n } while (nextCursor)\n}\n\n/**\n * Collect all data source templates into an in-memory array.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * const templates = await collectDataSourceTemplates(notion, {\n * data_source_id: dataSourceId,\n * })\n * // Do something with templates.\n * ```\n *\n * @param client A Notion client instance.\n * @param args Arguments including the data_source_id and optional start_cursor.\n */\nexport async function collectDataSourceTemplates(\n client: Client,\n args: ListDataSourceTemplatesArgs\n): Promise<DataSourceTemplate[]> {\n const results: DataSourceTemplate[] = []\n for await (const template of iterateDataSourceTemplates(client, args)) {\n results.push(template)\n }\n return results\n}\n\ntype DataSourceRow = QueryDataSourceResponse[\"results\"][number]\n\n/**\n * A filter the full-query helpers can combine with a created_time window bound.\n *\n * A top-level `or` filter is intentionally excluded: the helpers add a\n * created_time lower bound with `and`, and Notion only supports two levels of\n * filter nesting, so an `or` at the root leaves no room for the bound. Express\n * such queries as an `and` group, or run the helper once per `or` branch and\n * merge the results.\n */\nexport type FullDataSourceQueryFilter =\n | PropertyFilter\n | TimestampFilter\n | { and: GroupFilterOperatorArray }\n\n/**\n * Arguments for the full-query helpers. The same as `dataSources.query`, minus\n * the fields the helper controls: `start_cursor` (pagination is automatic) and\n * `sorts` (the helper sorts by created_time to partition). `filter` is narrowed\n * to {@link FullDataSourceQueryFilter}.\n */\nexport type FullDataSourceQueryArgs = Omit<\n QueryDataSourceParameters,\n \"start_cursor\" | \"sorts\" | \"filter\"\n> & {\n filter?: FullDataSourceQueryFilter\n}\n\n/**\n * Iterate over every row of a data source, including rows past the per-query\n * result limit that `dataSources.query` enforces on large data sources.\n *\n * A single query (one filter and sort) returns at most a fixed number of rows\n * (10,000 by default). Once that limit is reached, `has_more` becomes `false`\n * and the response carries `request_status.type === \"incomplete\"`. Plain\n * pagination such as {@link iteratePaginatedAPI} stops there and silently\n * misses the rest of the data source.\n *\n * This helper works around the limit by partitioning the data source into\n * created_time windows. It sorts by created_time ascending; whenever a window\n * reaches the limit, it starts a fresh query from the last row's created_time.\n * Each fresh query has a different filter, so it gets its own result budget.\n * Rows that share a boundary timestamp are de-duplicated by id, so every row is\n * yielded exactly once.\n *\n * created_time is used because it never changes. last_edited_time would shift\n * rows between windows as they are edited, causing gaps or duplicates.\n *\n * Throws if a single created_time value holds more rows than the limit, since\n * the window cannot be narrowed by time alone. Add a filter in that case so\n * each window stays under the limit.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * for await (const row of iterateAllDataSourceRows(notion, {\n * data_source_id: dataSourceId,\n * })) {\n * // Do something with row.\n * }\n * ```\n *\n * @param client A Notion client instance.\n * @param args Query arguments. `start_cursor` and `sorts` are managed by the\n * helper; `filter` is combined with the created_time window bound.\n */\nexport async function* iterateAllDataSourceRows(\n client: Client,\n args: FullDataSourceQueryArgs\n): AsyncIterableIterator<DataSourceRow> {\n const seenRowIds = new Set<string>()\n let windowStart: string | undefined = undefined\n\n for (;;) {\n let limitReached = false\n let lastCreatedTime: string | undefined = undefined\n let cursor: string | undefined = undefined\n\n do {\n const response = await client.dataSources.query({\n ...args,\n sorts: [{ timestamp: \"created_time\", direction: \"ascending\" }],\n filter: createdTimeLowerBound(args.filter, windowStart),\n start_cursor: cursor,\n })\n for (const row of response.results) {\n // Wiki data sources can return child data-source rows alongside pages.\n // Both carry created_time and either can be the window's boundary row,\n // so advance on either; reading only pages would stall a window made up\n // of data-source rows and throw spuriously.\n if (isFullPageOrDataSource(row)) {\n lastCreatedTime = row.created_time\n }\n if (!seenRowIds.has(row.id)) {\n seenRowIds.add(row.id)\n yield row\n }\n }\n if (response.request_status?.type === \"incomplete\") {\n limitReached = true\n }\n cursor = response.next_cursor ?? undefined\n } while (cursor)\n\n if (!limitReached) {\n return\n }\n if (lastCreatedTime === undefined || lastCreatedTime === windowStart) {\n throw new Error(\n \"iterateAllDataSourceRows cannot make progress: the per-query result \" +\n \"limit was reached but the created_time window could not advance \" +\n `past ${String(lastCreatedTime)}. More rows share this timestamp ` +\n \"than the limit allows. Add a filter to narrow the query.\"\n )\n }\n windowStart = lastCreatedTime\n }\n}\n\n/**\n * Collect every row of a data source into an in-memory array, including rows\n * past the per-query result limit. See {@link iterateAllDataSourceRows} for how\n * the limit is handled.\n *\n * Before using this, check that the full data source fits in memory. For very\n * large data sources, prefer {@link iterateAllDataSourceRows} and process rows\n * as they stream.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * const rows = await collectAllDataSourceRows(notion, {\n * data_source_id: dataSourceId,\n * })\n * // Do something with rows.\n * ```\n *\n * @param client A Notion client instance.\n * @param args Query arguments. See {@link iterateAllDataSourceRows}.\n */\nexport async function collectAllDataSourceRows(\n client: Client,\n args: FullDataSourceQueryArgs\n): Promise<DataSourceRow[]> {\n const rows: DataSourceRow[] = []\n for await (const row of iterateAllDataSourceRows(client, args)) {\n rows.push(row)\n }\n return rows\n}\n\n/**\n * Combine a caller-provided filter with the created_time lower bound used to\n * advance the partition window. Returns the filter unchanged for the first\n * window, which has no bound yet.\n */\nfunction createdTimeLowerBound(\n filter: FullDataSourceQueryFilter | undefined,\n windowStart: string | undefined\n): FullDataSourceQueryFilter | undefined {\n if (windowStart === undefined) {\n return filter\n }\n const bound: TimestampFilter = {\n timestamp: \"created_time\",\n created_time: { on_or_after: windowStart },\n }\n if (filter === undefined) {\n return bound\n }\n if (\"and\" in filter) {\n return { and: [...filter.and, bound] }\n }\n return { and: [filter, bound] }\n}\n\ntype ObjectResponse =\n | PageObjectResponse\n | PartialPageObjectResponse\n | DataSourceObjectResponse\n | PartialDataSourceObjectResponse\n | DatabaseObjectResponse\n | PartialDatabaseObjectResponse\n | BlockObjectResponse\n | PartialBlockObjectResponse\n\n/**\n * @returns `true` if `response` is a full `BlockObjectResponse`.\n */\nexport function isFullBlock(\n response: ObjectResponse\n): response is BlockObjectResponse {\n return response.object === \"block\" && \"type\" in response\n}\n\n/**\n * @returns `true` if `response` is a full `PageObjectResponse`.\n */\nexport function isFullPage(\n response: ObjectResponse\n): response is PageObjectResponse {\n return response.object === \"page\" && \"url\" in response\n}\n\n/**\n * @returns `true` if `response` is a full `DataSourceObjectResponse`.\n */\nexport function isFullDataSource(\n response: ObjectResponse\n): response is DataSourceObjectResponse {\n return response.object === \"data_source\"\n}\n\n/**\n * @returns `true` if `response` is a full `DatabaseObjectResponse`.\n */\nexport function isFullDatabase(\n response: ObjectResponse\n): response is DatabaseObjectResponse {\n return response.object === \"database\"\n}\n\n/**\n * @returns `true` if `response` is a full `DataSourceObjectResponse` or a full\n * `PageObjectResponse`.\n *\n * Can be used on the results of the list response from `queryDataSource` or\n * `search` APIs.\n */\nexport function isFullPageOrDataSource(\n response: ObjectResponse\n): response is DataSourceObjectResponse | PageObjectResponse {\n if (response.object === \"data_source\") {\n return isFullDataSource(response)\n } else {\n return isFullPage(response)\n }\n}\n\n/**\n * @returns `true` if `response` is a full `UserObjectResponse`.\n */\nexport function isFullUser(\n response: UserObjectResponse | PartialUserObjectResponse\n): response is UserObjectResponse {\n return \"type\" in response\n}\n\n/**\n * @returns `true` if `response` is a full `CommentObjectResponse`.\n */\nexport function isFullComment(\n response: CommentObjectResponse | PartialCommentObjectResponse\n): response is CommentObjectResponse {\n return \"created_by\" in response\n}\n\n/**\n * @returns `true` if `response` is a full `DataSourceViewObjectResponse`.\n */\nexport function isFullView(\n response: DataSourceViewObjectResponse | PartialDataSourceViewObjectResponse\n): response is DataSourceViewObjectResponse {\n return \"type\" in response\n}\n\n/**\n * @returns `true` if `richText` is a `TextRichTextItemResponse`.\n */\nexport function isTextRichTextItemResponse(\n richText: RichTextItemResponse\n): richText is RichTextItemResponseCommon & TextRichTextItemResponse {\n return richText.type === \"text\"\n}\n\n/**\n * @returns `true` if `richText` is an `EquationRichTextItemResponse`.\n */\nexport function isEquationRichTextItemResponse(\n richText: RichTextItemResponse\n): richText is RichTextItemResponseCommon & EquationRichTextItemResponse {\n return richText.type === \"equation\"\n}\n\n/**\n * @returns `true` if `richText` is an `MentionRichTextItemResponse`.\n */\nexport function isMentionRichTextItemResponse(\n richText: RichTextItemResponse\n): richText is RichTextItemResponseCommon & MentionRichTextItemResponse {\n return richText.type === \"mention\"\n}\n\n/**\n * Extracts a Notion ID from a Notion URL or returns the input if it's already a valid ID.\n *\n * Prioritizes path IDs over query parameters to avoid extracting view IDs instead of database IDs.\n *\n * @param urlOrId A Notion URL or ID string\n * @returns The extracted UUID in standard format (with hyphens) or null if invalid\n *\n * @example\n * ```typescript\n * // Database URL with view ID - extracts database ID, not view ID\n * extractNotionId('https://notion.so/workspace/DB-abc123def456789012345678901234ab?v=viewid123')\n * // Returns: 'abc123de-f456-7890-1234-5678901234ab' (database ID)\n *\n * // Already formatted UUID\n * extractNotionId('12345678-1234-1234-1234-123456789abc')\n * // Returns: '12345678-1234-1234-1234-123456789abc'\n * ```\n */\nexport function extractNotionId(urlOrId: string): string | null {\n if (!urlOrId || typeof urlOrId !== \"string\") {\n return null\n }\n\n const trimmed = urlOrId.trim()\n\n // Check if it's already a properly formatted UUID\n const uuidRegex =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n if (uuidRegex.test(trimmed)) {\n return trimmed.toLowerCase()\n }\n\n // Check if it's a compact UUID (32 chars, no hyphens)\n const compactUuidRegex = /^[0-9a-f]{32}$/i\n if (compactUuidRegex.test(trimmed)) {\n return formatUuid(trimmed)\n }\n\n // Extract from URL - prioritize path over query parameters\n // This prevents extracting view IDs when database IDs are in the path\n const pathMatch = trimmed.match(/\\/[^/?#]*-([0-9a-f]{32})(?:[/?#]|$)/i)\n if (pathMatch && pathMatch[1]) {\n return formatUuid(pathMatch[1])\n }\n\n // Fallback to query parameters if no path ID found\n const queryMatch = trimmed.match(\n /[?&](?:p|page_id|database_id)=([0-9a-f]{32})/i\n )\n if (queryMatch && queryMatch[1]) {\n return formatUuid(queryMatch[1])\n }\n\n // Last resort: any 32-char hex string in the URL\n const anyMatch = trimmed.match(/([0-9a-f]{32})/i)\n if (anyMatch && anyMatch[1]) {\n return formatUuid(anyMatch[1])\n }\n\n return null\n}\n\n/**\n * Formats a 32-character hex string into a standard UUID format.\n * @param compactId 32-character hex string without hyphens\n * @returns UUID with hyphens in standard format\n */\nfunction formatUuid(compactId: string): string {\n const clean = compactId.toLowerCase()\n return `${clean.slice(0, 8)}-${clean.slice(8, 12)}-${clean.slice(\n 12,\n 16\n )}-${clean.slice(16, 20)}-${clean.slice(20, 32)}`\n}\n\n/**\n * Extracts a database ID from a Notion database URL.\n * Convenience wrapper around `extractNotionId`.\n */\nexport function extractDatabaseId(databaseUrl: string): string | null {\n return extractNotionId(databaseUrl)\n}\n\n/**\n * Extracts a page ID from a Notion page URL.\n * Convenience wrapper around `extractNotionId`.\n */\nexport function extractPageId(pageUrl: string): string | null {\n return extractNotionId(pageUrl)\n}\n\n/**\n * Extracts a block ID from a Notion URL with a block fragment.\n * Looks for #block-<id> or #<id> patterns.\n */\nexport function extractBlockId(urlWithBlock: string): string | null {\n if (!urlWithBlock || typeof urlWithBlock !== \"string\") {\n return null\n }\n\n // Look for block fragment in URL (#block-32chars or just #32chars)\n const blockMatch = urlWithBlock.match(/#(?:block-)?([0-9a-f]{32})/i)\n if (blockMatch && blockMatch[1]) {\n return formatUuid(blockMatch[1])\n }\n\n return null\n}\n"]}
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BlockObjectResponse,\n CommentObjectResponse,\n DatabaseObjectResponse,\n DataSourceObjectResponse,\n DataSourceViewObjectResponse,\n EquationRichTextItemResponse,\n GroupFilterOperatorArray,\n ListDataSourceTemplatesResponse,\n MentionRichTextItemResponse,\n PageObjectResponse,\n PartialBlockObjectResponse,\n PartialCommentObjectResponse,\n PartialDatabaseObjectResponse,\n PartialDataSourceObjectResponse,\n PartialDataSourceViewObjectResponse,\n PartialPageObjectResponse,\n PartialUserObjectResponse,\n PropertyFilter,\n QueryDataSourceParameters,\n QueryDataSourceResponse,\n RichTextItemResponse,\n RichTextItemResponseCommon,\n TextRichTextItemResponse,\n TimestampFilter,\n UserObjectResponse,\n} from \"./api-endpoints\"\nimport type Client from \"./Client\"\n\ntype PaginatedArgs = {\n start_cursor?: string | null\n}\n\ntype PaginatedList<T> = {\n object: \"list\"\n results: T[]\n next_cursor: string | null\n has_more: boolean\n}\n\n/**\n * Returns an async iterator over the results of any paginated Notion API.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * for await (const block of iteratePaginatedAPI(notion.blocks.children.list, {\n * block_id: parentBlockId,\n * })) {\n * // Do something with block.\n * }\n * ```\n *\n * @param listFn A bound function on the Notion client that represents a conforming paginated\n * API. Example: `notion.blocks.children.list`.\n * @param firstPageArgs Arguments that should be passed to the API on the first and subsequent\n * calls to the API. Any necessary `next_cursor` will be automatically populated by\n * this function. Example: `{ block_id: \"<my block id>\" }`\n */\nexport async function* iteratePaginatedAPI<Args extends PaginatedArgs, Item>(\n listFn: (args: Args) => Promise<PaginatedList<Item>>,\n firstPageArgs: Args\n): AsyncIterableIterator<Item> {\n let nextCursor: string | null | undefined = firstPageArgs.start_cursor\n do {\n const response: PaginatedList<Item> = await listFn({\n ...firstPageArgs,\n start_cursor: nextCursor,\n })\n yield* response.results\n nextCursor = response.next_cursor\n } while (nextCursor)\n}\n\n/**\n * Collect all of the results of paginating an API into an in-memory array.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * const blocks = await collectPaginatedAPI(notion.blocks.children.list, {\n * block_id: parentBlockId,\n * })\n * // Do something with blocks.\n * ```\n *\n * @param listFn A bound function on the Notion client that represents a conforming paginated\n * API. Example: `notion.blocks.children.list`.\n * @param firstPageArgs Arguments that should be passed to the API on the first and subsequent\n * calls to the API. Any necessary `next_cursor` will be automatically populated by\n * this function. Example: `{ block_id: \"<my block id>\" }`\n */\nexport async function collectPaginatedAPI<Args extends PaginatedArgs, Item>(\n listFn: (args: Args) => Promise<PaginatedList<Item>>,\n firstPageArgs: Args\n): Promise<Item[]> {\n const results: Item[] = []\n for await (const item of iteratePaginatedAPI(listFn, firstPageArgs)) {\n results.push(item)\n }\n return results\n}\n\ntype DataSourceTemplate = ListDataSourceTemplatesResponse[\"templates\"][number]\n\ntype ListDataSourceTemplatesArgs = PaginatedArgs & {\n data_source_id: string\n name?: string\n page_size?: number\n}\n\n/**\n * Returns an async iterator over data source templates.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * for await (const template of iterateDataSourceTemplates(notion, {\n * data_source_id: dataSourceId,\n * })) {\n * console.log(template.name, template.is_default)\n * }\n * ```\n *\n * @param client A Notion client instance.\n * @param args Arguments including the data_source_id and optional start_cursor.\n */\nexport async function* iterateDataSourceTemplates(\n client: Client,\n args: ListDataSourceTemplatesArgs\n): AsyncIterableIterator<DataSourceTemplate> {\n let nextCursor: string | null | undefined = args.start_cursor\n do {\n const response: ListDataSourceTemplatesResponse =\n await client.dataSources.listTemplates({\n ...args,\n start_cursor: nextCursor,\n })\n yield* response.templates\n nextCursor = response.next_cursor\n } while (nextCursor)\n}\n\n/**\n * Collect all data source templates into an in-memory array.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * const templates = await collectDataSourceTemplates(notion, {\n * data_source_id: dataSourceId,\n * })\n * // Do something with templates.\n * ```\n *\n * @param client A Notion client instance.\n * @param args Arguments including the data_source_id and optional start_cursor.\n */\nexport async function collectDataSourceTemplates(\n client: Client,\n args: ListDataSourceTemplatesArgs\n): Promise<DataSourceTemplate[]> {\n const results: DataSourceTemplate[] = []\n for await (const template of iterateDataSourceTemplates(client, args)) {\n results.push(template)\n }\n return results\n}\n\ntype DataSourceRow = QueryDataSourceResponse[\"results\"][number]\n\n/**\n * A filter the full-query helpers can combine with a created_time window bound.\n *\n * A top-level `or` filter is intentionally excluded: the helpers add a\n * created_time lower bound with `and`, and Notion only supports two levels of\n * filter nesting, so an `or` at the root leaves no room for the bound. Express\n * such queries as an `and` group, or run the helper once per `or` branch and\n * merge the results.\n */\nexport type FullDataSourceQueryFilter =\n | PropertyFilter\n | TimestampFilter\n | { and: GroupFilterOperatorArray }\n\n/**\n * Arguments for the full-query helpers. The same as `dataSources.query`, minus\n * the fields the helper controls: `start_cursor` (pagination is automatic) and\n * `sorts` (the helper sorts by created_time to partition). `filter` is narrowed\n * to {@link FullDataSourceQueryFilter}.\n */\nexport type FullDataSourceQueryArgs = Omit<\n QueryDataSourceParameters,\n \"start_cursor\" | \"sorts\" | \"filter\"\n> & {\n filter?: FullDataSourceQueryFilter\n}\n\n/**\n * Iterate over every row of a data source, including rows past the per-query\n * result limit that `dataSources.query` enforces on large data sources.\n *\n * A single query (one filter and sort) returns at most a fixed number of rows\n * (10,000 by default). Once that limit is reached, `has_more` becomes `false`\n * and the response carries `request_status.type === \"incomplete\"`. Plain\n * pagination such as {@link iteratePaginatedAPI} stops there and silently\n * misses the rest of the data source.\n *\n * This helper works around the limit by partitioning the data source into\n * created_time windows. It sorts by created_time ascending; whenever a window\n * reaches the limit, it starts a fresh query from the last row's created_time.\n * Each fresh query has a different filter, so it gets its own result budget.\n * Rows that share a boundary timestamp are de-duplicated by id, so every row is\n * yielded exactly once.\n *\n * created_time is used because it never changes. last_edited_time would shift\n * rows between windows as they are edited, causing gaps or duplicates.\n *\n * Throws if a single created_time value holds more rows than the limit, since\n * the window cannot be narrowed by time alone. Add a filter in that case so\n * each window stays under the limit.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * for await (const row of iterateAllDataSourceRows(notion, {\n * data_source_id: dataSourceId,\n * })) {\n * // Do something with row.\n * }\n * ```\n *\n * @param client A Notion client instance.\n * @param args Query arguments. `start_cursor` and `sorts` are managed by the\n * helper; `filter` is combined with the created_time window bound.\n */\nexport async function* iterateAllDataSourceRows(\n client: Client,\n args: FullDataSourceQueryArgs\n): AsyncIterableIterator<DataSourceRow> {\n const seenRowIds = new Set<string>()\n let windowStart: string | undefined = undefined\n\n for (;;) {\n let limitReached = false\n let lastCreatedTime: string | undefined = undefined\n let cursor: string | undefined = undefined\n\n do {\n const response = await client.dataSources.query({\n ...args,\n sorts: [{ timestamp: \"created_time\", direction: \"ascending\" }],\n filter: createdTimeLowerBound(args.filter, windowStart),\n start_cursor: cursor,\n })\n for (const row of response.results) {\n // Wiki data sources can return child data-source rows alongside pages.\n // Both carry created_time and either can be the window's boundary row,\n // so advance on either; reading only pages would stall a window made up\n // of data-source rows and throw spuriously.\n if (isFullPageOrDataSource(row)) {\n lastCreatedTime = row.created_time\n }\n if (!seenRowIds.has(row.id)) {\n seenRowIds.add(row.id)\n yield row\n }\n }\n if (response.request_status?.type === \"incomplete\") {\n limitReached = true\n }\n cursor = response.next_cursor ?? undefined\n } while (cursor)\n\n if (!limitReached) {\n return\n }\n if (lastCreatedTime === undefined || lastCreatedTime === windowStart) {\n throw new Error(\n \"iterateAllDataSourceRows cannot make progress: the per-query result \" +\n \"limit was reached but the created_time window could not advance \" +\n `past ${String(lastCreatedTime)}. More rows share this timestamp ` +\n \"than the limit allows. Add a filter to narrow the query.\"\n )\n }\n windowStart = lastCreatedTime\n }\n}\n\n/**\n * Collect every row of a data source into an in-memory array, including rows\n * past the per-query result limit. See {@link iterateAllDataSourceRows} for how\n * the limit is handled.\n *\n * Before using this, check that the full data source fits in memory. For very\n * large data sources, prefer {@link iterateAllDataSourceRows} and process rows\n * as they stream.\n *\n * Example (given a notion Client called `notion`):\n *\n * ```\n * const rows = await collectAllDataSourceRows(notion, {\n * data_source_id: dataSourceId,\n * })\n * // Do something with rows.\n * ```\n *\n * @param client A Notion client instance.\n * @param args Query arguments. See {@link iterateAllDataSourceRows}.\n */\nexport async function collectAllDataSourceRows(\n client: Client,\n args: FullDataSourceQueryArgs\n): Promise<DataSourceRow[]> {\n const rows: DataSourceRow[] = []\n for await (const row of iterateAllDataSourceRows(client, args)) {\n rows.push(row)\n }\n return rows\n}\n\n/**\n * Combine a caller-provided filter with the created_time lower bound used to\n * advance the partition window. Returns the filter unchanged for the first\n * window, which has no bound yet.\n */\nfunction createdTimeLowerBound(\n filter: FullDataSourceQueryFilter | undefined,\n windowStart: string | undefined\n): FullDataSourceQueryFilter | undefined {\n if (windowStart === undefined) {\n return filter\n }\n const bound: TimestampFilter = {\n timestamp: \"created_time\",\n created_time: { on_or_after: windowStart },\n }\n if (filter === undefined) {\n return bound\n }\n if (\"and\" in filter) {\n return { and: [...filter.and, bound] }\n }\n return { and: [filter, bound] }\n}\n\ntype ObjectResponse =\n | PageObjectResponse\n | PartialPageObjectResponse\n | DataSourceObjectResponse\n | PartialDataSourceObjectResponse\n | DatabaseObjectResponse\n | PartialDatabaseObjectResponse\n | BlockObjectResponse\n | PartialBlockObjectResponse\n\n/**\n * @returns `true` if `response` is a full `BlockObjectResponse`.\n */\nexport function isFullBlock(\n response: ObjectResponse\n): response is BlockObjectResponse {\n return response.object === \"block\" && \"type\" in response\n}\n\n/**\n * @returns `true` if `response` is a full `PageObjectResponse`.\n */\nexport function isFullPage(\n response: ObjectResponse\n): response is PageObjectResponse {\n return response.object === \"page\" && \"url\" in response\n}\n\n/**\n * @returns `true` if `response` is a full `DataSourceObjectResponse`.\n */\nexport function isFullDataSource(\n response: ObjectResponse\n): response is DataSourceObjectResponse {\n return response.object === \"data_source\" && \"title\" in response\n}\n\n/**\n * @returns `true` if `response` is a full `DatabaseObjectResponse`.\n */\nexport function isFullDatabase(\n response: ObjectResponse\n): response is DatabaseObjectResponse {\n return response.object === \"database\" && \"title\" in response\n}\n\n/**\n * @returns `true` if `response` is a full `DataSourceObjectResponse` or a full\n * `PageObjectResponse`.\n *\n * Can be used on the results of the list response from `queryDataSource` or\n * `search` APIs.\n */\nexport function isFullPageOrDataSource(\n response: ObjectResponse\n): response is DataSourceObjectResponse | PageObjectResponse {\n if (response.object === \"data_source\") {\n return isFullDataSource(response)\n } else {\n return isFullPage(response)\n }\n}\n\n/**\n * @returns `true` if `response` is a full `UserObjectResponse`.\n */\nexport function isFullUser(\n response: UserObjectResponse | PartialUserObjectResponse\n): response is UserObjectResponse {\n return \"type\" in response\n}\n\n/**\n * @returns `true` if `response` is a full `CommentObjectResponse`.\n */\nexport function isFullComment(\n response: CommentObjectResponse | PartialCommentObjectResponse\n): response is CommentObjectResponse {\n return \"created_by\" in response\n}\n\n/**\n * @returns `true` if `response` is a full `DataSourceViewObjectResponse`.\n */\nexport function isFullView(\n response: DataSourceViewObjectResponse | PartialDataSourceViewObjectResponse\n): response is DataSourceViewObjectResponse {\n return \"type\" in response\n}\n\n/**\n * @returns `true` if `richText` is a `TextRichTextItemResponse`.\n */\nexport function isTextRichTextItemResponse(\n richText: RichTextItemResponse\n): richText is RichTextItemResponseCommon & TextRichTextItemResponse {\n return richText.type === \"text\"\n}\n\n/**\n * @returns `true` if `richText` is an `EquationRichTextItemResponse`.\n */\nexport function isEquationRichTextItemResponse(\n richText: RichTextItemResponse\n): richText is RichTextItemResponseCommon & EquationRichTextItemResponse {\n return richText.type === \"equation\"\n}\n\n/**\n * @returns `true` if `richText` is an `MentionRichTextItemResponse`.\n */\nexport function isMentionRichTextItemResponse(\n richText: RichTextItemResponse\n): richText is RichTextItemResponseCommon & MentionRichTextItemResponse {\n return richText.type === \"mention\"\n}\n\n/**\n * Extracts a Notion ID from a Notion URL or returns the input if it's already a valid ID.\n *\n * Prioritizes path IDs over query parameters to avoid extracting view IDs instead of database IDs.\n *\n * @param urlOrId A Notion URL or ID string\n * @returns The extracted UUID in standard format (with hyphens) or null if invalid\n *\n * @example\n * ```typescript\n * // Database URL with view ID - extracts database ID, not view ID\n * extractNotionId('https://notion.so/workspace/DB-abc123def456789012345678901234ab?v=viewid123')\n * // Returns: 'abc123de-f456-7890-1234-5678901234ab' (database ID)\n *\n * // Already formatted UUID\n * extractNotionId('12345678-1234-1234-1234-123456789abc')\n * // Returns: '12345678-1234-1234-1234-123456789abc'\n * ```\n */\nexport function extractNotionId(urlOrId: string): string | null {\n if (!urlOrId || typeof urlOrId !== \"string\") {\n return null\n }\n\n const trimmed = urlOrId.trim()\n\n // Check if it's already a properly formatted UUID\n const uuidRegex =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n if (uuidRegex.test(trimmed)) {\n return trimmed.toLowerCase()\n }\n\n // Check if it's a compact UUID (32 chars, no hyphens)\n const compactUuidRegex = /^[0-9a-f]{32}$/i\n if (compactUuidRegex.test(trimmed)) {\n return formatUuid(trimmed)\n }\n\n // Extract from URL - prioritize path over query parameters\n // This prevents extracting view IDs when database IDs are in the path\n const pathMatch = trimmed.match(/\\/[^/?#]*-([0-9a-f]{32})(?:[/?#]|$)/i)\n if (pathMatch && pathMatch[1]) {\n return formatUuid(pathMatch[1])\n }\n\n // Fallback to query parameters if no path ID found\n const queryMatch = trimmed.match(\n /[?&](?:p|page_id|database_id)=([0-9a-f]{32})/i\n )\n if (queryMatch && queryMatch[1]) {\n return formatUuid(queryMatch[1])\n }\n\n // Last resort: any 32-char hex string in the URL\n const anyMatch = trimmed.match(/([0-9a-f]{32})/i)\n if (anyMatch && anyMatch[1]) {\n return formatUuid(anyMatch[1])\n }\n\n return null\n}\n\n/**\n * Formats a 32-character hex string into a standard UUID format.\n * @param compactId 32-character hex string without hyphens\n * @returns UUID with hyphens in standard format\n */\nfunction formatUuid(compactId: string): string {\n const clean = compactId.toLowerCase()\n return `${clean.slice(0, 8)}-${clean.slice(8, 12)}-${clean.slice(\n 12,\n 16\n )}-${clean.slice(16, 20)}-${clean.slice(20, 32)}`\n}\n\n/**\n * Extracts a database ID from a Notion database URL.\n * Convenience wrapper around `extractNotionId`.\n */\nexport function extractDatabaseId(databaseUrl: string): string | null {\n return extractNotionId(databaseUrl)\n}\n\n/**\n * Extracts a page ID from a Notion page URL.\n * Convenience wrapper around `extractNotionId`.\n */\nexport function extractPageId(pageUrl: string): string | null {\n return extractNotionId(pageUrl)\n}\n\n/**\n * Extracts a block ID from a Notion URL with a block fragment.\n * Looks for #block-<id> or #<id> patterns.\n */\nexport function extractBlockId(urlWithBlock: string): string | null {\n if (!urlWithBlock || typeof urlWithBlock !== \"string\") {\n return null\n }\n\n // Look for block fragment in URL (#block-32chars or just #32chars)\n const blockMatch = urlWithBlock.match(/#(?:block-)?([0-9a-f]{32})/i)\n if (blockMatch && blockMatch[1]) {\n return formatUuid(blockMatch[1])\n }\n\n return null\n}\n"]}
|