@notionx/core 0.1.2 → 1.0.0
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/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/rate-limit.js.map +1 -1
- package/dist/auth/routes/google-callback.js.map +1 -1
- package/dist/auth/routes/google.js.map +1 -1
- package/dist/auth/routes/index.js.map +1 -1
- package/dist/auth/routes/verify-email.js.map +1 -1
- package/dist/auth/routes/viewer.js.map +1 -1
- package/dist/auth/turnstile.js.map +1 -1
- package/dist/auth/user-session.d.ts +1 -1
- package/dist/auth/user-session.js.map +1 -1
- package/dist/auth/users.js.map +1 -1
- package/dist/content/index.d.ts +2 -2
- package/dist/content/index.js +8 -60
- package/dist/content/index.js.map +1 -1
- package/dist/content/revalidate.d.ts +2 -1
- package/dist/content/revalidate.js +5 -28
- package/dist/content/revalidate.js.map +1 -1
- package/dist/content/search-index.d.ts +1 -1
- package/dist/content/search-index.js.map +1 -1
- package/dist/content/search.d.ts +2 -5
- package/dist/content/search.js +3 -32
- package/dist/content/search.js.map +1 -1
- package/dist/doctor/cli.js +0 -0
- package/dist/email/index.js.map +1 -1
- package/dist/{env-C5qu-0R-.d.ts → env-hoez1e-n.d.ts} +0 -4
- package/dist/i18n/index.d.ts +18 -24
- package/dist/i18n/index.js +29 -54
- package/dist/i18n/index.js.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/admin/index.js.map +1 -1
- package/dist/media/index.js +3 -2
- package/dist/media/index.js.map +1 -1
- package/dist/media/routes/index.js +0 -1
- package/dist/media/routes/index.js.map +1 -1
- package/dist/media/routes/notion-media.js +0 -1
- package/dist/media/routes/notion-media.js.map +1 -1
- package/dist/notion/config.d.ts +1 -4
- package/dist/notion/config.js +1 -23
- package/dist/notion/config.js.map +1 -1
- package/dist/notion/content-cache.d.ts +1 -1
- package/dist/notion/generic-source.js +0 -1
- package/dist/notion/generic-source.js.map +1 -1
- package/dist/notion/index.d.ts +3 -3
- package/dist/notion/index.js +1 -23
- package/dist/notion/index.js.map +1 -1
- package/dist/notion/media.d.ts +1 -1
- package/dist/notion/media.js +1 -1
- package/dist/notion/media.js.map +1 -1
- package/dist/notion/routes/index.d.ts +1 -1
- package/dist/notion/routes/index.js +0 -1
- package/dist/notion/routes/index.js.map +1 -1
- package/dist/notion/routes/webhook.d.ts +1 -1
- package/dist/notion/routes/webhook.js +0 -1
- package/dist/notion/routes/webhook.js.map +1 -1
- package/dist/notion/types.d.ts +1 -73
- package/dist/notion/webhook.d.ts +1 -1
- package/dist/notion/webhook.js +0 -1
- package/dist/notion/webhook.js.map +1 -1
- package/dist/pages/index.js +0 -1
- package/dist/pages/index.js.map +1 -1
- package/dist/platform/current.d.ts +1 -1
- package/dist/platform/current.js.map +1 -1
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js.map +1 -1
- package/dist/platform/runtime.d.ts +1 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/routes/cdn.js.map +1 -1
- package/dist/storage/routes/files.js.map +1 -1
- package/dist/storage/routes/index.js.map +1 -1
- package/dist/util/index.d.ts +1 -1
- package/dist/util/index.js +1 -2
- package/dist/util/index.js.map +1 -1
- package/dist/worker/index.js +0 -1
- package/dist/worker/index.js.map +1 -1
- package/dist/worker/routes/content-revalidate.d.ts +1 -1
- package/dist/worker/routes/health.js.map +1 -1
- package/dist/worker/routes/index.d.ts +1 -1
- package/dist/worker/routes/index.js.map +1 -1
- package/package.json +14 -12
package/dist/notion/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/notion/client.ts","../../src/notion/config.ts","../../src/notion/blocks.ts","../../src/notion/block-text.ts","../../src/notion/content-cache.ts","../../src/notion/media.ts","../../src/notion/generic-source.ts","../../src/notion/property-mappers.ts","../../src/notion/webhook.ts"],"sourcesContent":["import { Client } from \"@notionhq/client\";\nimport type { NotionClientConfig } from \"./config\";\n\nexport function createNotionClient(config: NotionClientConfig) {\n return new Client({\n auth: config.token,\n baseUrl: config.apiBaseUrl,\n notionVersion: \"2026-03-11\",\n });\n}\n","import type { NotionContentModelLike } from \"./types\";\n\ntype NotionEnv = {\n NOTION_TOKEN?: string;\n NOTION_DATA_SOURCE_ID?: string;\n NOTION_MOVIES_DATA_SOURCE_ID?: string;\n NOTION_API_BASE_URL?: string;\n NOTION_EDIT_BASE_URL?: string;\n NOTION_WEBHOOK_VERIFICATION_TOKEN?: string;\n [key: string]: string | undefined;\n};\n\nexport const DEFAULT_NOTION_MOVIES_DATA_SOURCE_ID =\n \"371dc62d-0738-8015-a601-000bc3944fcb\";\n\nexport type NotionClientConfig = {\n token: string;\n apiBaseUrl?: string;\n};\n\nexport type NotionConfig = {\n token: string;\n dataSourceId: string;\n apiBaseUrl?: string;\n editBaseUrl?: string;\n webhookVerificationToken?: string;\n};\n\nfunction readProcessEnv(): NotionEnv {\n const env: NotionEnv = {\n NOTION_TOKEN: process.env.NOTION_TOKEN,\n NOTION_DATA_SOURCE_ID: process.env.NOTION_DATA_SOURCE_ID,\n NOTION_MOVIES_DATA_SOURCE_ID: process.env.NOTION_MOVIES_DATA_SOURCE_ID,\n NOTION_API_BASE_URL: process.env.NOTION_API_BASE_URL,\n NOTION_EDIT_BASE_URL: process.env.NOTION_EDIT_BASE_URL,\n NOTION_WEBHOOK_VERIFICATION_TOKEN:\n process.env.NOTION_WEBHOOK_VERIFICATION_TOKEN,\n };\n\n for (const [key, value] of Object.entries(process.env)) {\n if (key.startsWith(\"NOTION_\") && typeof value === \"string\") {\n env[key] = value;\n }\n }\n\n return env;\n}\n\nasync function readWorkerEnv(): Promise<NotionEnv> {\n try {\n const mod = (await import(\n /* webpackIgnore: true */ \"cloudflare:workers\"\n )) as unknown as { env?: Record<string, unknown> };\n const env: NotionEnv = {};\n for (const [key, value] of Object.entries(mod.env ?? {})) {\n if (key.startsWith(\"NOTION_\") && typeof value === \"string\") {\n env[key] = value;\n }\n }\n return env;\n } catch {\n return {};\n }\n}\n\nfunction readString(source: NotionEnv, name: string): string | undefined {\n const value = String(source[name] ?? \"\").trim();\n return value || undefined;\n}\n\nfunction mergeEnv(...sources: NotionEnv[]): NotionEnv {\n const merged: NotionEnv = {};\n\n for (const source of sources) {\n for (const name of Object.keys(source)) {\n if (!name.startsWith(\"NOTION_\")) continue;\n const value = readString(source, name);\n if (value) merged[name] = value;\n }\n }\n\n return merged;\n}\n\nasync function readEnv(): Promise<NotionEnv> {\n const processEnv = readProcessEnv();\n return mergeEnv(await readWorkerEnv(), processEnv);\n}\n\nfunction readRequired(\n source: NotionEnv,\n name: string\n): string {\n const value = readString(source, name);\n if (!value) {\n throw new Error(`Missing required Notion env: ${name}`);\n }\n return value;\n}\n\nexport function getNotionEditBaseUrl(): string {\n return readString(readProcessEnv(), \"NOTION_EDIT_BASE_URL\") ?? \"https://www.notion.so\";\n}\n\nexport async function hasNotionConfig(): Promise<boolean> {\n const env = await readEnv();\n return Boolean(\n readString(env, \"NOTION_TOKEN\") && readString(env, \"NOTION_DATA_SOURCE_ID\")\n );\n}\n\nexport async function hasNotionMovieConfig(): Promise<boolean> {\n const env = await readEnv();\n return Boolean(readString(env, \"NOTION_TOKEN\"));\n}\n\nexport async function hasNotionModelConfig(\n model: NotionContentModelLike\n): Promise<boolean> {\n const env = await readEnv();\n return Boolean(\n readString(env, \"NOTION_TOKEN\") &&\n (readString(env, model.source.dataSourceEnv) ||\n model.source.defaultDataSourceId)\n );\n}\n\nexport async function getNotionClientConfig(): Promise<NotionClientConfig> {\n const env = await readEnv();\n return {\n token: readRequired(env, \"NOTION_TOKEN\"),\n apiBaseUrl: readString(env, \"NOTION_API_BASE_URL\"),\n };\n}\n\nexport async function getNotionConfig(): Promise<NotionConfig> {\n const env = await readEnv();\n return {\n token: readRequired(env, \"NOTION_TOKEN\"),\n dataSourceId: readRequired(env, \"NOTION_DATA_SOURCE_ID\"),\n apiBaseUrl: readString(env, \"NOTION_API_BASE_URL\"),\n editBaseUrl: readString(env, \"NOTION_EDIT_BASE_URL\"),\n webhookVerificationToken: readString(\n env,\n \"NOTION_WEBHOOK_VERIFICATION_TOKEN\"\n ),\n };\n}\n\nexport async function getNotionWebhookVerificationToken(): Promise<\n string | undefined\n> {\n const env = await readEnv();\n return readString(env, \"NOTION_WEBHOOK_VERIFICATION_TOKEN\");\n}\n\nexport async function getNotionMovieConfig(): Promise<NotionConfig> {\n const env = await readEnv();\n return {\n token: readRequired(env, \"NOTION_TOKEN\"),\n dataSourceId:\n readString(env, \"NOTION_MOVIES_DATA_SOURCE_ID\") ??\n DEFAULT_NOTION_MOVIES_DATA_SOURCE_ID,\n apiBaseUrl: readString(env, \"NOTION_API_BASE_URL\"),\n editBaseUrl: readString(env, \"NOTION_EDIT_BASE_URL\"),\n webhookVerificationToken: readString(\n env,\n \"NOTION_WEBHOOK_VERIFICATION_TOKEN\"\n ),\n };\n}\n\nexport async function getNotionConfigForModel(\n model: NotionContentModelLike\n): Promise<NotionConfig> {\n const env = await readEnv();\n const dataSourceId =\n readString(env, model.source.dataSourceEnv) ??\n model.source.defaultDataSourceId;\n if (!dataSourceId) {\n throw new Error(`Missing required Notion env: ${model.source.dataSourceEnv}`);\n }\n\n return {\n token: readRequired(env, model.source.tokenEnv),\n dataSourceId,\n apiBaseUrl: readString(env, \"NOTION_API_BASE_URL\"),\n editBaseUrl: readString(env, \"NOTION_EDIT_BASE_URL\"),\n webhookVerificationToken: readString(\n env,\n \"NOTION_WEBHOOK_VERIFICATION_TOKEN\"\n ),\n };\n}\n","import type { NotionBlock } from \"./types\";\n\ntype BlockChildrenListResponse = {\n results?: unknown[];\n has_more?: boolean;\n next_cursor?: string | null;\n};\n\nexport type NotionBlockClient = {\n blocks: {\n children: {\n list: (args: {\n block_id: string;\n page_size?: number;\n start_cursor?: string;\n }) => Promise<BlockChildrenListResponse>;\n };\n };\n};\n\nfunction normalizeBlock(input: unknown): NotionBlock | null {\n if (!input || typeof input !== \"object\") return null;\n const block = input as NotionBlock;\n return block.id && block.type ? block : null;\n}\n\nexport async function listBlockChildren(\n client: NotionBlockClient,\n blockId: string\n): Promise<NotionBlock[]> {\n const results: NotionBlock[] = [];\n let cursor: string | undefined;\n\n do {\n const response = await client.blocks.children.list({\n block_id: blockId,\n page_size: 100,\n ...(cursor ? { start_cursor: cursor } : {}),\n });\n\n for (const item of response.results ?? []) {\n const block = normalizeBlock(item);\n if (block) results.push(block);\n }\n\n cursor = response.next_cursor ?? undefined;\n if (!response.has_more) break;\n } while (cursor);\n\n return results;\n}\n\nexport async function listBlockChildrenDeep(\n client: NotionBlockClient,\n blockId: string,\n options?: { maxDepth?: number }\n): Promise<NotionBlock[]> {\n const maxDepth = options?.maxDepth ?? 6;\n\n async function visit(id: string, depth: number): Promise<NotionBlock[]> {\n const children = await listBlockChildren(client, id);\n if (depth >= maxDepth) return children;\n\n return Promise.all(\n children.map(async (block) => {\n if (!block.has_children) return block;\n return {\n ...block,\n children: await visit(block.id, depth + 1),\n };\n })\n );\n }\n\n return visit(blockId, 0);\n}\n","import type { NotionBlock, NotionRichTextPart } from \"./types\";\n\ntype RichTextContainer = {\n rich_text?: NotionRichTextPart[];\n caption?: NotionRichTextPart[];\n title?: NotionRichTextPart[];\n cells?: NotionRichTextPart[][];\n expression?: string;\n};\n\nfunction typedValue(block: NotionBlock): RichTextContainer {\n return (block[block.type] ?? {}) as RichTextContainer;\n}\n\nfunction richTextPlainText(parts: unknown) {\n if (!Array.isArray(parts)) return \"\";\n return parts\n .map((part: NotionRichTextPart) =>\n part.type === \"equation\"\n ? part.equation?.expression ?? \"\"\n : part.plain_text ?? part.text?.content ?? \"\"\n )\n .join(\"\");\n}\n\nfunction blockPlainText(block: NotionBlock) {\n const value = typedValue(block);\n const text = [\n richTextPlainText(value.rich_text),\n richTextPlainText(value.caption),\n richTextPlainText(value.title),\n value.expression ?? \"\",\n ...(value.cells ?? []).map(richTextPlainText),\n ];\n\n return text.filter(Boolean).join(\" \");\n}\n\nexport function flattenNotionBlockText(blocks: readonly NotionBlock[]): string {\n const parts: string[] = [];\n\n function visit(block: NotionBlock) {\n const text = blockPlainText(block).trim();\n if (text) parts.push(text);\n for (const child of block.children ?? []) {\n visit(child);\n }\n }\n\n for (const block of blocks) visit(block);\n\n return parts\n .join(\" \")\n .normalize(\"NFKC\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n","import type { KeyValueCacheAdapter } from \"../platform/runtime\";\nimport type { NotionBlock } from \"./types\";\n\nconst CACHE_VERSION = \"v2\";\nexport const NOTION_LIST_CACHE_TTL_SECONDS = 300;\nexport const NOTION_BLOCKS_CACHE_TTL_SECONDS = 60 * 60 * 24;\nconst CONTENT_CACHE_READ_TTL_SECONDS = 60;\n\nexport type NotionContentCacheDeleteResult = {\n ok: boolean;\n skipped: boolean;\n deleted: string[];\n failed: Array<{ key?: string; error: string }>;\n};\n\ntype CacheableValue = Record<string, unknown> | unknown[] | null;\n\nfunction modelPrefix(modelId: string) {\n return `notion:${CACHE_VERSION}:${modelId}`;\n}\n\nexport function notionModelListCacheKey(modelId: string) {\n return `${modelPrefix(modelId)}:list`;\n}\n\nfunction versionSegment(value?: string) {\n const version = String(value ?? \"\").trim();\n return version ? `:v:${encodeURIComponent(version)}` : \"\";\n}\n\nexport function notionPageBlocksCacheKey(\n modelId: string,\n pageId: string,\n cacheVersion?: string\n) {\n return `${modelPrefix(modelId)}:page:${pageId}:blocks${versionSegment(cacheVersion)}`;\n}\n\nexport function notionModelCachePrefix(modelId: string) {\n return `${modelPrefix(modelId)}:`;\n}\n\nexport function notionPageCachePrefix(modelId: string, pageId: string) {\n return `${modelPrefix(modelId)}:page:${pageId}:`;\n}\n\nfunction logNotionContentCache(fields: Record<string, unknown>) {\n try {\n console.log(JSON.stringify({ tag: \"notion_content_cache\", ...fields }));\n } catch {\n // Ignore logging serialization errors.\n }\n}\n\nexport async function getCachedNotionValue<T extends CacheableValue>(\n cache: KeyValueCacheAdapter | null | undefined,\n key: string\n): Promise<T | null> {\n if (!cache) return null;\n try {\n const value = await cache.get<T>(key, {\n cacheTtl: CONTENT_CACHE_READ_TTL_SECONDS,\n });\n logNotionContentCache({\n op: \"get\",\n key,\n hit: value !== null,\n cache: cache.kind,\n });\n return value;\n } catch (error) {\n logNotionContentCache({\n op: \"get_error\",\n key,\n cache: cache.kind,\n message: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n}\n\nexport async function putCachedNotionValue<T extends CacheableValue>(\n cache: KeyValueCacheAdapter | null | undefined,\n key: string,\n value: T,\n options?: { expirationTtl?: number }\n) {\n if (!cache) return;\n try {\n await cache.put(key, value, {\n expirationTtl: options?.expirationTtl ?? NOTION_BLOCKS_CACHE_TTL_SECONDS,\n metadata: {\n source: \"notion\",\n cachedAt: new Date().toISOString(),\n },\n });\n logNotionContentCache({\n op: \"put\",\n key,\n cache: cache.kind,\n });\n } catch (error) {\n logNotionContentCache({\n op: \"put_error\",\n key,\n cache: cache.kind,\n message: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\nexport async function getCachedNotionBlocks(\n cache: KeyValueCacheAdapter | null | undefined,\n input: { modelId: string; pageId: string; cacheVersion?: string }\n) {\n return getCachedNotionValue<NotionBlock[]>(\n cache,\n notionPageBlocksCacheKey(input.modelId, input.pageId, input.cacheVersion)\n );\n}\n\nexport async function putCachedNotionBlocks(\n cache: KeyValueCacheAdapter | null | undefined,\n input: {\n modelId: string;\n pageId: string;\n cacheVersion?: string;\n blocks: NotionBlock[];\n }\n) {\n await putCachedNotionValue(\n cache,\n notionPageBlocksCacheKey(input.modelId, input.pageId, input.cacheVersion),\n input.blocks,\n { expirationTtl: NOTION_BLOCKS_CACHE_TTL_SECONDS }\n );\n}\n\nexport async function deleteNotionContentCache(input: {\n modelId: string;\n pageId?: string;\n routeId?: string;\n previousRouteId?: string;\n cache?: KeyValueCacheAdapter | null;\n getCache?: () => KeyValueCacheAdapter | null;\n}): Promise<NotionContentCacheDeleteResult> {\n let cache: KeyValueCacheAdapter | null;\n try {\n cache = input.cache ?? input.getCache?.() ?? null;\n } catch (error) {\n return {\n ok: false,\n skipped: true,\n deleted: [],\n failed: [\n {\n error: error instanceof Error ? error.message : String(error),\n },\n ],\n };\n }\n\n if (!cache) {\n return { ok: true, skipped: true, deleted: [], failed: [] };\n }\n\n const prefixes = new Set<string>();\n if (input.pageId) {\n prefixes.add(notionPageCachePrefix(input.modelId, input.pageId));\n } else {\n prefixes.add(notionModelCachePrefix(input.modelId));\n }\n\n prefixes.add(notionModelListCacheKey(input.modelId));\n\n const deleted: string[] = [];\n const failed: Array<{ key?: string; error: string }> = [];\n\n for (const prefix of prefixes) {\n let cursor: string | undefined;\n do {\n try {\n const result = await cache.list({ prefix, cursor, limit: 100 });\n for (const { name } of result.keys) {\n try {\n await cache.delete(name);\n deleted.push(name);\n } catch (error) {\n failed.push({\n key: name,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n cursor = result.listComplete ? undefined : result.cursor;\n } catch (error) {\n failed.push({\n key: prefix,\n error: error instanceof Error ? error.message : String(error),\n });\n cursor = undefined;\n }\n } while (cursor);\n }\n\n return {\n ok: failed.length === 0,\n skipped: false,\n deleted,\n failed,\n };\n}\n","import type { NotionBlock, NotionFileSource, NotionPageLike } from \"./types\";\n\ntype FileLike = {\n type?: string;\n external?: { url?: string };\n file?: { url?: string; expiry_time?: string };\n name?: string;\n};\n\nfunction stripLeadingSlash(value: string) {\n return value.startsWith(\"/\") ? value.slice(1) : value;\n}\n\nfunction encodePathPart(value: string) {\n return encodeURIComponent(stripLeadingSlash(value));\n}\n\nfunction appendVersion(path: string, version?: string) {\n const value = String(version ?? \"\").trim();\n if (!value) return path;\n return `${path}?${new URLSearchParams({ v: value })}`;\n}\n\nfunction blockVersion(block: NotionBlock): string | undefined {\n return typeof block.last_edited_time === \"string\"\n ? block.last_edited_time\n : undefined;\n}\n\nexport function notionPageCoverMediaPath(pageId: string): string {\n return `/api/notion/media/page/${encodePathPart(pageId)}/cover`;\n}\n\nexport function notionPagePropertyMediaPath(\n pageId: string,\n propertyName: string\n): string {\n return `/api/notion/media/page/${encodePathPart(pageId)}/property/${encodePathPart(propertyName)}`;\n}\n\nexport function notionBlockMediaPath(blockId: string): string {\n return `/api/notion/media/block/${encodePathPart(blockId)}`;\n}\n\nexport function normalizeNotionFileSource(input: unknown): NotionFileSource | null {\n const file = input as FileLike | null | undefined;\n if (!file || typeof file !== \"object\") return null;\n\n if (file.type === \"external\") {\n const url = String(file.external?.url ?? \"\").trim();\n return url ? { type: \"external\", url } : null;\n }\n\n if (file.type === \"file\") {\n const url = String(file.file?.url ?? \"\").trim();\n if (!url) return null;\n return {\n type: \"file\",\n url,\n expiryTime: String(file.file?.expiry_time ?? \"\").trim() || null,\n };\n }\n\n return null;\n}\n\nexport function resolveNotionFileUrl(input: unknown): string | null {\n return normalizeNotionFileSource(input)?.url ?? null;\n}\n\nexport function isNotionHostedFile(input: unknown): boolean {\n return normalizeNotionFileSource(input)?.type === \"file\";\n}\n\nexport function pickFirstFilesPropertyValue(property: unknown): unknown | null {\n const value = property as { type?: string; files?: unknown[] } | null | undefined;\n if (!value || value.type !== \"files\" || !Array.isArray(value.files)) {\n return null;\n }\n return value.files[0] ?? null;\n}\n\nexport function pickPageCoverFile(page: NotionPageLike): unknown | null {\n return page.cover ?? null;\n}\n\nexport function coverImageUrlForPage(\n page: NotionPageLike,\n coverPropertyName = \"Cover\"\n): string | null {\n const propertyFile = pickFirstFilesPropertyValue(\n page.properties?.[coverPropertyName]\n );\n const propertySource = normalizeNotionFileSource(propertyFile);\n if (propertySource) {\n return appendVersion(\n notionPagePropertyMediaPath(page.id, coverPropertyName),\n page.last_edited_time\n );\n }\n\n const coverSource = normalizeNotionFileSource(pickPageCoverFile(page));\n if (coverSource) {\n return appendVersion(notionPageCoverMediaPath(page.id), page.last_edited_time);\n }\n\n return null;\n}\n\nexport function fileObjectForMediaBlock(block: NotionBlock): unknown | null {\n const typed = block[block.type] as Record<string, unknown> | undefined;\n if (!typed || typeof typed !== \"object\") return null;\n\n if (\n block.type === \"image\" ||\n block.type === \"video\" ||\n block.type === \"file\" ||\n block.type === \"pdf\" ||\n block.type === \"audio\"\n ) {\n return typed;\n }\n\n return null;\n}\n\nexport function mediaUrlForBlock(block: NotionBlock): string | null {\n const source = normalizeNotionFileSource(fileObjectForMediaBlock(block));\n if (!source) return null;\n if (source.type === \"external\" && block.type !== \"image\") {\n return source.url;\n }\n return appendVersion(notionBlockMediaPath(block.id), blockVersion(block));\n}\n\nexport function firstImageUrlFromBlocks(blocks: NotionBlock[]): string | null {\n for (const block of blocks) {\n if (block.type === \"image\") {\n const imageUrl = mediaUrlForBlock(block);\n if (imageUrl) return imageUrl;\n }\n\n const nested = block.children?.length\n ? firstImageUrlFromBlocks(block.children)\n : null;\n if (nested) return nested;\n }\n\n return null;\n}\n\nexport function publicMediaBlockForApi(block: NotionBlock): NotionBlock {\n const value = block[block.type];\n const source = normalizeNotionFileSource(value);\n const children = block.children?.map(publicMediaBlockForApi);\n\n if (!source) {\n return children ? { ...block, children } : { ...block };\n }\n\n const path = appendVersion(notionBlockMediaPath(block.id), blockVersion(block));\n const publicValue =\n source.type === \"external\"\n ? block.type === \"image\"\n ? {\n ...(value as Record<string, unknown>),\n external: { url: path },\n }\n : value\n : {\n ...(value as Record<string, unknown>),\n file: {\n url: path,\n expiry_time: null,\n },\n };\n\n return {\n ...block,\n [block.type]: publicValue,\n ...(children ? { children } : {}),\n };\n}\n\nexport function gatedMediaBlockForApi(\n block: NotionBlock,\n options?: { movieId?: string }\n): NotionBlock {\n const value = block[block.type];\n const source = normalizeNotionFileSource(value);\n const children = block.children?.map((child) =>\n gatedMediaBlockForApi(child, options)\n );\n\n if (block.type !== \"video\" || !source) {\n const publicBlock = publicMediaBlockForApi(block);\n return children ? { ...publicBlock, children } : publicBlock;\n }\n\n const gatedValue: Record<string, unknown> = {\n ...(value as Record<string, unknown>),\n gated: true,\n access_url: options?.movieId\n ? `/api/movies/${encodePathPart(options.movieId)}/video/${encodePathPart(block.id)}`\n : null,\n };\n\n if (source.type === \"external\") {\n gatedValue.external = { url: null };\n } else {\n gatedValue.file = {\n url: null,\n expiry_time: null,\n };\n }\n\n return {\n ...block,\n video: gatedValue,\n ...(children ? { children } : {}),\n };\n}\n\nexport function isDirectVideoUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return /\\.(mp4|webm|mov|m4v)(?:$|\\?)/i.test(parsed.pathname);\n } catch {\n return false;\n }\n}\n\nexport function videoEmbedUrl(url: string): string | null {\n try {\n const parsed = new URL(url);\n const host = parsed.hostname.replace(/^www\\./, \"\");\n\n if (host === \"youtube.com\" || host === \"m.youtube.com\") {\n const id = parsed.searchParams.get(\"v\");\n return id ? `https://www.youtube.com/embed/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"youtu.be\") {\n const id = parsed.pathname.split(\"/\").filter(Boolean)[0];\n return id ? `https://www.youtube.com/embed/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"youtube-nocookie.com\") {\n return parsed.toString();\n }\n\n if (host === \"vimeo.com\") {\n const id = parsed.pathname.split(\"/\").filter(Boolean)[0];\n return id ? `https://player.vimeo.com/video/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"player.vimeo.com\") {\n return parsed.toString();\n }\n } catch {\n return null;\n }\n\n return null;\n}\n","import { cache } from \"react\";\nimport { listBlockChildrenDeep, type NotionBlockClient } from \"./blocks\";\nimport { createNotionClient } from \"./client\";\nimport { getNotionConfigForModel, hasNotionModelConfig } from \"./config\";\nimport { coverImageUrlForPage } from \"./media\";\nimport {\n getDateProperty,\n getRichTextProperty,\n getTagsProperty,\n isValidPublicSlug,\n notionPageEditUrl,\n pickDescriptionFallback,\n} from \"./property-mappers\";\nimport type {\n NotionBlock,\n NotionFieldMap,\n NotionGenericContentModel,\n NotionPageLike,\n} from \"./types\";\n\ntype PropertyMap = Record<string, unknown>;\n\ntype DataSourceQueryResponse = {\n results?: unknown[];\n has_more?: boolean;\n next_cursor?: string | null;\n};\n\ntype QueryDataSourceInput = {\n startCursor?: string;\n};\n\nexport type GenericContentListItem = {\n pageId: string;\n slug: string;\n title: string;\n description: string;\n date: string;\n tags: string[];\n coverImage: string | null;\n published: boolean;\n editUrl: string | null;\n properties: Record<string, string | string[]>;\n};\n\nexport type GenericContentDetail = GenericContentListItem & {\n blocks: NotionBlock[];\n};\n\nexport type GenericContentSourceDeps<\n TFields extends NotionFieldMap = NotionFieldMap,\n> = {\n model: NotionGenericContentModel & { source: { fields: TFields } };\n dataSourceId: string;\n queryDataSource: (\n input?: QueryDataSourceInput\n ) => Promise<DataSourceQueryResponse>;\n getPageBlocks: (pageId: string) => Promise<NotionBlock[]>;\n editBaseUrl?: string;\n};\n\nfunction normalizePage(input: unknown): NotionPageLike | null {\n if (!input || typeof input !== \"object\") return null;\n const page = input as NotionPageLike;\n return page.id ? page : null;\n}\n\nfunction firstFieldName(value: string | readonly string[] | undefined) {\n if (Array.isArray(value)) return value[0];\n return value;\n}\n\nfunction getFieldName(fields: NotionFieldMap, key: string) {\n return firstFieldName(fields[key]);\n}\n\nfunction pickPublishedFlagForModel(\n properties: PropertyMap,\n fields: NotionFieldMap\n) {\n const publishedField = getFieldName(fields, \"published\") ?? \"Published\";\n const published = properties[publishedField] as\n | Record<string, unknown>\n | undefined;\n if (published?.type === \"checkbox\") return Boolean(published.checkbox);\n\n const statusField = getFieldName(fields, \"status\") ?? \"Status\";\n const status = properties[statusField] as Record<string, unknown> | undefined;\n if (status?.type === \"status\") {\n const value = status.status as { name?: string } | null | undefined;\n return String(value?.name ?? \"\").trim().toLowerCase() === \"published\";\n }\n if (status?.type === \"select\") {\n const value = status.select as { name?: string } | null | undefined;\n return String(value?.name ?? \"\").trim().toLowerCase() === \"published\";\n }\n\n return true;\n}\n\nfunction coverImageUrlForModel(page: NotionPageLike, fields: NotionFieldMap) {\n const coverField = fields.cover;\n if (Array.isArray(coverField)) {\n for (const field of coverField) {\n const imageUrl = coverImageUrlForPage(page, field);\n if (imageUrl) return imageUrl;\n }\n }\n if (typeof coverField === \"string\") {\n return coverImageUrlForPage(page, coverField);\n }\n return coverImageUrlForPage(page);\n}\n\nfunction mapExtraProperties(properties: PropertyMap, fields: NotionFieldMap) {\n const result: Record<string, string | string[]> = {};\n for (const [key, value] of Object.entries(fields)) {\n const field = firstFieldName(value);\n if (!field) continue;\n const tags = getTagsProperty(properties, field);\n result[key] = tags.length > 0 ? tags : getRichTextProperty(properties, field);\n }\n return result;\n}\n\nexport function mapNotionPageToGenericContentItem<\n TFields extends NotionFieldMap,\n>(\n model: { id: string; source: { fields: TFields } },\n page: NotionPageLike,\n options?: { editBaseUrl?: string }\n): GenericContentListItem {\n const fields = model.source.fields;\n const properties = isRecord(page.properties) ? page.properties : {};\n const titleField = getFieldName(fields, \"title\");\n const slugField = getFieldName(fields, \"slug\");\n const descriptionField = getFieldName(fields, \"description\");\n const dateField = getFieldName(fields, \"date\");\n const tagsField = getFieldName(fields, \"tags\");\n\n const title = titleField ? getRichTextProperty(properties, titleField) : \"\";\n const slug = slugField\n ? getRichTextProperty(properties, slugField).toLowerCase()\n : page.id.replaceAll(\"-\", \"\").toLowerCase();\n const description = pickDescriptionFallback(\n descriptionField ? getRichTextProperty(properties, descriptionField) : \"\",\n title\n );\n\n return {\n pageId: page.id,\n slug,\n title,\n description,\n date: dateField ? getDateProperty(properties, dateField) : \"\",\n tags: tagsField ? getTagsProperty(properties, tagsField) : [],\n coverImage: coverImageUrlForModel(page, fields),\n published: pickPublishedFlagForModel(properties, fields),\n editUrl: notionPageEditUrl(page.id, options?.editBaseUrl),\n properties: mapExtraProperties(properties, fields),\n };\n}\n\nexport function isRenderableGenericContentItem(item: GenericContentListItem) {\n return Boolean(item.published && item.title && item.slug && isValidPublicSlug(item.slug));\n}\n\nexport function createGenericNotionContentSource<\n TFields extends NotionFieldMap,\n>(deps: GenericContentSourceDeps<TFields>) {\n return {\n async listItems(): Promise<GenericContentListItem[]> {\n const pages: NotionPageLike[] = [];\n let cursor: string | undefined;\n\n do {\n const response = await deps.queryDataSource({ startCursor: cursor });\n for (const item of response.results ?? []) {\n const page = normalizePage(item);\n if (page) pages.push(page);\n }\n\n cursor = response.next_cursor ?? undefined;\n if (!response.has_more) break;\n } while (cursor);\n\n return pages\n .map((page) =>\n mapNotionPageToGenericContentItem(deps.model, page, {\n editBaseUrl: deps.editBaseUrl,\n })\n )\n .filter(isRenderableGenericContentItem)\n .sort((a, b) => b.date.localeCompare(a.date));\n },\n\n async getItemBySlug(slug: string): Promise<GenericContentDetail | null> {\n const items = await this.listItems();\n const item = items.find((candidate) => candidate.slug === slug);\n if (!item) return null;\n return {\n ...item,\n blocks: await deps.getPageBlocks(item.pageId),\n };\n },\n };\n}\n\nasync function createDefaultGenericSource<\n TFields extends NotionFieldMap,\n>(model: NotionGenericContentModel & { source: { fields: TFields } }) {\n if (!(await hasNotionModelConfig(model))) return null;\n\n const config = await getNotionConfigForModel(model);\n const client = createNotionClient(config);\n return createGenericNotionContentSource({\n model,\n dataSourceId: config.dataSourceId,\n editBaseUrl: config.editBaseUrl,\n queryDataSource: async ({ startCursor } = {}) =>\n client.dataSources.query({\n data_source_id: config.dataSourceId,\n page_size: model.source.query.pageSize,\n sorts: model.source.query.sorts\n ? [...model.source.query.sorts]\n : undefined,\n filter_properties: model.source.query.filterProperties\n ? [...model.source.query.filterProperties]\n : undefined,\n ...(startCursor ? { start_cursor: startCursor } : {}),\n }),\n getPageBlocks: (pageId) =>\n listBlockChildrenDeep(client as unknown as NotionBlockClient, pageId),\n });\n}\n\nconst sourceCache = cache(createDefaultGenericSource);\n\nexport async function listGenericNotionContent<\n TFields extends NotionFieldMap,\n>(model: NotionGenericContentModel & { source: { fields: TFields } }) {\n const source = await sourceCache(model);\n if (!source) return [];\n return source.listItems();\n}\n\nexport async function getGenericNotionContentBySlug<\n TFields extends NotionFieldMap,\n>(model: NotionGenericContentModel & { source: { fields: TFields } }, slug: string) {\n const source = await sourceCache(model);\n if (!source) return null;\n return source.getItemBySlug(slug);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\");\n}\n","type PropertyMap = Record<string, unknown>;\n\ntype TextPart = {\n plain_text?: string;\n};\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\");\n}\n\nfunction getPlainText(parts: unknown): string {\n if (!Array.isArray(parts)) return \"\";\n return parts\n .map((part: TextPart) => part.plain_text ?? \"\")\n .join(\"\")\n .trim();\n}\n\nfunction getProperty(properties: PropertyMap, key: string) {\n return properties[key] as Record<string, unknown> | undefined;\n}\n\nfunction firstPropertyOfType(properties: PropertyMap, type: string) {\n return Object.values(properties).find(\n (property): property is Record<string, unknown> =>\n isRecord(property) && property.type === type\n );\n}\n\nexport function getFirstTitleProperty(properties: PropertyMap): string {\n const property = firstPropertyOfType(properties, \"title\");\n return property ? getPlainText(property.title) : \"\";\n}\n\nexport function getRichTextProperty(properties: PropertyMap, key: string): string {\n const property = getProperty(properties, key);\n if (!property) return \"\";\n\n if (property.type === \"title\") return getPlainText(property.title);\n if (property.type === \"rich_text\") return getPlainText(property.rich_text);\n if (property.type === \"url\") return String(property.url ?? \"\").trim();\n if (property.type === \"email\") return String(property.email ?? \"\").trim();\n if (property.type === \"phone_number\") {\n return String(property.phone_number ?? \"\").trim();\n }\n\n return \"\";\n}\n\nexport function getDateProperty(properties: PropertyMap, key: string): string {\n const property = getProperty(properties, key);\n if (property?.type !== \"date\") return \"\";\n const date = property.date as { start?: string } | null | undefined;\n return String(date?.start ?? \"\").trim();\n}\n\nexport function getFirstDateProperty(properties: PropertyMap): string {\n const property = firstPropertyOfType(properties, \"date\");\n if (!property) return \"\";\n const date = property.date as { start?: string } | null | undefined;\n return String(date?.start ?? \"\").trim();\n}\n\nexport function getSelectProperty(properties: PropertyMap, key: string): string {\n const property = getProperty(properties, key);\n if (property?.type !== \"select\") return \"\";\n const select = property.select as { name?: string } | null | undefined;\n return String(select?.name ?? \"\").trim();\n}\n\nexport function getCheckboxProperty(properties: PropertyMap, key: string): boolean {\n const property = getProperty(properties, key);\n if (property?.type !== \"checkbox\") return false;\n return Boolean(property.checkbox);\n}\n\nexport function getNumberProperty(\n properties: PropertyMap,\n key: string,\n fallback = 0\n): number {\n const property = getProperty(properties, key);\n if (property?.type !== \"number\") return fallback;\n const value = Number(property.number);\n return Number.isFinite(value) ? value : fallback;\n}\n\nexport function getRelationPageIds(properties: PropertyMap, key: string): string[] {\n const property = getProperty(properties, key);\n if (property?.type !== \"relation\" || !Array.isArray(property.relation)) {\n return [];\n }\n\n return property.relation\n .map((item: { id?: string }) => String(item.id ?? \"\").trim())\n .filter(Boolean);\n}\n\nexport function getTagsProperty(properties: PropertyMap, key: string): string[] {\n const property = getProperty(properties, key);\n if (property?.type === \"multi_select\" && Array.isArray(property.multi_select)) {\n return property.multi_select\n .map((item: { name?: string }) => String(item.name ?? \"\").trim())\n .filter(Boolean);\n }\n\n if (property?.type === \"select\") {\n const select = property.select as { name?: string } | null | undefined;\n const name = String(select?.name ?? \"\").trim();\n return name ? [name] : [];\n }\n\n return [];\n}\n\nexport function getFirstTagsProperty(properties: PropertyMap): string[] {\n const multiSelect = firstPropertyOfType(properties, \"multi_select\");\n if (multiSelect && Array.isArray(multiSelect.multi_select)) {\n return multiSelect.multi_select\n .map((item: { name?: string }) => String(item.name ?? \"\").trim())\n .filter(Boolean);\n }\n\n const select = firstPropertyOfType(properties, \"select\");\n const name = String((select?.select as { name?: string } | null)?.name ?? \"\").trim();\n return name ? [name] : [];\n}\n\nexport function getAuthorProperty(properties: PropertyMap, key: string): string {\n const property = getProperty(properties, key);\n if (!property) return \"\";\n\n if (property.type === \"people\" && Array.isArray(property.people)) {\n return property.people\n .map((person: { name?: string; person?: { email?: string } }) =>\n String(person.name ?? person.person?.email ?? \"\").trim()\n )\n .filter(Boolean)\n .join(\", \");\n }\n\n return getRichTextProperty(properties, key);\n}\n\nexport function getFirstPeopleProperty(properties: PropertyMap): string {\n const property = firstPropertyOfType(properties, \"people\");\n if (!property || !Array.isArray(property.people)) return \"\";\n\n return property.people\n .map((person: { name?: string; person?: { email?: string } }) =>\n String(person.name ?? person.person?.email ?? \"\").trim()\n )\n .filter(Boolean)\n .join(\", \");\n}\n\nexport function pickPublishedFlag(properties: PropertyMap): boolean {\n const published = getProperty(properties, \"Published\");\n if (published?.type === \"checkbox\") {\n return Boolean(published.checkbox);\n }\n\n const status = getProperty(properties, \"Status\");\n if (status?.type === \"status\") {\n const statusValue = status.status as { name?: string } | null | undefined;\n return String(statusValue?.name ?? \"\").trim().toLowerCase() === \"published\";\n }\n\n if (status?.type === \"select\") {\n const statusValue = status.select as { name?: string } | null | undefined;\n return String(statusValue?.name ?? \"\").trim().toLowerCase() === \"published\";\n }\n\n return false;\n}\n\nexport function pickDescriptionFallback(description: string, title: string): string {\n return description.trim() || title.trim();\n}\n\nexport function isValidPublicSlug(slug: string): boolean {\n return /^[a-z0-9][a-z0-9-]{0,79}$/.test(slug);\n}\n\nexport function notionPageEditUrl(pageId: string, editBaseUrl?: string): string {\n const compactPageId = pageId.replaceAll(\"-\", \"\");\n if (editBaseUrl?.includes(\"{pageId}\")) {\n return editBaseUrl.replaceAll(\"{pageId}\", compactPageId);\n }\n return `https://www.notion.so/${compactPageId}`;\n}\n\n/**\n * Normalize a Notion page id (with or without dashes) to a compact lowercase\n * string. Used as a stable identifier in URLs and cache keys.\n */\nexport function compactNotionId(id: string): string {\n return id.replaceAll(\"-\", \"\").toLowerCase();\n}\n","import type { KeyValueCacheAdapter } from \"../platform/runtime\";\nimport { createNotionClient } from \"./client\";\nimport { getNotionConfigForModel } from \"./config\";\nimport {\n compactNotionId,\n getRichTextProperty,\n getSelectProperty,\n isValidPublicSlug,\n} from \"./property-mappers\";\nimport type {\n NotionFieldMap,\n NotionGenericContentModel,\n NotionPageLike,\n} from \"./types\";\n\ntype JsonRecord = Record<string, unknown>;\n\ntype StoredWebhookVerificationToken = {\n token: string;\n updatedAt: string;\n};\n\nconst WEBHOOK_VERIFICATION_TOKEN_CACHE_KEY =\n \"notion:webhook:verification-token:v1\";\n\nexport type NotionWebhookParseResult =\n | { type: \"verification\"; verificationToken: string }\n | { type: \"events\"; events: NotionWebhookEvent[] };\n\nexport type NotionWebhookEvent = {\n id?: string;\n eventType: string;\n modelId: string;\n pageId?: string;\n dataSourceId?: string;\n routeId?: string;\n locale?: string;\n kind: \"publish\" | \"update\" | \"delete\";\n includeApi: boolean;\n reason: \"page\" | \"data_source\";\n};\n\n/**\n * Generic shape that callers (i.e. the starter) supply so the webhook can\n * route events to the correct content model. Each entry must expose the\n * Notion data source id that the model is bound to, and a hook to derive a\n * route id and locale from the Notion page payload.\n */\nexport type NotionWebhookModelRegistration<\n TFields extends NotionFieldMap = NotionFieldMap,\n> = NotionGenericContentModel & {\n source: { fields: TFields };\n resolveRouteId?: (page: JsonRecord) => string;\n resolveLocale?: (page: JsonRecord) => string;\n};\n\nexport type NotionPageRetriever = (\n pageId: string,\n model: NotionGenericContentModel\n) => Promise<NotionPageLike | null>;\n\nexport type NotionWebhookParseOptions<\n TFields extends NotionFieldMap = NotionFieldMap,\n> = {\n models: ReadonlyArray<NotionWebhookModelRegistration<TFields>>;\n /**\n * Optional override for resolving the data source id of a model. Defaults\n * to `process.env[model.source.dataSourceEnv] ?? model.source.defaultDataSourceId`.\n */\n getModelDataSourceId?: (model: NotionWebhookModelRegistration<TFields>) => string | null;\n};\n\nexport type InvalidationKind = \"publish\" | \"update\" | \"delete\";\n\n/**\n * Request shape consumed by the revalidation pipeline. Mirrors the starter's\n * `ContentRevalidateRequest`; duplicated here so the package does not need\n * a runtime dependency on the starter.\n */\nexport type NotionWebhookRevalidateRequest = {\n modelId: string;\n pageId?: string;\n routeId?: string;\n previousRouteId?: string;\n locale?: string;\n kind?: InvalidationKind;\n includeApi?: boolean;\n};\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return Boolean(value && typeof value === \"object\" && !Array.isArray(value));\n}\n\nfunction readString(source: unknown, key: string) {\n if (!isRecord(source)) return \"\";\n const value = source[key];\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction asRecords(value: unknown) {\n if (Array.isArray(value)) return value.filter(isRecord);\n if (isRecord(value)) return [value];\n return [];\n}\n\nfunction nestedRecords(source: JsonRecord, ...keys: string[]) {\n const records: JsonRecord[] = [];\n for (const key of keys) {\n const value = source[key];\n if (isRecord(value)) records.push(value);\n }\n return records;\n}\n\nfunction firstString(...values: string[]) {\n return values.find(Boolean) ?? \"\";\n}\n\nfunction normalizeId(value: string) {\n return value.replaceAll(\"-\", \"\").toLowerCase();\n}\n\nfunction findIdByType(input: JsonRecord, type: string): string {\n const stack = [input];\n const seen = new Set<JsonRecord>();\n\n while (stack.length > 0) {\n const current = stack.pop();\n if (!current || seen.has(current)) continue;\n seen.add(current);\n\n if (readString(current, \"type\") === type) {\n const id = readString(current, \"id\");\n if (id) return id;\n }\n\n for (const value of Object.values(current)) {\n if (isRecord(value)) stack.push(value);\n if (Array.isArray(value)) {\n for (const item of value) {\n if (isRecord(item)) stack.push(item);\n }\n }\n }\n }\n\n return \"\";\n}\n\nfunction findDataSourceId(input: JsonRecord): string {\n const stack = [input];\n const seen = new Set<JsonRecord>();\n\n while (stack.length > 0) {\n const current = stack.pop();\n if (!current || seen.has(current)) continue;\n seen.add(current);\n\n const direct = firstString(\n readString(current, \"data_source_id\"),\n readString(current, \"source_id\")\n );\n if (direct) return direct;\n\n const type = readString(current, \"type\");\n if (type === \"data_source\") {\n const id = readString(current, \"id\");\n if (id) return id;\n }\n\n for (const value of Object.values(current)) {\n if (isRecord(value)) stack.push(value);\n if (Array.isArray(value)) {\n for (const item of value) {\n if (isRecord(item)) stack.push(item);\n }\n }\n }\n }\n\n return \"\";\n}\n\nfunction firstFieldName(value: string | readonly string[] | undefined) {\n if (Array.isArray(value)) return value[0];\n return value;\n}\n\nfunction defaultRouteIdFromProperties(\n model: NotionGenericContentModel,\n page: JsonRecord\n) {\n const properties = isRecord(page.properties) ? page.properties : {};\n const slugField = firstFieldName(model.source.fields.slug);\n const slug = slugField\n ? getRichTextProperty(properties, slugField).toLowerCase()\n : \"\";\n return isValidPublicSlug(slug) ? slug : \"\";\n}\n\nfunction defaultLocaleFromProperties(model: NotionGenericContentModel, page: JsonRecord) {\n const properties = isRecord(page.properties) ? page.properties : {};\n const localeField = firstFieldName(model.source.fields.locale);\n return localeField ? getSelectProperty(properties, localeField) : \"\";\n}\n\nfunction eventKind(eventType: string): \"publish\" | \"update\" | \"delete\" {\n if (eventType.includes(\".deleted\")) return \"delete\";\n if (eventType.includes(\".created\") || eventType.includes(\".undeleted\")) {\n return \"publish\";\n }\n return \"update\";\n}\n\nfunction defaultGetModelDataSourceId(\n model: NotionGenericContentModel\n): string | null {\n const fromEnv = process.env[model.source.dataSourceEnv];\n if (fromEnv) return fromEnv;\n return model.source.defaultDataSourceId ?? null;\n}\n\nfunction matchModelByDataSourceId<\n TFields extends NotionFieldMap,\n>(\n models: ReadonlyArray<NotionWebhookModelRegistration<TFields>>,\n dataSourceId: string,\n getDataSourceId: (model: NotionWebhookModelRegistration<TFields>) => string | null\n) {\n if (!dataSourceId) return null;\n const normalized = normalizeId(dataSourceId);\n return (\n models.find((model) => {\n const configured = getDataSourceId(model);\n return configured ? normalizeId(configured) === normalized : false;\n }) ?? null\n );\n}\n\nfunction findModelForEvent<\n TFields extends NotionFieldMap,\n>(\n models: ReadonlyArray<NotionWebhookModelRegistration<TFields>>,\n event: JsonRecord,\n page: JsonRecord | undefined,\n getDataSourceId: (model: NotionWebhookModelRegistration<TFields>) => string | null\n) {\n const modelId = firstString(\n readString(event, \"modelId\"),\n readString(event, \"model_id\"),\n readString(event.data, \"modelId\"),\n readString(event.data, \"model_id\")\n );\n if (modelId) {\n return models.find((model) => model.id === modelId) ?? null;\n }\n\n const dataSourceId = firstString(\n findDataSourceId(event),\n findIdByType(event, \"data_source\"),\n readString(event, \"data_source_id\"),\n readString(event.data, \"data_source_id\"),\n readString(page?.parent, \"data_source_id\"),\n readString(page?.parent, \"database_id\")\n );\n return matchModelByDataSourceId(models, dataSourceId, getDataSourceId);\n}\n\nfunction pageIdForEvent(event: JsonRecord, page?: JsonRecord) {\n return firstString(\n readString(page, \"id\"),\n findIdByType(event, \"page\"),\n readString(event, \"page_id\"),\n readString(event.data, \"page_id\")\n );\n}\n\nfunction pageForEvent(event: JsonRecord) {\n let fallback: JsonRecord | null = null;\n for (const record of [\n ...nestedRecords(isRecord(event.data) ? event.data : {}, \"page\", \"entity\"),\n ...nestedRecords(event, \"page\", \"entity\"),\n event,\n ]) {\n const type = readString(record, \"type\");\n if (type === \"page\" || readString(record, \"object\") === \"page\") {\n if (!readString(record, \"id\")) continue;\n if (isRecord(record.properties) || isRecord(record.parent)) return record;\n fallback ??= record;\n }\n }\n return fallback;\n}\n\nexport function parseNotionWebhookPayload<\n TFields extends NotionFieldMap = NotionFieldMap,\n>(\n payload: unknown,\n options: NotionWebhookParseOptions<TFields>\n): NotionWebhookParseResult {\n if (!isRecord(payload)) return { type: \"events\", events: [] };\n\n const verificationToken = readString(payload, \"verification_token\");\n if (verificationToken) {\n return { type: \"verification\", verificationToken };\n }\n\n const getDataSourceId = options.getModelDataSourceId ?? defaultGetModelDataSourceId;\n\n const events = asRecords(payload.events ?? payload.event ?? payload)\n .map((event) =>\n parseEvent(event, options.models, getDataSourceId)\n )\n .filter((event): event is NotionWebhookEvent => Boolean(event));\n\n return { type: \"events\", events };\n}\n\nfunction parseEvent<\n TFields extends NotionFieldMap,\n>(\n event: JsonRecord,\n models: ReadonlyArray<NotionWebhookModelRegistration<TFields>>,\n getDataSourceId: (model: NotionWebhookModelRegistration<TFields>) => string | null\n): NotionWebhookEvent | null {\n const eventType = firstString(readString(event, \"type\"), readString(event, \"event\"));\n if (!eventType) return null;\n const page = pageForEvent(event);\n const model = findModelForEvent(\n models,\n event,\n page ?? undefined,\n getDataSourceId\n );\n if (!model) return null;\n\n const routeId = page\n ? (model.resolveRouteId?.(page) ??\n defaultRouteIdFromProperties(model, page))\n : \"\";\n const locale = page\n ? (model.resolveLocale?.(page) ?? defaultLocaleFromProperties(model, page))\n : \"\";\n const dataSourceId = firstString(\n findDataSourceId(event),\n findIdByType(event, \"data_source\"),\n readString(event, \"data_source_id\"),\n readString(event.data, \"data_source_id\"),\n readString(page?.parent, \"data_source_id\"),\n readString(page?.parent, \"database_id\")\n );\n const dataSourceEvent =\n eventType.startsWith(\"data_source.\") || eventType.startsWith(\"database.\");\n return {\n id: readString(event, \"id\") || undefined,\n eventType,\n modelId: model.id,\n pageId: pageIdForEvent(event, page ?? undefined) || undefined,\n dataSourceId: dataSourceId || undefined,\n routeId: routeId || undefined,\n locale: locale || undefined,\n kind: eventKind(eventType),\n includeApi: true,\n reason: page && routeId ? \"page\" : dataSourceEvent ? \"data_source\" : \"page\",\n };\n}\n\nasync function defaultRetrieveNotionPage(\n pageId: string,\n model: NotionGenericContentModel\n) {\n const config = await getNotionConfigForModel(model);\n const client = createNotionClient(config);\n const page = await client.pages.retrieve({ page_id: pageId });\n return page as NotionPageLike;\n}\n\nfunction resolveWebhookEventRoute<\n TFields extends NotionFieldMap,\n>(\n event: NotionWebhookEvent,\n models: ReadonlyArray<NotionWebhookModelRegistration<TFields>>,\n retrievePage: NotionPageRetriever\n): Promise<NotionWebhookEvent> {\n if (event.routeId || !event.pageId) return Promise.resolve(event);\n if (event.kind === \"delete\") return Promise.resolve(event);\n\n const model = models.find((m) => m.id === event.modelId);\n if (!model) return Promise.resolve(event);\n\n return retrievePage(event.pageId, model)\n .then((page) => {\n if (!page) return event;\n const pageRecord = page as unknown as JsonRecord;\n const routeId =\n model.resolveRouteId?.(pageRecord) ??\n defaultRouteIdFromProperties(model, pageRecord);\n const locale =\n model.resolveLocale?.(pageRecord) ??\n defaultLocaleFromProperties(model, pageRecord);\n if (!routeId) return event;\n return {\n ...event,\n routeId,\n locale: locale || event.locale,\n reason: \"page\" as const,\n };\n })\n .catch((error) => {\n const err = error as { code?: string; status?: number; message?: string };\n console.warn(\n JSON.stringify({\n tag: \"notion_webhook_page_lookup_failed\",\n eventId: event.id,\n eventType: event.eventType,\n modelId: event.modelId,\n pageId: event.pageId,\n code: err?.code,\n status: err?.status,\n message: err?.message ?? String(error),\n })\n );\n return event;\n });\n}\n\nexport async function parseNotionWebhookPayloadWithPageLookup<\n TFields extends NotionFieldMap = NotionFieldMap,\n>(\n payload: unknown,\n options: NotionWebhookParseOptions<TFields> & {\n retrievePage?: NotionPageRetriever;\n lookupPages?: boolean;\n }\n): Promise<NotionWebhookParseResult> {\n const parsed = parseNotionWebhookPayload(payload, options);\n if (parsed.type === \"verification\") return parsed;\n if (options?.lookupPages === false) return parsed;\n\n const retrievePage = options?.retrievePage ?? defaultRetrieveNotionPage;\n return {\n type: \"events\",\n events: await Promise.all(\n parsed.events.map((event) =>\n resolveWebhookEventRoute(event, options.models, retrievePage)\n )\n ),\n };\n}\n\nexport function notionWebhookEventToRevalidateRequest(\n event: NotionWebhookEvent\n): NotionWebhookRevalidateRequest {\n return {\n modelId: event.modelId,\n pageId: event.pageId,\n routeId: event.routeId,\n locale: event.locale,\n kind: event.kind,\n includeApi: event.includeApi,\n };\n}\n\nexport async function signNotionWebhookBody(body: string, verificationToken: string) {\n const key = await crypto.subtle.importKey(\n \"raw\",\n new TextEncoder().encode(verificationToken),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n );\n const signature = await crypto.subtle.sign(\n \"HMAC\",\n key,\n new TextEncoder().encode(body)\n );\n return Array.from(new Uint8Array(signature))\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nfunction normalizeNotionSignature(signature: string | null) {\n const value = String(signature ?? \"\").trim();\n const prefixed = value.match(/^sha256=(.+)$/i);\n return prefixed && prefixed[1] ? prefixed[1].trim() : value;\n}\n\nexport async function verifyNotionWebhookSignature(input: {\n body: string;\n signature: string | null;\n verificationToken?: string | null;\n}) {\n const token = String(input.verificationToken ?? \"\").trim();\n const signature = normalizeNotionSignature(input.signature);\n if (!token || !signature) return false;\n const expected = await signNotionWebhookBody(input.body, token);\n if (expected.length !== signature.length) return false;\n\n let diff = 0;\n for (let index = 0; index < expected.length; index += 1) {\n diff |= expected.charCodeAt(index) ^ signature.charCodeAt(index);\n }\n return diff === 0;\n}\n\nexport async function verifyNotionWebhookSignatureWithTokens(input: {\n body: string;\n signature: string | null;\n verificationTokens: Array<string | null | undefined>;\n}) {\n const tokens = Array.from(\n new Set(input.verificationTokens.map((token) => String(token ?? \"\").trim()))\n ).filter(Boolean);\n\n for (const token of tokens) {\n if (\n await verifyNotionWebhookSignature({\n body: input.body,\n signature: input.signature,\n verificationToken: token,\n })\n ) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction readStoredWebhookVerificationToken(value: unknown) {\n if (typeof value === \"string\") return value.trim() || null;\n if (!isRecord(value)) return null;\n\n const token = readString(value, \"token\");\n return token || null;\n}\n\nexport async function getStoredNotionWebhookVerificationToken(\n cache: KeyValueCacheAdapter | null | undefined\n) {\n if (!cache) return null;\n\n try {\n const value = await cache.get<StoredWebhookVerificationToken | string>(\n WEBHOOK_VERIFICATION_TOKEN_CACHE_KEY,\n { cacheTtl: 60 }\n );\n return readStoredWebhookVerificationToken(value);\n } catch (error) {\n console.warn(\n JSON.stringify({\n tag: \"notion_webhook_token_lookup_failed\",\n message: error instanceof Error ? error.message : String(error),\n })\n );\n return null;\n }\n}\n\nexport async function putStoredNotionWebhookVerificationToken(\n cache: KeyValueCacheAdapter | null | undefined,\n token: string\n) {\n const normalized = token.trim();\n if (!cache || !normalized) return false;\n\n await cache.put<StoredWebhookVerificationToken>(\n WEBHOOK_VERIFICATION_TOKEN_CACHE_KEY,\n {\n token: normalized,\n updatedAt: new Date().toISOString(),\n },\n {\n metadata: {\n source: \"notion-webhook\",\n },\n }\n );\n return true;\n}\n\n// Re-exported for backwards compatibility with the starter.\nexport { compactNotionId };\n"],"mappings":"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","names":["cache","isRecord","isRecord","readString","firstFieldName","cache"]}
|
|
1
|
+
{"version":3,"sources":["../../src/notion/client.ts","../../src/notion/config.ts","../../src/notion/blocks.ts","../../src/notion/block-text.ts","../../src/notion/content-cache.ts","../../src/notion/media.ts","../../src/notion/generic-source.ts","../../src/notion/property-mappers.ts","../../src/notion/webhook.ts"],"sourcesContent":["import { Client } from \"@notionhq/client\";\nimport type { NotionClientConfig } from \"./config\";\n\nexport function createNotionClient(config: NotionClientConfig) {\n return new Client({\n auth: config.token,\n baseUrl: config.apiBaseUrl,\n notionVersion: \"2026-03-11\",\n });\n}\n","import type { NotionContentModelLike } from \"./types\";\n\ntype NotionEnv = {\n NOTION_TOKEN?: string;\n NOTION_DATA_SOURCE_ID?: string;\n NOTION_API_BASE_URL?: string;\n NOTION_EDIT_BASE_URL?: string;\n NOTION_WEBHOOK_VERIFICATION_TOKEN?: string;\n [key: string]: string | undefined;\n};\n\nexport type NotionClientConfig = {\n token: string;\n apiBaseUrl?: string;\n};\n\nexport type NotionConfig = {\n token: string;\n dataSourceId: string;\n apiBaseUrl?: string;\n editBaseUrl?: string;\n webhookVerificationToken?: string;\n};\n\nfunction readProcessEnv(): NotionEnv {\n const env: NotionEnv = {\n NOTION_TOKEN: process.env.NOTION_TOKEN,\n NOTION_DATA_SOURCE_ID: process.env.NOTION_DATA_SOURCE_ID,\n NOTION_API_BASE_URL: process.env.NOTION_API_BASE_URL,\n NOTION_EDIT_BASE_URL: process.env.NOTION_EDIT_BASE_URL,\n NOTION_WEBHOOK_VERIFICATION_TOKEN:\n process.env.NOTION_WEBHOOK_VERIFICATION_TOKEN,\n };\n\n for (const [key, value] of Object.entries(process.env)) {\n if (key.startsWith(\"NOTION_\") && typeof value === \"string\") {\n env[key] = value;\n }\n }\n\n return env;\n}\n\nasync function readWorkerEnv(): Promise<NotionEnv> {\n try {\n const mod = (await import(\n /* webpackIgnore: true */ \"cloudflare:workers\"\n )) as unknown as { env?: Record<string, unknown> };\n const env: NotionEnv = {};\n for (const [key, value] of Object.entries(mod.env ?? {})) {\n if (key.startsWith(\"NOTION_\") && typeof value === \"string\") {\n env[key] = value;\n }\n }\n return env;\n } catch {\n return {};\n }\n}\n\nfunction readString(source: NotionEnv, name: string): string | undefined {\n const value = String(source[name] ?? \"\").trim();\n return value || undefined;\n}\n\nfunction mergeEnv(...sources: NotionEnv[]): NotionEnv {\n const merged: NotionEnv = {};\n\n for (const source of sources) {\n for (const name of Object.keys(source)) {\n if (!name.startsWith(\"NOTION_\")) continue;\n const value = readString(source, name);\n if (value) merged[name] = value;\n }\n }\n\n return merged;\n}\n\nasync function readEnv(): Promise<NotionEnv> {\n const processEnv = readProcessEnv();\n return mergeEnv(await readWorkerEnv(), processEnv);\n}\n\nfunction readRequired(\n source: NotionEnv,\n name: string\n): string {\n const value = readString(source, name);\n if (!value) {\n throw new Error(`Missing required Notion env: ${name}`);\n }\n return value;\n}\n\nexport function getNotionEditBaseUrl(): string {\n return readString(readProcessEnv(), \"NOTION_EDIT_BASE_URL\") ?? \"https://www.notion.so\";\n}\n\nexport async function hasNotionConfig(): Promise<boolean> {\n const env = await readEnv();\n return Boolean(\n readString(env, \"NOTION_TOKEN\") && readString(env, \"NOTION_DATA_SOURCE_ID\")\n );\n}\n\nexport async function hasNotionModelConfig(\n model: NotionContentModelLike\n): Promise<boolean> {\n const env = await readEnv();\n return Boolean(\n readString(env, \"NOTION_TOKEN\") &&\n (readString(env, model.source.dataSourceEnv) ||\n model.source.defaultDataSourceId)\n );\n}\n\nexport async function getNotionClientConfig(): Promise<NotionClientConfig> {\n const env = await readEnv();\n return {\n token: readRequired(env, \"NOTION_TOKEN\"),\n apiBaseUrl: readString(env, \"NOTION_API_BASE_URL\"),\n };\n}\n\nexport async function getNotionConfig(): Promise<NotionConfig> {\n const env = await readEnv();\n return {\n token: readRequired(env, \"NOTION_TOKEN\"),\n dataSourceId: readRequired(env, \"NOTION_DATA_SOURCE_ID\"),\n apiBaseUrl: readString(env, \"NOTION_API_BASE_URL\"),\n editBaseUrl: readString(env, \"NOTION_EDIT_BASE_URL\"),\n webhookVerificationToken: readString(\n env,\n \"NOTION_WEBHOOK_VERIFICATION_TOKEN\"\n ),\n };\n}\n\nexport async function getNotionWebhookVerificationToken(): Promise<\n string | undefined\n> {\n const env = await readEnv();\n return readString(env, \"NOTION_WEBHOOK_VERIFICATION_TOKEN\");\n}\n\nexport async function getNotionConfigForModel(\n model: NotionContentModelLike\n): Promise<NotionConfig> {\n const env = await readEnv();\n const dataSourceId =\n readString(env, model.source.dataSourceEnv) ??\n model.source.defaultDataSourceId;\n if (!dataSourceId) {\n throw new Error(`Missing required Notion env: ${model.source.dataSourceEnv}`);\n }\n\n return {\n token: readRequired(env, model.source.tokenEnv),\n dataSourceId,\n apiBaseUrl: readString(env, \"NOTION_API_BASE_URL\"),\n editBaseUrl: readString(env, \"NOTION_EDIT_BASE_URL\"),\n webhookVerificationToken: readString(\n env,\n \"NOTION_WEBHOOK_VERIFICATION_TOKEN\"\n ),\n };\n}\n","import type { NotionBlock } from \"./types\";\n\ntype BlockChildrenListResponse = {\n results?: unknown[];\n has_more?: boolean;\n next_cursor?: string | null;\n};\n\nexport type NotionBlockClient = {\n blocks: {\n children: {\n list: (args: {\n block_id: string;\n page_size?: number;\n start_cursor?: string;\n }) => Promise<BlockChildrenListResponse>;\n };\n };\n};\n\nfunction normalizeBlock(input: unknown): NotionBlock | null {\n if (!input || typeof input !== \"object\") return null;\n const block = input as NotionBlock;\n return block.id && block.type ? block : null;\n}\n\nexport async function listBlockChildren(\n client: NotionBlockClient,\n blockId: string\n): Promise<NotionBlock[]> {\n const results: NotionBlock[] = [];\n let cursor: string | undefined;\n\n do {\n const response = await client.blocks.children.list({\n block_id: blockId,\n page_size: 100,\n ...(cursor ? { start_cursor: cursor } : {}),\n });\n\n for (const item of response.results ?? []) {\n const block = normalizeBlock(item);\n if (block) results.push(block);\n }\n\n cursor = response.next_cursor ?? undefined;\n if (!response.has_more) break;\n } while (cursor);\n\n return results;\n}\n\nexport async function listBlockChildrenDeep(\n client: NotionBlockClient,\n blockId: string,\n options?: { maxDepth?: number }\n): Promise<NotionBlock[]> {\n const maxDepth = options?.maxDepth ?? 6;\n\n async function visit(id: string, depth: number): Promise<NotionBlock[]> {\n const children = await listBlockChildren(client, id);\n if (depth >= maxDepth) return children;\n\n return Promise.all(\n children.map(async (block) => {\n if (!block.has_children) return block;\n return {\n ...block,\n children: await visit(block.id, depth + 1),\n };\n })\n );\n }\n\n return visit(blockId, 0);\n}\n","import type { NotionBlock, NotionRichTextPart } from \"./types\";\n\ntype RichTextContainer = {\n rich_text?: NotionRichTextPart[];\n caption?: NotionRichTextPart[];\n title?: NotionRichTextPart[];\n cells?: NotionRichTextPart[][];\n expression?: string;\n};\n\nfunction typedValue(block: NotionBlock): RichTextContainer {\n return (block[block.type] ?? {}) as RichTextContainer;\n}\n\nfunction richTextPlainText(parts: unknown) {\n if (!Array.isArray(parts)) return \"\";\n return parts\n .map((part: NotionRichTextPart) =>\n part.type === \"equation\"\n ? part.equation?.expression ?? \"\"\n : part.plain_text ?? part.text?.content ?? \"\"\n )\n .join(\"\");\n}\n\nfunction blockPlainText(block: NotionBlock) {\n const value = typedValue(block);\n const text = [\n richTextPlainText(value.rich_text),\n richTextPlainText(value.caption),\n richTextPlainText(value.title),\n value.expression ?? \"\",\n ...(value.cells ?? []).map(richTextPlainText),\n ];\n\n return text.filter(Boolean).join(\" \");\n}\n\nexport function flattenNotionBlockText(blocks: readonly NotionBlock[]): string {\n const parts: string[] = [];\n\n function visit(block: NotionBlock) {\n const text = blockPlainText(block).trim();\n if (text) parts.push(text);\n for (const child of block.children ?? []) {\n visit(child);\n }\n }\n\n for (const block of blocks) visit(block);\n\n return parts\n .join(\" \")\n .normalize(\"NFKC\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n","import type { KeyValueCacheAdapter } from \"../platform/runtime\";\nimport type { NotionBlock } from \"./types\";\n\nconst CACHE_VERSION = \"v2\";\nexport const NOTION_LIST_CACHE_TTL_SECONDS = 300;\nexport const NOTION_BLOCKS_CACHE_TTL_SECONDS = 60 * 60 * 24;\nconst CONTENT_CACHE_READ_TTL_SECONDS = 60;\n\nexport type NotionContentCacheDeleteResult = {\n ok: boolean;\n skipped: boolean;\n deleted: string[];\n failed: Array<{ key?: string; error: string }>;\n};\n\ntype CacheableValue = Record<string, unknown> | unknown[] | null;\n\nfunction modelPrefix(modelId: string) {\n return `notion:${CACHE_VERSION}:${modelId}`;\n}\n\nexport function notionModelListCacheKey(modelId: string) {\n return `${modelPrefix(modelId)}:list`;\n}\n\nfunction versionSegment(value?: string) {\n const version = String(value ?? \"\").trim();\n return version ? `:v:${encodeURIComponent(version)}` : \"\";\n}\n\nexport function notionPageBlocksCacheKey(\n modelId: string,\n pageId: string,\n cacheVersion?: string\n) {\n return `${modelPrefix(modelId)}:page:${pageId}:blocks${versionSegment(cacheVersion)}`;\n}\n\nexport function notionModelCachePrefix(modelId: string) {\n return `${modelPrefix(modelId)}:`;\n}\n\nexport function notionPageCachePrefix(modelId: string, pageId: string) {\n return `${modelPrefix(modelId)}:page:${pageId}:`;\n}\n\nfunction logNotionContentCache(fields: Record<string, unknown>) {\n try {\n console.log(JSON.stringify({ tag: \"notion_content_cache\", ...fields }));\n } catch {\n // Ignore logging serialization errors.\n }\n}\n\nexport async function getCachedNotionValue<T extends CacheableValue>(\n cache: KeyValueCacheAdapter | null | undefined,\n key: string\n): Promise<T | null> {\n if (!cache) return null;\n try {\n const value = await cache.get<T>(key, {\n cacheTtl: CONTENT_CACHE_READ_TTL_SECONDS,\n });\n logNotionContentCache({\n op: \"get\",\n key,\n hit: value !== null,\n cache: cache.kind,\n });\n return value;\n } catch (error) {\n logNotionContentCache({\n op: \"get_error\",\n key,\n cache: cache.kind,\n message: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n}\n\nexport async function putCachedNotionValue<T extends CacheableValue>(\n cache: KeyValueCacheAdapter | null | undefined,\n key: string,\n value: T,\n options?: { expirationTtl?: number }\n) {\n if (!cache) return;\n try {\n await cache.put(key, value, {\n expirationTtl: options?.expirationTtl ?? NOTION_BLOCKS_CACHE_TTL_SECONDS,\n metadata: {\n source: \"notion\",\n cachedAt: new Date().toISOString(),\n },\n });\n logNotionContentCache({\n op: \"put\",\n key,\n cache: cache.kind,\n });\n } catch (error) {\n logNotionContentCache({\n op: \"put_error\",\n key,\n cache: cache.kind,\n message: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\nexport async function getCachedNotionBlocks(\n cache: KeyValueCacheAdapter | null | undefined,\n input: { modelId: string; pageId: string; cacheVersion?: string }\n) {\n return getCachedNotionValue<NotionBlock[]>(\n cache,\n notionPageBlocksCacheKey(input.modelId, input.pageId, input.cacheVersion)\n );\n}\n\nexport async function putCachedNotionBlocks(\n cache: KeyValueCacheAdapter | null | undefined,\n input: {\n modelId: string;\n pageId: string;\n cacheVersion?: string;\n blocks: NotionBlock[];\n }\n) {\n await putCachedNotionValue(\n cache,\n notionPageBlocksCacheKey(input.modelId, input.pageId, input.cacheVersion),\n input.blocks,\n { expirationTtl: NOTION_BLOCKS_CACHE_TTL_SECONDS }\n );\n}\n\nexport async function deleteNotionContentCache(input: {\n modelId: string;\n pageId?: string;\n routeId?: string;\n previousRouteId?: string;\n cache?: KeyValueCacheAdapter | null;\n getCache?: () => KeyValueCacheAdapter | null;\n}): Promise<NotionContentCacheDeleteResult> {\n let cache: KeyValueCacheAdapter | null;\n try {\n cache = input.cache ?? input.getCache?.() ?? null;\n } catch (error) {\n return {\n ok: false,\n skipped: true,\n deleted: [],\n failed: [\n {\n error: error instanceof Error ? error.message : String(error),\n },\n ],\n };\n }\n\n if (!cache) {\n return { ok: true, skipped: true, deleted: [], failed: [] };\n }\n\n const prefixes = new Set<string>();\n if (input.pageId) {\n prefixes.add(notionPageCachePrefix(input.modelId, input.pageId));\n } else {\n prefixes.add(notionModelCachePrefix(input.modelId));\n }\n\n prefixes.add(notionModelListCacheKey(input.modelId));\n\n const deleted: string[] = [];\n const failed: Array<{ key?: string; error: string }> = [];\n\n for (const prefix of prefixes) {\n let cursor: string | undefined;\n do {\n try {\n const result = await cache.list({ prefix, cursor, limit: 100 });\n for (const { name } of result.keys) {\n try {\n await cache.delete(name);\n deleted.push(name);\n } catch (error) {\n failed.push({\n key: name,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n cursor = result.listComplete ? undefined : result.cursor;\n } catch (error) {\n failed.push({\n key: prefix,\n error: error instanceof Error ? error.message : String(error),\n });\n cursor = undefined;\n }\n } while (cursor);\n }\n\n return {\n ok: failed.length === 0,\n skipped: false,\n deleted,\n failed,\n };\n}\n","import type { NotionBlock, NotionFileSource, NotionPageLike } from \"./types\";\n\ntype FileLike = {\n type?: string;\n external?: { url?: string };\n file?: { url?: string; expiry_time?: string };\n name?: string;\n};\n\nfunction stripLeadingSlash(value: string) {\n return value.startsWith(\"/\") ? value.slice(1) : value;\n}\n\nfunction encodePathPart(value: string) {\n return encodeURIComponent(stripLeadingSlash(value));\n}\n\nfunction appendVersion(path: string, version?: string) {\n const value = String(version ?? \"\").trim();\n if (!value) return path;\n return `${path}?${new URLSearchParams({ v: value })}`;\n}\n\nfunction blockVersion(block: NotionBlock): string | undefined {\n return typeof block.last_edited_time === \"string\"\n ? block.last_edited_time\n : undefined;\n}\n\nexport function notionPageCoverMediaPath(pageId: string): string {\n return `/api/notion/media/page/${encodePathPart(pageId)}/cover`;\n}\n\nexport function notionPagePropertyMediaPath(\n pageId: string,\n propertyName: string\n): string {\n return `/api/notion/media/page/${encodePathPart(pageId)}/property/${encodePathPart(propertyName)}`;\n}\n\nexport function notionBlockMediaPath(blockId: string): string {\n return `/api/notion/media/block/${encodePathPart(blockId)}`;\n}\n\nexport function normalizeNotionFileSource(input: unknown): NotionFileSource | null {\n const file = input as FileLike | null | undefined;\n if (!file || typeof file !== \"object\") return null;\n\n if (file.type === \"external\") {\n const url = String(file.external?.url ?? \"\").trim();\n return url ? { type: \"external\", url } : null;\n }\n\n if (file.type === \"file\") {\n const url = String(file.file?.url ?? \"\").trim();\n if (!url) return null;\n return {\n type: \"file\",\n url,\n expiryTime: String(file.file?.expiry_time ?? \"\").trim() || null,\n };\n }\n\n return null;\n}\n\nexport function resolveNotionFileUrl(input: unknown): string | null {\n return normalizeNotionFileSource(input)?.url ?? null;\n}\n\nexport function isNotionHostedFile(input: unknown): boolean {\n return normalizeNotionFileSource(input)?.type === \"file\";\n}\n\nexport function pickFirstFilesPropertyValue(property: unknown): unknown | null {\n const value = property as { type?: string; files?: unknown[] } | null | undefined;\n if (!value || value.type !== \"files\" || !Array.isArray(value.files)) {\n return null;\n }\n return value.files[0] ?? null;\n}\n\nexport function pickPageCoverFile(page: NotionPageLike): unknown | null {\n return page.cover ?? null;\n}\n\nexport function coverImageUrlForPage(\n page: NotionPageLike,\n coverPropertyName = \"Cover\"\n): string | null {\n const propertyFile = pickFirstFilesPropertyValue(\n page.properties?.[coverPropertyName]\n );\n const propertySource = normalizeNotionFileSource(propertyFile);\n if (propertySource) {\n return appendVersion(\n notionPagePropertyMediaPath(page.id, coverPropertyName),\n page.last_edited_time\n );\n }\n\n const coverSource = normalizeNotionFileSource(pickPageCoverFile(page));\n if (coverSource) {\n return appendVersion(notionPageCoverMediaPath(page.id), page.last_edited_time);\n }\n\n return null;\n}\n\nexport function fileObjectForMediaBlock(block: NotionBlock): unknown | null {\n const typed = block[block.type] as Record<string, unknown> | undefined;\n if (!typed || typeof typed !== \"object\") return null;\n\n if (\n block.type === \"image\" ||\n block.type === \"video\" ||\n block.type === \"file\" ||\n block.type === \"pdf\" ||\n block.type === \"audio\"\n ) {\n return typed;\n }\n\n return null;\n}\n\nexport function mediaUrlForBlock(block: NotionBlock): string | null {\n const source = normalizeNotionFileSource(fileObjectForMediaBlock(block));\n if (!source) return null;\n if (source.type === \"external\" && block.type !== \"image\") {\n return source.url;\n }\n return appendVersion(notionBlockMediaPath(block.id), blockVersion(block));\n}\n\nexport function firstImageUrlFromBlocks(blocks: NotionBlock[]): string | null {\n for (const block of blocks) {\n if (block.type === \"image\") {\n const imageUrl = mediaUrlForBlock(block);\n if (imageUrl) return imageUrl;\n }\n\n const nested = block.children?.length\n ? firstImageUrlFromBlocks(block.children)\n : null;\n if (nested) return nested;\n }\n\n return null;\n}\n\nexport function publicMediaBlockForApi(block: NotionBlock): NotionBlock {\n const value = block[block.type];\n const source = normalizeNotionFileSource(value);\n const children = block.children?.map(publicMediaBlockForApi);\n\n if (!source) {\n return children ? { ...block, children } : { ...block };\n }\n\n const path = appendVersion(notionBlockMediaPath(block.id), blockVersion(block));\n const publicValue =\n source.type === \"external\"\n ? block.type === \"image\"\n ? {\n ...(value as Record<string, unknown>),\n external: { url: path },\n }\n : value\n : {\n ...(value as Record<string, unknown>),\n file: {\n url: path,\n expiry_time: null,\n },\n };\n\n return {\n ...block,\n [block.type]: publicValue,\n ...(children ? { children } : {}),\n };\n}\n\nexport function gatedMediaBlockForApi(\n block: NotionBlock,\n options?: { accessUrlForBlock?: (block: NotionBlock) => string | null }\n): NotionBlock {\n const value = block[block.type];\n const source = normalizeNotionFileSource(value);\n const children = block.children?.map((child) =>\n gatedMediaBlockForApi(child, options)\n );\n\n if (block.type !== \"video\" || !source) {\n const publicBlock = publicMediaBlockForApi(block);\n return children ? { ...publicBlock, children } : publicBlock;\n }\n\n const gatedValue: Record<string, unknown> = {\n ...(value as Record<string, unknown>),\n gated: true,\n access_url: options?.accessUrlForBlock?.(block) ?? null,\n };\n\n if (source.type === \"external\") {\n gatedValue.external = { url: null };\n } else {\n gatedValue.file = {\n url: null,\n expiry_time: null,\n };\n }\n\n return {\n ...block,\n video: gatedValue,\n ...(children ? { children } : {}),\n };\n}\n\nexport function isDirectVideoUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return /\\.(mp4|webm|mov|m4v)(?:$|\\?)/i.test(parsed.pathname);\n } catch {\n return false;\n }\n}\n\nexport function videoEmbedUrl(url: string): string | null {\n try {\n const parsed = new URL(url);\n const host = parsed.hostname.replace(/^www\\./, \"\");\n\n if (host === \"youtube.com\" || host === \"m.youtube.com\") {\n const id = parsed.searchParams.get(\"v\");\n return id ? `https://www.youtube.com/embed/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"youtu.be\") {\n const id = parsed.pathname.split(\"/\").filter(Boolean)[0];\n return id ? `https://www.youtube.com/embed/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"youtube-nocookie.com\") {\n return parsed.toString();\n }\n\n if (host === \"vimeo.com\") {\n const id = parsed.pathname.split(\"/\").filter(Boolean)[0];\n return id ? `https://player.vimeo.com/video/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"player.vimeo.com\") {\n return parsed.toString();\n }\n } catch {\n return null;\n }\n\n return null;\n}\n","import { cache } from \"react\";\nimport { listBlockChildrenDeep, type NotionBlockClient } from \"./blocks\";\nimport { createNotionClient } from \"./client\";\nimport { getNotionConfigForModel, hasNotionModelConfig } from \"./config\";\nimport { coverImageUrlForPage } from \"./media\";\nimport {\n getDateProperty,\n getRichTextProperty,\n getTagsProperty,\n isValidPublicSlug,\n notionPageEditUrl,\n pickDescriptionFallback,\n} from \"./property-mappers\";\nimport type {\n NotionBlock,\n NotionFieldMap,\n NotionGenericContentModel,\n NotionPageLike,\n} from \"./types\";\n\ntype PropertyMap = Record<string, unknown>;\n\ntype DataSourceQueryResponse = {\n results?: unknown[];\n has_more?: boolean;\n next_cursor?: string | null;\n};\n\ntype QueryDataSourceInput = {\n startCursor?: string;\n};\n\nexport type GenericContentListItem = {\n pageId: string;\n slug: string;\n title: string;\n description: string;\n date: string;\n tags: string[];\n coverImage: string | null;\n published: boolean;\n editUrl: string | null;\n properties: Record<string, string | string[]>;\n};\n\nexport type GenericContentDetail = GenericContentListItem & {\n blocks: NotionBlock[];\n};\n\nexport type GenericContentSourceDeps<\n TFields extends NotionFieldMap = NotionFieldMap,\n> = {\n model: NotionGenericContentModel & { source: { fields: TFields } };\n dataSourceId: string;\n queryDataSource: (\n input?: QueryDataSourceInput\n ) => Promise<DataSourceQueryResponse>;\n getPageBlocks: (pageId: string) => Promise<NotionBlock[]>;\n editBaseUrl?: string;\n};\n\nfunction normalizePage(input: unknown): NotionPageLike | null {\n if (!input || typeof input !== \"object\") return null;\n const page = input as NotionPageLike;\n return page.id ? page : null;\n}\n\nfunction firstFieldName(value: string | readonly string[] | undefined) {\n if (Array.isArray(value)) return value[0];\n return value;\n}\n\nfunction getFieldName(fields: NotionFieldMap, key: string) {\n return firstFieldName(fields[key]);\n}\n\nfunction pickPublishedFlagForModel(\n properties: PropertyMap,\n fields: NotionFieldMap\n) {\n const publishedField = getFieldName(fields, \"published\") ?? \"Published\";\n const published = properties[publishedField] as\n | Record<string, unknown>\n | undefined;\n if (published?.type === \"checkbox\") return Boolean(published.checkbox);\n\n const statusField = getFieldName(fields, \"status\") ?? \"Status\";\n const status = properties[statusField] as Record<string, unknown> | undefined;\n if (status?.type === \"status\") {\n const value = status.status as { name?: string } | null | undefined;\n return String(value?.name ?? \"\").trim().toLowerCase() === \"published\";\n }\n if (status?.type === \"select\") {\n const value = status.select as { name?: string } | null | undefined;\n return String(value?.name ?? \"\").trim().toLowerCase() === \"published\";\n }\n\n return true;\n}\n\nfunction coverImageUrlForModel(page: NotionPageLike, fields: NotionFieldMap) {\n const coverField = fields.cover;\n if (Array.isArray(coverField)) {\n for (const field of coverField) {\n const imageUrl = coverImageUrlForPage(page, field);\n if (imageUrl) return imageUrl;\n }\n }\n if (typeof coverField === \"string\") {\n return coverImageUrlForPage(page, coverField);\n }\n return coverImageUrlForPage(page);\n}\n\nfunction mapExtraProperties(properties: PropertyMap, fields: NotionFieldMap) {\n const result: Record<string, string | string[]> = {};\n for (const [key, value] of Object.entries(fields)) {\n const field = firstFieldName(value);\n if (!field) continue;\n const tags = getTagsProperty(properties, field);\n result[key] = tags.length > 0 ? tags : getRichTextProperty(properties, field);\n }\n return result;\n}\n\nexport function mapNotionPageToGenericContentItem<\n TFields extends NotionFieldMap,\n>(\n model: { id: string; source: { fields: TFields } },\n page: NotionPageLike,\n options?: { editBaseUrl?: string }\n): GenericContentListItem {\n const fields = model.source.fields;\n const properties = isRecord(page.properties) ? page.properties : {};\n const titleField = getFieldName(fields, \"title\");\n const slugField = getFieldName(fields, \"slug\");\n const descriptionField = getFieldName(fields, \"description\");\n const dateField = getFieldName(fields, \"date\");\n const tagsField = getFieldName(fields, \"tags\");\n\n const title = titleField ? getRichTextProperty(properties, titleField) : \"\";\n const slug = slugField\n ? getRichTextProperty(properties, slugField).toLowerCase()\n : page.id.replaceAll(\"-\", \"\").toLowerCase();\n const description = pickDescriptionFallback(\n descriptionField ? getRichTextProperty(properties, descriptionField) : \"\",\n title\n );\n\n return {\n pageId: page.id,\n slug,\n title,\n description,\n date: dateField ? getDateProperty(properties, dateField) : \"\",\n tags: tagsField ? getTagsProperty(properties, tagsField) : [],\n coverImage: coverImageUrlForModel(page, fields),\n published: pickPublishedFlagForModel(properties, fields),\n editUrl: notionPageEditUrl(page.id, options?.editBaseUrl),\n properties: mapExtraProperties(properties, fields),\n };\n}\n\nexport function isRenderableGenericContentItem(item: GenericContentListItem) {\n return Boolean(item.published && item.title && item.slug && isValidPublicSlug(item.slug));\n}\n\nexport function createGenericNotionContentSource<\n TFields extends NotionFieldMap,\n>(deps: GenericContentSourceDeps<TFields>) {\n return {\n async listItems(): Promise<GenericContentListItem[]> {\n const pages: NotionPageLike[] = [];\n let cursor: string | undefined;\n\n do {\n const response = await deps.queryDataSource({ startCursor: cursor });\n for (const item of response.results ?? []) {\n const page = normalizePage(item);\n if (page) pages.push(page);\n }\n\n cursor = response.next_cursor ?? undefined;\n if (!response.has_more) break;\n } while (cursor);\n\n return pages\n .map((page) =>\n mapNotionPageToGenericContentItem(deps.model, page, {\n editBaseUrl: deps.editBaseUrl,\n })\n )\n .filter(isRenderableGenericContentItem)\n .sort((a, b) => b.date.localeCompare(a.date));\n },\n\n async getItemBySlug(slug: string): Promise<GenericContentDetail | null> {\n const items = await this.listItems();\n const item = items.find((candidate) => candidate.slug === slug);\n if (!item) return null;\n return {\n ...item,\n blocks: await deps.getPageBlocks(item.pageId),\n };\n },\n };\n}\n\nasync function createDefaultGenericSource<\n TFields extends NotionFieldMap,\n>(model: NotionGenericContentModel & { source: { fields: TFields } }) {\n if (!(await hasNotionModelConfig(model))) return null;\n\n const config = await getNotionConfigForModel(model);\n const client = createNotionClient(config);\n return createGenericNotionContentSource({\n model,\n dataSourceId: config.dataSourceId,\n editBaseUrl: config.editBaseUrl,\n queryDataSource: async ({ startCursor } = {}) =>\n client.dataSources.query({\n data_source_id: config.dataSourceId,\n page_size: model.source.query.pageSize,\n sorts: model.source.query.sorts\n ? [...model.source.query.sorts]\n : undefined,\n filter_properties: model.source.query.filterProperties\n ? [...model.source.query.filterProperties]\n : undefined,\n ...(startCursor ? { start_cursor: startCursor } : {}),\n }),\n getPageBlocks: (pageId) =>\n listBlockChildrenDeep(client as unknown as NotionBlockClient, pageId),\n });\n}\n\nconst sourceCache = cache(createDefaultGenericSource);\n\nexport async function listGenericNotionContent<\n TFields extends NotionFieldMap,\n>(model: NotionGenericContentModel & { source: { fields: TFields } }) {\n const source = await sourceCache(model);\n if (!source) return [];\n return source.listItems();\n}\n\nexport async function getGenericNotionContentBySlug<\n TFields extends NotionFieldMap,\n>(model: NotionGenericContentModel & { source: { fields: TFields } }, slug: string) {\n const source = await sourceCache(model);\n if (!source) return null;\n return source.getItemBySlug(slug);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\");\n}\n","type PropertyMap = Record<string, unknown>;\n\ntype TextPart = {\n plain_text?: string;\n};\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\");\n}\n\nfunction getPlainText(parts: unknown): string {\n if (!Array.isArray(parts)) return \"\";\n return parts\n .map((part: TextPart) => part.plain_text ?? \"\")\n .join(\"\")\n .trim();\n}\n\nfunction getProperty(properties: PropertyMap, key: string) {\n return properties[key] as Record<string, unknown> | undefined;\n}\n\nfunction firstPropertyOfType(properties: PropertyMap, type: string) {\n return Object.values(properties).find(\n (property): property is Record<string, unknown> =>\n isRecord(property) && property.type === type\n );\n}\n\nexport function getFirstTitleProperty(properties: PropertyMap): string {\n const property = firstPropertyOfType(properties, \"title\");\n return property ? getPlainText(property.title) : \"\";\n}\n\nexport function getRichTextProperty(properties: PropertyMap, key: string): string {\n const property = getProperty(properties, key);\n if (!property) return \"\";\n\n if (property.type === \"title\") return getPlainText(property.title);\n if (property.type === \"rich_text\") return getPlainText(property.rich_text);\n if (property.type === \"url\") return String(property.url ?? \"\").trim();\n if (property.type === \"email\") return String(property.email ?? \"\").trim();\n if (property.type === \"phone_number\") {\n return String(property.phone_number ?? \"\").trim();\n }\n\n return \"\";\n}\n\nexport function getDateProperty(properties: PropertyMap, key: string): string {\n const property = getProperty(properties, key);\n if (property?.type !== \"date\") return \"\";\n const date = property.date as { start?: string } | null | undefined;\n return String(date?.start ?? \"\").trim();\n}\n\nexport function getFirstDateProperty(properties: PropertyMap): string {\n const property = firstPropertyOfType(properties, \"date\");\n if (!property) return \"\";\n const date = property.date as { start?: string } | null | undefined;\n return String(date?.start ?? \"\").trim();\n}\n\nexport function getSelectProperty(properties: PropertyMap, key: string): string {\n const property = getProperty(properties, key);\n if (property?.type !== \"select\") return \"\";\n const select = property.select as { name?: string } | null | undefined;\n return String(select?.name ?? \"\").trim();\n}\n\nexport function getCheckboxProperty(properties: PropertyMap, key: string): boolean {\n const property = getProperty(properties, key);\n if (property?.type !== \"checkbox\") return false;\n return Boolean(property.checkbox);\n}\n\nexport function getNumberProperty(\n properties: PropertyMap,\n key: string,\n fallback = 0\n): number {\n const property = getProperty(properties, key);\n if (property?.type !== \"number\") return fallback;\n const value = Number(property.number);\n return Number.isFinite(value) ? value : fallback;\n}\n\nexport function getRelationPageIds(properties: PropertyMap, key: string): string[] {\n const property = getProperty(properties, key);\n if (property?.type !== \"relation\" || !Array.isArray(property.relation)) {\n return [];\n }\n\n return property.relation\n .map((item: { id?: string }) => String(item.id ?? \"\").trim())\n .filter(Boolean);\n}\n\nexport function getTagsProperty(properties: PropertyMap, key: string): string[] {\n const property = getProperty(properties, key);\n if (property?.type === \"multi_select\" && Array.isArray(property.multi_select)) {\n return property.multi_select\n .map((item: { name?: string }) => String(item.name ?? \"\").trim())\n .filter(Boolean);\n }\n\n if (property?.type === \"select\") {\n const select = property.select as { name?: string } | null | undefined;\n const name = String(select?.name ?? \"\").trim();\n return name ? [name] : [];\n }\n\n return [];\n}\n\nexport function getFirstTagsProperty(properties: PropertyMap): string[] {\n const multiSelect = firstPropertyOfType(properties, \"multi_select\");\n if (multiSelect && Array.isArray(multiSelect.multi_select)) {\n return multiSelect.multi_select\n .map((item: { name?: string }) => String(item.name ?? \"\").trim())\n .filter(Boolean);\n }\n\n const select = firstPropertyOfType(properties, \"select\");\n const name = String((select?.select as { name?: string } | null)?.name ?? \"\").trim();\n return name ? [name] : [];\n}\n\nexport function getAuthorProperty(properties: PropertyMap, key: string): string {\n const property = getProperty(properties, key);\n if (!property) return \"\";\n\n if (property.type === \"people\" && Array.isArray(property.people)) {\n return property.people\n .map((person: { name?: string; person?: { email?: string } }) =>\n String(person.name ?? person.person?.email ?? \"\").trim()\n )\n .filter(Boolean)\n .join(\", \");\n }\n\n return getRichTextProperty(properties, key);\n}\n\nexport function getFirstPeopleProperty(properties: PropertyMap): string {\n const property = firstPropertyOfType(properties, \"people\");\n if (!property || !Array.isArray(property.people)) return \"\";\n\n return property.people\n .map((person: { name?: string; person?: { email?: string } }) =>\n String(person.name ?? person.person?.email ?? \"\").trim()\n )\n .filter(Boolean)\n .join(\", \");\n}\n\nexport function pickPublishedFlag(properties: PropertyMap): boolean {\n const published = getProperty(properties, \"Published\");\n if (published?.type === \"checkbox\") {\n return Boolean(published.checkbox);\n }\n\n const status = getProperty(properties, \"Status\");\n if (status?.type === \"status\") {\n const statusValue = status.status as { name?: string } | null | undefined;\n return String(statusValue?.name ?? \"\").trim().toLowerCase() === \"published\";\n }\n\n if (status?.type === \"select\") {\n const statusValue = status.select as { name?: string } | null | undefined;\n return String(statusValue?.name ?? \"\").trim().toLowerCase() === \"published\";\n }\n\n return false;\n}\n\nexport function pickDescriptionFallback(description: string, title: string): string {\n return description.trim() || title.trim();\n}\n\nexport function isValidPublicSlug(slug: string): boolean {\n return /^[a-z0-9][a-z0-9-]{0,79}$/.test(slug);\n}\n\nexport function notionPageEditUrl(pageId: string, editBaseUrl?: string): string {\n const compactPageId = pageId.replaceAll(\"-\", \"\");\n if (editBaseUrl?.includes(\"{pageId}\")) {\n return editBaseUrl.replaceAll(\"{pageId}\", compactPageId);\n }\n return `https://www.notion.so/${compactPageId}`;\n}\n\n/**\n * Normalize a Notion page id (with or without dashes) to a compact lowercase\n * string. Used as a stable identifier in URLs and cache keys.\n */\nexport function compactNotionId(id: string): string {\n return id.replaceAll(\"-\", \"\").toLowerCase();\n}\n","import type { KeyValueCacheAdapter } from \"../platform/runtime\";\nimport { createNotionClient } from \"./client\";\nimport { getNotionConfigForModel } from \"./config\";\nimport {\n compactNotionId,\n getRichTextProperty,\n getSelectProperty,\n isValidPublicSlug,\n} from \"./property-mappers\";\nimport type {\n NotionFieldMap,\n NotionGenericContentModel,\n NotionPageLike,\n} from \"./types\";\n\ntype JsonRecord = Record<string, unknown>;\n\ntype StoredWebhookVerificationToken = {\n token: string;\n updatedAt: string;\n};\n\nconst WEBHOOK_VERIFICATION_TOKEN_CACHE_KEY =\n \"notion:webhook:verification-token:v1\";\n\nexport type NotionWebhookParseResult =\n | { type: \"verification\"; verificationToken: string }\n | { type: \"events\"; events: NotionWebhookEvent[] };\n\nexport type NotionWebhookEvent = {\n id?: string;\n eventType: string;\n modelId: string;\n pageId?: string;\n dataSourceId?: string;\n routeId?: string;\n locale?: string;\n kind: \"publish\" | \"update\" | \"delete\";\n includeApi: boolean;\n reason: \"page\" | \"data_source\";\n};\n\n/**\n * Generic shape that callers (i.e. the starter) supply so the webhook can\n * route events to the correct content model. Each entry must expose the\n * Notion data source id that the model is bound to, and a hook to derive a\n * route id and locale from the Notion page payload.\n */\nexport type NotionWebhookModelRegistration<\n TFields extends NotionFieldMap = NotionFieldMap,\n> = NotionGenericContentModel & {\n source: { fields: TFields };\n resolveRouteId?: (page: JsonRecord) => string;\n resolveLocale?: (page: JsonRecord) => string;\n};\n\nexport type NotionPageRetriever = (\n pageId: string,\n model: NotionGenericContentModel\n) => Promise<NotionPageLike | null>;\n\nexport type NotionWebhookParseOptions<\n TFields extends NotionFieldMap = NotionFieldMap,\n> = {\n models: ReadonlyArray<NotionWebhookModelRegistration<TFields>>;\n /**\n * Optional override for resolving the data source id of a model. Defaults\n * to `process.env[model.source.dataSourceEnv] ?? model.source.defaultDataSourceId`.\n */\n getModelDataSourceId?: (model: NotionWebhookModelRegistration<TFields>) => string | null;\n};\n\nexport type InvalidationKind = \"publish\" | \"update\" | \"delete\";\n\n/**\n * Request shape consumed by the revalidation pipeline. Mirrors the starter's\n * `ContentRevalidateRequest`; duplicated here so the package does not need\n * a runtime dependency on the starter.\n */\nexport type NotionWebhookRevalidateRequest = {\n modelId: string;\n pageId?: string;\n routeId?: string;\n previousRouteId?: string;\n locale?: string;\n kind?: InvalidationKind;\n includeApi?: boolean;\n};\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return Boolean(value && typeof value === \"object\" && !Array.isArray(value));\n}\n\nfunction readString(source: unknown, key: string) {\n if (!isRecord(source)) return \"\";\n const value = source[key];\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction asRecords(value: unknown) {\n if (Array.isArray(value)) return value.filter(isRecord);\n if (isRecord(value)) return [value];\n return [];\n}\n\nfunction nestedRecords(source: JsonRecord, ...keys: string[]) {\n const records: JsonRecord[] = [];\n for (const key of keys) {\n const value = source[key];\n if (isRecord(value)) records.push(value);\n }\n return records;\n}\n\nfunction firstString(...values: string[]) {\n return values.find(Boolean) ?? \"\";\n}\n\nfunction normalizeId(value: string) {\n return value.replaceAll(\"-\", \"\").toLowerCase();\n}\n\nfunction findIdByType(input: JsonRecord, type: string): string {\n const stack = [input];\n const seen = new Set<JsonRecord>();\n\n while (stack.length > 0) {\n const current = stack.pop();\n if (!current || seen.has(current)) continue;\n seen.add(current);\n\n if (readString(current, \"type\") === type) {\n const id = readString(current, \"id\");\n if (id) return id;\n }\n\n for (const value of Object.values(current)) {\n if (isRecord(value)) stack.push(value);\n if (Array.isArray(value)) {\n for (const item of value) {\n if (isRecord(item)) stack.push(item);\n }\n }\n }\n }\n\n return \"\";\n}\n\nfunction findDataSourceId(input: JsonRecord): string {\n const stack = [input];\n const seen = new Set<JsonRecord>();\n\n while (stack.length > 0) {\n const current = stack.pop();\n if (!current || seen.has(current)) continue;\n seen.add(current);\n\n const direct = firstString(\n readString(current, \"data_source_id\"),\n readString(current, \"source_id\")\n );\n if (direct) return direct;\n\n const type = readString(current, \"type\");\n if (type === \"data_source\") {\n const id = readString(current, \"id\");\n if (id) return id;\n }\n\n for (const value of Object.values(current)) {\n if (isRecord(value)) stack.push(value);\n if (Array.isArray(value)) {\n for (const item of value) {\n if (isRecord(item)) stack.push(item);\n }\n }\n }\n }\n\n return \"\";\n}\n\nfunction firstFieldName(value: string | readonly string[] | undefined) {\n if (Array.isArray(value)) return value[0];\n return value;\n}\n\nfunction defaultRouteIdFromProperties(\n model: NotionGenericContentModel,\n page: JsonRecord\n) {\n const properties = isRecord(page.properties) ? page.properties : {};\n const slugField = firstFieldName(model.source.fields.slug);\n const slug = slugField\n ? getRichTextProperty(properties, slugField).toLowerCase()\n : \"\";\n return isValidPublicSlug(slug) ? slug : \"\";\n}\n\nfunction defaultLocaleFromProperties(model: NotionGenericContentModel, page: JsonRecord) {\n const properties = isRecord(page.properties) ? page.properties : {};\n const localeField = firstFieldName(model.source.fields.locale);\n return localeField ? getSelectProperty(properties, localeField) : \"\";\n}\n\nfunction eventKind(eventType: string): \"publish\" | \"update\" | \"delete\" {\n if (eventType.includes(\".deleted\")) return \"delete\";\n if (eventType.includes(\".created\") || eventType.includes(\".undeleted\")) {\n return \"publish\";\n }\n return \"update\";\n}\n\nfunction defaultGetModelDataSourceId(\n model: NotionGenericContentModel\n): string | null {\n const fromEnv = process.env[model.source.dataSourceEnv];\n if (fromEnv) return fromEnv;\n return model.source.defaultDataSourceId ?? null;\n}\n\nfunction matchModelByDataSourceId<\n TFields extends NotionFieldMap,\n>(\n models: ReadonlyArray<NotionWebhookModelRegistration<TFields>>,\n dataSourceId: string,\n getDataSourceId: (model: NotionWebhookModelRegistration<TFields>) => string | null\n) {\n if (!dataSourceId) return null;\n const normalized = normalizeId(dataSourceId);\n return (\n models.find((model) => {\n const configured = getDataSourceId(model);\n return configured ? normalizeId(configured) === normalized : false;\n }) ?? null\n );\n}\n\nfunction findModelForEvent<\n TFields extends NotionFieldMap,\n>(\n models: ReadonlyArray<NotionWebhookModelRegistration<TFields>>,\n event: JsonRecord,\n page: JsonRecord | undefined,\n getDataSourceId: (model: NotionWebhookModelRegistration<TFields>) => string | null\n) {\n const modelId = firstString(\n readString(event, \"modelId\"),\n readString(event, \"model_id\"),\n readString(event.data, \"modelId\"),\n readString(event.data, \"model_id\")\n );\n if (modelId) {\n return models.find((model) => model.id === modelId) ?? null;\n }\n\n const dataSourceId = firstString(\n findDataSourceId(event),\n findIdByType(event, \"data_source\"),\n readString(event, \"data_source_id\"),\n readString(event.data, \"data_source_id\"),\n readString(page?.parent, \"data_source_id\"),\n readString(page?.parent, \"database_id\")\n );\n return matchModelByDataSourceId(models, dataSourceId, getDataSourceId);\n}\n\nfunction pageIdForEvent(event: JsonRecord, page?: JsonRecord) {\n return firstString(\n readString(page, \"id\"),\n findIdByType(event, \"page\"),\n readString(event, \"page_id\"),\n readString(event.data, \"page_id\")\n );\n}\n\nfunction pageForEvent(event: JsonRecord) {\n let fallback: JsonRecord | null = null;\n for (const record of [\n ...nestedRecords(isRecord(event.data) ? event.data : {}, \"page\", \"entity\"),\n ...nestedRecords(event, \"page\", \"entity\"),\n event,\n ]) {\n const type = readString(record, \"type\");\n if (type === \"page\" || readString(record, \"object\") === \"page\") {\n if (!readString(record, \"id\")) continue;\n if (isRecord(record.properties) || isRecord(record.parent)) return record;\n fallback ??= record;\n }\n }\n return fallback;\n}\n\nexport function parseNotionWebhookPayload<\n TFields extends NotionFieldMap = NotionFieldMap,\n>(\n payload: unknown,\n options: NotionWebhookParseOptions<TFields>\n): NotionWebhookParseResult {\n if (!isRecord(payload)) return { type: \"events\", events: [] };\n\n const verificationToken = readString(payload, \"verification_token\");\n if (verificationToken) {\n return { type: \"verification\", verificationToken };\n }\n\n const getDataSourceId = options.getModelDataSourceId ?? defaultGetModelDataSourceId;\n\n const events = asRecords(payload.events ?? payload.event ?? payload)\n .map((event) =>\n parseEvent(event, options.models, getDataSourceId)\n )\n .filter((event): event is NotionWebhookEvent => Boolean(event));\n\n return { type: \"events\", events };\n}\n\nfunction parseEvent<\n TFields extends NotionFieldMap,\n>(\n event: JsonRecord,\n models: ReadonlyArray<NotionWebhookModelRegistration<TFields>>,\n getDataSourceId: (model: NotionWebhookModelRegistration<TFields>) => string | null\n): NotionWebhookEvent | null {\n const eventType = firstString(readString(event, \"type\"), readString(event, \"event\"));\n if (!eventType) return null;\n const page = pageForEvent(event);\n const model = findModelForEvent(\n models,\n event,\n page ?? undefined,\n getDataSourceId\n );\n if (!model) return null;\n\n const routeId = page\n ? (model.resolveRouteId?.(page) ??\n defaultRouteIdFromProperties(model, page))\n : \"\";\n const locale = page\n ? (model.resolveLocale?.(page) ?? defaultLocaleFromProperties(model, page))\n : \"\";\n const dataSourceId = firstString(\n findDataSourceId(event),\n findIdByType(event, \"data_source\"),\n readString(event, \"data_source_id\"),\n readString(event.data, \"data_source_id\"),\n readString(page?.parent, \"data_source_id\"),\n readString(page?.parent, \"database_id\")\n );\n const dataSourceEvent =\n eventType.startsWith(\"data_source.\") || eventType.startsWith(\"database.\");\n return {\n id: readString(event, \"id\") || undefined,\n eventType,\n modelId: model.id,\n pageId: pageIdForEvent(event, page ?? undefined) || undefined,\n dataSourceId: dataSourceId || undefined,\n routeId: routeId || undefined,\n locale: locale || undefined,\n kind: eventKind(eventType),\n includeApi: true,\n reason: page && routeId ? \"page\" : dataSourceEvent ? \"data_source\" : \"page\",\n };\n}\n\nasync function defaultRetrieveNotionPage(\n pageId: string,\n model: NotionGenericContentModel\n) {\n const config = await getNotionConfigForModel(model);\n const client = createNotionClient(config);\n const page = await client.pages.retrieve({ page_id: pageId });\n return page as NotionPageLike;\n}\n\nfunction resolveWebhookEventRoute<\n TFields extends NotionFieldMap,\n>(\n event: NotionWebhookEvent,\n models: ReadonlyArray<NotionWebhookModelRegistration<TFields>>,\n retrievePage: NotionPageRetriever\n): Promise<NotionWebhookEvent> {\n if (event.routeId || !event.pageId) return Promise.resolve(event);\n if (event.kind === \"delete\") return Promise.resolve(event);\n\n const model = models.find((m) => m.id === event.modelId);\n if (!model) return Promise.resolve(event);\n\n return retrievePage(event.pageId, model)\n .then((page) => {\n if (!page) return event;\n const pageRecord = page as unknown as JsonRecord;\n const routeId =\n model.resolveRouteId?.(pageRecord) ??\n defaultRouteIdFromProperties(model, pageRecord);\n const locale =\n model.resolveLocale?.(pageRecord) ??\n defaultLocaleFromProperties(model, pageRecord);\n if (!routeId) return event;\n return {\n ...event,\n routeId,\n locale: locale || event.locale,\n reason: \"page\" as const,\n };\n })\n .catch((error) => {\n const err = error as { code?: string; status?: number; message?: string };\n console.warn(\n JSON.stringify({\n tag: \"notion_webhook_page_lookup_failed\",\n eventId: event.id,\n eventType: event.eventType,\n modelId: event.modelId,\n pageId: event.pageId,\n code: err?.code,\n status: err?.status,\n message: err?.message ?? String(error),\n })\n );\n return event;\n });\n}\n\nexport async function parseNotionWebhookPayloadWithPageLookup<\n TFields extends NotionFieldMap = NotionFieldMap,\n>(\n payload: unknown,\n options: NotionWebhookParseOptions<TFields> & {\n retrievePage?: NotionPageRetriever;\n lookupPages?: boolean;\n }\n): Promise<NotionWebhookParseResult> {\n const parsed = parseNotionWebhookPayload(payload, options);\n if (parsed.type === \"verification\") return parsed;\n if (options?.lookupPages === false) return parsed;\n\n const retrievePage = options?.retrievePage ?? defaultRetrieveNotionPage;\n return {\n type: \"events\",\n events: await Promise.all(\n parsed.events.map((event) =>\n resolveWebhookEventRoute(event, options.models, retrievePage)\n )\n ),\n };\n}\n\nexport function notionWebhookEventToRevalidateRequest(\n event: NotionWebhookEvent\n): NotionWebhookRevalidateRequest {\n return {\n modelId: event.modelId,\n pageId: event.pageId,\n routeId: event.routeId,\n locale: event.locale,\n kind: event.kind,\n includeApi: event.includeApi,\n };\n}\n\nexport async function signNotionWebhookBody(body: string, verificationToken: string) {\n const key = await crypto.subtle.importKey(\n \"raw\",\n new TextEncoder().encode(verificationToken),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n );\n const signature = await crypto.subtle.sign(\n \"HMAC\",\n key,\n new TextEncoder().encode(body)\n );\n return Array.from(new Uint8Array(signature))\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nfunction normalizeNotionSignature(signature: string | null) {\n const value = String(signature ?? \"\").trim();\n const prefixed = value.match(/^sha256=(.+)$/i);\n return prefixed && prefixed[1] ? prefixed[1].trim() : value;\n}\n\nexport async function verifyNotionWebhookSignature(input: {\n body: string;\n signature: string | null;\n verificationToken?: string | null;\n}) {\n const token = String(input.verificationToken ?? \"\").trim();\n const signature = normalizeNotionSignature(input.signature);\n if (!token || !signature) return false;\n const expected = await signNotionWebhookBody(input.body, token);\n if (expected.length !== signature.length) return false;\n\n let diff = 0;\n for (let index = 0; index < expected.length; index += 1) {\n diff |= expected.charCodeAt(index) ^ signature.charCodeAt(index);\n }\n return diff === 0;\n}\n\nexport async function verifyNotionWebhookSignatureWithTokens(input: {\n body: string;\n signature: string | null;\n verificationTokens: Array<string | null | undefined>;\n}) {\n const tokens = Array.from(\n new Set(input.verificationTokens.map((token) => String(token ?? \"\").trim()))\n ).filter(Boolean);\n\n for (const token of tokens) {\n if (\n await verifyNotionWebhookSignature({\n body: input.body,\n signature: input.signature,\n verificationToken: token,\n })\n ) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction readStoredWebhookVerificationToken(value: unknown) {\n if (typeof value === \"string\") return value.trim() || null;\n if (!isRecord(value)) return null;\n\n const token = readString(value, \"token\");\n return token || null;\n}\n\nexport async function getStoredNotionWebhookVerificationToken(\n cache: KeyValueCacheAdapter | null | undefined\n) {\n if (!cache) return null;\n\n try {\n const value = await cache.get<StoredWebhookVerificationToken | string>(\n WEBHOOK_VERIFICATION_TOKEN_CACHE_KEY,\n { cacheTtl: 60 }\n );\n return readStoredWebhookVerificationToken(value);\n } catch (error) {\n console.warn(\n JSON.stringify({\n tag: \"notion_webhook_token_lookup_failed\",\n message: error instanceof Error ? error.message : String(error),\n })\n );\n return null;\n }\n}\n\nexport async function putStoredNotionWebhookVerificationToken(\n cache: KeyValueCacheAdapter | null | undefined,\n token: string\n) {\n const normalized = token.trim();\n if (!cache || !normalized) return false;\n\n await cache.put<StoredWebhookVerificationToken>(\n WEBHOOK_VERIFICATION_TOKEN_CACHE_KEY,\n {\n token: normalized,\n updatedAt: new Date().toISOString(),\n },\n {\n metadata: {\n source: \"notion-webhook\",\n },\n }\n );\n return true;\n}\n\n// Re-exported for backwards compatibility with the starter.\nexport { compactNotionId };\n"],"mappings":"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","names":["cache","isRecord","isRecord","readString","firstFieldName","cache"]}
|
package/dist/notion/media.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ declare function mediaUrlForBlock(block: NotionBlock): string | null;
|
|
|
14
14
|
declare function firstImageUrlFromBlocks(blocks: NotionBlock[]): string | null;
|
|
15
15
|
declare function publicMediaBlockForApi(block: NotionBlock): NotionBlock;
|
|
16
16
|
declare function gatedMediaBlockForApi(block: NotionBlock, options?: {
|
|
17
|
-
|
|
17
|
+
accessUrlForBlock?: (block: NotionBlock) => string | null;
|
|
18
18
|
}): NotionBlock;
|
|
19
19
|
declare function isDirectVideoUrl(url: string): boolean;
|
|
20
20
|
declare function videoEmbedUrl(url: string): string | null;
|
package/dist/notion/media.js
CHANGED
|
@@ -137,7 +137,7 @@ function gatedMediaBlockForApi(block, options) {
|
|
|
137
137
|
const gatedValue = {
|
|
138
138
|
...value,
|
|
139
139
|
gated: true,
|
|
140
|
-
access_url: options?.
|
|
140
|
+
access_url: options?.accessUrlForBlock?.(block) ?? null
|
|
141
141
|
};
|
|
142
142
|
if (source.type === "external") {
|
|
143
143
|
gatedValue.external = { url: null };
|
package/dist/notion/media.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/notion/media.ts"],"sourcesContent":["import type { NotionBlock, NotionFileSource, NotionPageLike } from \"./types\";\n\ntype FileLike = {\n type?: string;\n external?: { url?: string };\n file?: { url?: string; expiry_time?: string };\n name?: string;\n};\n\nfunction stripLeadingSlash(value: string) {\n return value.startsWith(\"/\") ? value.slice(1) : value;\n}\n\nfunction encodePathPart(value: string) {\n return encodeURIComponent(stripLeadingSlash(value));\n}\n\nfunction appendVersion(path: string, version?: string) {\n const value = String(version ?? \"\").trim();\n if (!value) return path;\n return `${path}?${new URLSearchParams({ v: value })}`;\n}\n\nfunction blockVersion(block: NotionBlock): string | undefined {\n return typeof block.last_edited_time === \"string\"\n ? block.last_edited_time\n : undefined;\n}\n\nexport function notionPageCoverMediaPath(pageId: string): string {\n return `/api/notion/media/page/${encodePathPart(pageId)}/cover`;\n}\n\nexport function notionPagePropertyMediaPath(\n pageId: string,\n propertyName: string\n): string {\n return `/api/notion/media/page/${encodePathPart(pageId)}/property/${encodePathPart(propertyName)}`;\n}\n\nexport function notionBlockMediaPath(blockId: string): string {\n return `/api/notion/media/block/${encodePathPart(blockId)}`;\n}\n\nexport function normalizeNotionFileSource(input: unknown): NotionFileSource | null {\n const file = input as FileLike | null | undefined;\n if (!file || typeof file !== \"object\") return null;\n\n if (file.type === \"external\") {\n const url = String(file.external?.url ?? \"\").trim();\n return url ? { type: \"external\", url } : null;\n }\n\n if (file.type === \"file\") {\n const url = String(file.file?.url ?? \"\").trim();\n if (!url) return null;\n return {\n type: \"file\",\n url,\n expiryTime: String(file.file?.expiry_time ?? \"\").trim() || null,\n };\n }\n\n return null;\n}\n\nexport function resolveNotionFileUrl(input: unknown): string | null {\n return normalizeNotionFileSource(input)?.url ?? null;\n}\n\nexport function isNotionHostedFile(input: unknown): boolean {\n return normalizeNotionFileSource(input)?.type === \"file\";\n}\n\nexport function pickFirstFilesPropertyValue(property: unknown): unknown | null {\n const value = property as { type?: string; files?: unknown[] } | null | undefined;\n if (!value || value.type !== \"files\" || !Array.isArray(value.files)) {\n return null;\n }\n return value.files[0] ?? null;\n}\n\nexport function pickPageCoverFile(page: NotionPageLike): unknown | null {\n return page.cover ?? null;\n}\n\nexport function coverImageUrlForPage(\n page: NotionPageLike,\n coverPropertyName = \"Cover\"\n): string | null {\n const propertyFile = pickFirstFilesPropertyValue(\n page.properties?.[coverPropertyName]\n );\n const propertySource = normalizeNotionFileSource(propertyFile);\n if (propertySource) {\n return appendVersion(\n notionPagePropertyMediaPath(page.id, coverPropertyName),\n page.last_edited_time\n );\n }\n\n const coverSource = normalizeNotionFileSource(pickPageCoverFile(page));\n if (coverSource) {\n return appendVersion(notionPageCoverMediaPath(page.id), page.last_edited_time);\n }\n\n return null;\n}\n\nexport function fileObjectForMediaBlock(block: NotionBlock): unknown | null {\n const typed = block[block.type] as Record<string, unknown> | undefined;\n if (!typed || typeof typed !== \"object\") return null;\n\n if (\n block.type === \"image\" ||\n block.type === \"video\" ||\n block.type === \"file\" ||\n block.type === \"pdf\" ||\n block.type === \"audio\"\n ) {\n return typed;\n }\n\n return null;\n}\n\nexport function mediaUrlForBlock(block: NotionBlock): string | null {\n const source = normalizeNotionFileSource(fileObjectForMediaBlock(block));\n if (!source) return null;\n if (source.type === \"external\" && block.type !== \"image\") {\n return source.url;\n }\n return appendVersion(notionBlockMediaPath(block.id), blockVersion(block));\n}\n\nexport function firstImageUrlFromBlocks(blocks: NotionBlock[]): string | null {\n for (const block of blocks) {\n if (block.type === \"image\") {\n const imageUrl = mediaUrlForBlock(block);\n if (imageUrl) return imageUrl;\n }\n\n const nested = block.children?.length\n ? firstImageUrlFromBlocks(block.children)\n : null;\n if (nested) return nested;\n }\n\n return null;\n}\n\nexport function publicMediaBlockForApi(block: NotionBlock): NotionBlock {\n const value = block[block.type];\n const source = normalizeNotionFileSource(value);\n const children = block.children?.map(publicMediaBlockForApi);\n\n if (!source) {\n return children ? { ...block, children } : { ...block };\n }\n\n const path = appendVersion(notionBlockMediaPath(block.id), blockVersion(block));\n const publicValue =\n source.type === \"external\"\n ? block.type === \"image\"\n ? {\n ...(value as Record<string, unknown>),\n external: { url: path },\n }\n : value\n : {\n ...(value as Record<string, unknown>),\n file: {\n url: path,\n expiry_time: null,\n },\n };\n\n return {\n ...block,\n [block.type]: publicValue,\n ...(children ? { children } : {}),\n };\n}\n\nexport function gatedMediaBlockForApi(\n block: NotionBlock,\n options?: { movieId?: string }\n): NotionBlock {\n const value = block[block.type];\n const source = normalizeNotionFileSource(value);\n const children = block.children?.map((child) =>\n gatedMediaBlockForApi(child, options)\n );\n\n if (block.type !== \"video\" || !source) {\n const publicBlock = publicMediaBlockForApi(block);\n return children ? { ...publicBlock, children } : publicBlock;\n }\n\n const gatedValue: Record<string, unknown> = {\n ...(value as Record<string, unknown>),\n gated: true,\n access_url: options?.movieId\n ? `/api/movies/${encodePathPart(options.movieId)}/video/${encodePathPart(block.id)}`\n : null,\n };\n\n if (source.type === \"external\") {\n gatedValue.external = { url: null };\n } else {\n gatedValue.file = {\n url: null,\n expiry_time: null,\n };\n }\n\n return {\n ...block,\n video: gatedValue,\n ...(children ? { children } : {}),\n };\n}\n\nexport function isDirectVideoUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return /\\.(mp4|webm|mov|m4v)(?:$|\\?)/i.test(parsed.pathname);\n } catch {\n return false;\n }\n}\n\nexport function videoEmbedUrl(url: string): string | null {\n try {\n const parsed = new URL(url);\n const host = parsed.hostname.replace(/^www\\./, \"\");\n\n if (host === \"youtube.com\" || host === \"m.youtube.com\") {\n const id = parsed.searchParams.get(\"v\");\n return id ? `https://www.youtube.com/embed/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"youtu.be\") {\n const id = parsed.pathname.split(\"/\").filter(Boolean)[0];\n return id ? `https://www.youtube.com/embed/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"youtube-nocookie.com\") {\n return parsed.toString();\n }\n\n if (host === \"vimeo.com\") {\n const id = parsed.pathname.split(\"/\").filter(Boolean)[0];\n return id ? `https://player.vimeo.com/video/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"player.vimeo.com\") {\n return parsed.toString();\n }\n } catch {\n return null;\n }\n\n return null;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/notion/media.ts"],"sourcesContent":["import type { NotionBlock, NotionFileSource, NotionPageLike } from \"./types\";\n\ntype FileLike = {\n type?: string;\n external?: { url?: string };\n file?: { url?: string; expiry_time?: string };\n name?: string;\n};\n\nfunction stripLeadingSlash(value: string) {\n return value.startsWith(\"/\") ? value.slice(1) : value;\n}\n\nfunction encodePathPart(value: string) {\n return encodeURIComponent(stripLeadingSlash(value));\n}\n\nfunction appendVersion(path: string, version?: string) {\n const value = String(version ?? \"\").trim();\n if (!value) return path;\n return `${path}?${new URLSearchParams({ v: value })}`;\n}\n\nfunction blockVersion(block: NotionBlock): string | undefined {\n return typeof block.last_edited_time === \"string\"\n ? block.last_edited_time\n : undefined;\n}\n\nexport function notionPageCoverMediaPath(pageId: string): string {\n return `/api/notion/media/page/${encodePathPart(pageId)}/cover`;\n}\n\nexport function notionPagePropertyMediaPath(\n pageId: string,\n propertyName: string\n): string {\n return `/api/notion/media/page/${encodePathPart(pageId)}/property/${encodePathPart(propertyName)}`;\n}\n\nexport function notionBlockMediaPath(blockId: string): string {\n return `/api/notion/media/block/${encodePathPart(blockId)}`;\n}\n\nexport function normalizeNotionFileSource(input: unknown): NotionFileSource | null {\n const file = input as FileLike | null | undefined;\n if (!file || typeof file !== \"object\") return null;\n\n if (file.type === \"external\") {\n const url = String(file.external?.url ?? \"\").trim();\n return url ? { type: \"external\", url } : null;\n }\n\n if (file.type === \"file\") {\n const url = String(file.file?.url ?? \"\").trim();\n if (!url) return null;\n return {\n type: \"file\",\n url,\n expiryTime: String(file.file?.expiry_time ?? \"\").trim() || null,\n };\n }\n\n return null;\n}\n\nexport function resolveNotionFileUrl(input: unknown): string | null {\n return normalizeNotionFileSource(input)?.url ?? null;\n}\n\nexport function isNotionHostedFile(input: unknown): boolean {\n return normalizeNotionFileSource(input)?.type === \"file\";\n}\n\nexport function pickFirstFilesPropertyValue(property: unknown): unknown | null {\n const value = property as { type?: string; files?: unknown[] } | null | undefined;\n if (!value || value.type !== \"files\" || !Array.isArray(value.files)) {\n return null;\n }\n return value.files[0] ?? null;\n}\n\nexport function pickPageCoverFile(page: NotionPageLike): unknown | null {\n return page.cover ?? null;\n}\n\nexport function coverImageUrlForPage(\n page: NotionPageLike,\n coverPropertyName = \"Cover\"\n): string | null {\n const propertyFile = pickFirstFilesPropertyValue(\n page.properties?.[coverPropertyName]\n );\n const propertySource = normalizeNotionFileSource(propertyFile);\n if (propertySource) {\n return appendVersion(\n notionPagePropertyMediaPath(page.id, coverPropertyName),\n page.last_edited_time\n );\n }\n\n const coverSource = normalizeNotionFileSource(pickPageCoverFile(page));\n if (coverSource) {\n return appendVersion(notionPageCoverMediaPath(page.id), page.last_edited_time);\n }\n\n return null;\n}\n\nexport function fileObjectForMediaBlock(block: NotionBlock): unknown | null {\n const typed = block[block.type] as Record<string, unknown> | undefined;\n if (!typed || typeof typed !== \"object\") return null;\n\n if (\n block.type === \"image\" ||\n block.type === \"video\" ||\n block.type === \"file\" ||\n block.type === \"pdf\" ||\n block.type === \"audio\"\n ) {\n return typed;\n }\n\n return null;\n}\n\nexport function mediaUrlForBlock(block: NotionBlock): string | null {\n const source = normalizeNotionFileSource(fileObjectForMediaBlock(block));\n if (!source) return null;\n if (source.type === \"external\" && block.type !== \"image\") {\n return source.url;\n }\n return appendVersion(notionBlockMediaPath(block.id), blockVersion(block));\n}\n\nexport function firstImageUrlFromBlocks(blocks: NotionBlock[]): string | null {\n for (const block of blocks) {\n if (block.type === \"image\") {\n const imageUrl = mediaUrlForBlock(block);\n if (imageUrl) return imageUrl;\n }\n\n const nested = block.children?.length\n ? firstImageUrlFromBlocks(block.children)\n : null;\n if (nested) return nested;\n }\n\n return null;\n}\n\nexport function publicMediaBlockForApi(block: NotionBlock): NotionBlock {\n const value = block[block.type];\n const source = normalizeNotionFileSource(value);\n const children = block.children?.map(publicMediaBlockForApi);\n\n if (!source) {\n return children ? { ...block, children } : { ...block };\n }\n\n const path = appendVersion(notionBlockMediaPath(block.id), blockVersion(block));\n const publicValue =\n source.type === \"external\"\n ? block.type === \"image\"\n ? {\n ...(value as Record<string, unknown>),\n external: { url: path },\n }\n : value\n : {\n ...(value as Record<string, unknown>),\n file: {\n url: path,\n expiry_time: null,\n },\n };\n\n return {\n ...block,\n [block.type]: publicValue,\n ...(children ? { children } : {}),\n };\n}\n\nexport function gatedMediaBlockForApi(\n block: NotionBlock,\n options?: { accessUrlForBlock?: (block: NotionBlock) => string | null }\n): NotionBlock {\n const value = block[block.type];\n const source = normalizeNotionFileSource(value);\n const children = block.children?.map((child) =>\n gatedMediaBlockForApi(child, options)\n );\n\n if (block.type !== \"video\" || !source) {\n const publicBlock = publicMediaBlockForApi(block);\n return children ? { ...publicBlock, children } : publicBlock;\n }\n\n const gatedValue: Record<string, unknown> = {\n ...(value as Record<string, unknown>),\n gated: true,\n access_url: options?.accessUrlForBlock?.(block) ?? null,\n };\n\n if (source.type === \"external\") {\n gatedValue.external = { url: null };\n } else {\n gatedValue.file = {\n url: null,\n expiry_time: null,\n };\n }\n\n return {\n ...block,\n video: gatedValue,\n ...(children ? { children } : {}),\n };\n}\n\nexport function isDirectVideoUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return /\\.(mp4|webm|mov|m4v)(?:$|\\?)/i.test(parsed.pathname);\n } catch {\n return false;\n }\n}\n\nexport function videoEmbedUrl(url: string): string | null {\n try {\n const parsed = new URL(url);\n const host = parsed.hostname.replace(/^www\\./, \"\");\n\n if (host === \"youtube.com\" || host === \"m.youtube.com\") {\n const id = parsed.searchParams.get(\"v\");\n return id ? `https://www.youtube.com/embed/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"youtu.be\") {\n const id = parsed.pathname.split(\"/\").filter(Boolean)[0];\n return id ? `https://www.youtube.com/embed/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"youtube-nocookie.com\") {\n return parsed.toString();\n }\n\n if (host === \"vimeo.com\") {\n const id = parsed.pathname.split(\"/\").filter(Boolean)[0];\n return id ? `https://player.vimeo.com/video/${encodeURIComponent(id)}` : null;\n }\n\n if (host === \"player.vimeo.com\") {\n return parsed.toString();\n }\n } catch {\n return null;\n }\n\n return null;\n}\n"],"mappings":";AASA,SAAS,kBAAkB,OAAe;AACxC,SAAO,MAAM,WAAW,GAAG,IAAI,MAAM,MAAM,CAAC,IAAI;AAClD;AAEA,SAAS,eAAe,OAAe;AACrC,SAAO,mBAAmB,kBAAkB,KAAK,CAAC;AACpD;AAEA,SAAS,cAAc,MAAc,SAAkB;AACrD,QAAM,QAAQ,OAAO,WAAW,EAAE,EAAE,KAAK;AACzC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,GAAG,IAAI,IAAI,IAAI,gBAAgB,EAAE,GAAG,MAAM,CAAC,CAAC;AACrD;AAEA,SAAS,aAAa,OAAwC;AAC5D,SAAO,OAAO,MAAM,qBAAqB,WACrC,MAAM,mBACN;AACN;AAEO,SAAS,yBAAyB,QAAwB;AAC/D,SAAO,0BAA0B,eAAe,MAAM,CAAC;AACzD;AAEO,SAAS,4BACd,QACA,cACQ;AACR,SAAO,0BAA0B,eAAe,MAAM,CAAC,aAAa,eAAe,YAAY,CAAC;AAClG;AAEO,SAAS,qBAAqB,SAAyB;AAC5D,SAAO,2BAA2B,eAAe,OAAO,CAAC;AAC3D;AAEO,SAAS,0BAA0B,OAAyC;AACjF,QAAM,OAAO;AACb,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAE9C,MAAI,KAAK,SAAS,YAAY;AAC5B,UAAM,MAAM,OAAO,KAAK,UAAU,OAAO,EAAE,EAAE,KAAK;AAClD,WAAO,MAAM,EAAE,MAAM,YAAY,IAAI,IAAI;AAAA,EAC3C;AAEA,MAAI,KAAK,SAAS,QAAQ;AACxB,UAAM,MAAM,OAAO,KAAK,MAAM,OAAO,EAAE,EAAE,KAAK;AAC9C,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,YAAY,OAAO,KAAK,MAAM,eAAe,EAAE,EAAE,KAAK,KAAK;AAAA,IAC7D;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,qBAAqB,OAA+B;AAClE,SAAO,0BAA0B,KAAK,GAAG,OAAO;AAClD;AAEO,SAAS,mBAAmB,OAAyB;AAC1D,SAAO,0BAA0B,KAAK,GAAG,SAAS;AACpD;AAEO,SAAS,4BAA4B,UAAmC;AAC7E,QAAM,QAAQ;AACd,MAAI,CAAC,SAAS,MAAM,SAAS,WAAW,CAAC,MAAM,QAAQ,MAAM,KAAK,GAAG;AACnE,WAAO;AAAA,EACT;AACA,SAAO,MAAM,MAAM,CAAC,KAAK;AAC3B;AAEO,SAAS,kBAAkB,MAAsC;AACtE,SAAO,KAAK,SAAS;AACvB;AAEO,SAAS,qBACd,MACA,oBAAoB,SACL;AACf,QAAM,eAAe;AAAA,IACnB,KAAK,aAAa,iBAAiB;AAAA,EACrC;AACA,QAAM,iBAAiB,0BAA0B,YAAY;AAC7D,MAAI,gBAAgB;AAClB,WAAO;AAAA,MACL,4BAA4B,KAAK,IAAI,iBAAiB;AAAA,MACtD,KAAK;AAAA,IACP;AAAA,EACF;AAEA,QAAM,cAAc,0BAA0B,kBAAkB,IAAI,CAAC;AACrE,MAAI,aAAa;AACf,WAAO,cAAc,yBAAyB,KAAK,EAAE,GAAG,KAAK,gBAAgB;AAAA,EAC/E;AAEA,SAAO;AACT;AAEO,SAAS,wBAAwB,OAAoC;AAC1E,QAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAEhD,MACE,MAAM,SAAS,WACf,MAAM,SAAS,WACf,MAAM,SAAS,UACf,MAAM,SAAS,SACf,MAAM,SAAS,SACf;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,iBAAiB,OAAmC;AAClE,QAAM,SAAS,0BAA0B,wBAAwB,KAAK,CAAC;AACvE,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,OAAO,SAAS,cAAc,MAAM,SAAS,SAAS;AACxD,WAAO,OAAO;AAAA,EAChB;AACA,SAAO,cAAc,qBAAqB,MAAM,EAAE,GAAG,aAAa,KAAK,CAAC;AAC1E;AAEO,SAAS,wBAAwB,QAAsC;AAC5E,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,SAAS;AAC1B,YAAM,WAAW,iBAAiB,KAAK;AACvC,UAAI,SAAU,QAAO;AAAA,IACvB;AAEA,UAAM,SAAS,MAAM,UAAU,SAC3B,wBAAwB,MAAM,QAAQ,IACtC;AACJ,QAAI,OAAQ,QAAO;AAAA,EACrB;AAEA,SAAO;AACT;AAEO,SAAS,uBAAuB,OAAiC;AACtE,QAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,QAAM,SAAS,0BAA0B,KAAK;AAC9C,QAAM,WAAW,MAAM,UAAU,IAAI,sBAAsB;AAE3D,MAAI,CAAC,QAAQ;AACX,WAAO,WAAW,EAAE,GAAG,OAAO,SAAS,IAAI,EAAE,GAAG,MAAM;AAAA,EACxD;AAEA,QAAM,OAAO,cAAc,qBAAqB,MAAM,EAAE,GAAG,aAAa,KAAK,CAAC;AAC9E,QAAM,cACJ,OAAO,SAAS,aACZ,MAAM,SAAS,UACb;AAAA,IACE,GAAI;AAAA,IACJ,UAAU,EAAE,KAAK,KAAK;AAAA,EACxB,IACA,QACF;AAAA,IACE,GAAI;AAAA,IACJ,MAAM;AAAA,MACJ,KAAK;AAAA,MACL,aAAa;AAAA,IACf;AAAA,EACF;AAEN,SAAO;AAAA,IACL,GAAG;AAAA,IACH,CAAC,MAAM,IAAI,GAAG;AAAA,IACd,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,EACjC;AACF;AAEO,SAAS,sBACd,OACA,SACa;AACb,QAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,QAAM,SAAS,0BAA0B,KAAK;AAC9C,QAAM,WAAW,MAAM,UAAU;AAAA,IAAI,CAAC,UACpC,sBAAsB,OAAO,OAAO;AAAA,EACtC;AAEA,MAAI,MAAM,SAAS,WAAW,CAAC,QAAQ;AACrC,UAAM,cAAc,uBAAuB,KAAK;AAChD,WAAO,WAAW,EAAE,GAAG,aAAa,SAAS,IAAI;AAAA,EACnD;AAEA,QAAM,aAAsC;AAAA,IAC1C,GAAI;AAAA,IACJ,OAAO;AAAA,IACP,YAAY,SAAS,oBAAoB,KAAK,KAAK;AAAA,EACrD;AAEA,MAAI,OAAO,SAAS,YAAY;AAC9B,eAAW,WAAW,EAAE,KAAK,KAAK;AAAA,EACpC,OAAO;AACL,eAAW,OAAO;AAAA,MAChB,KAAK;AAAA,MACL,aAAa;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO;AAAA,IACP,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,EACjC;AACF;AAEO,SAAS,iBAAiB,KAAsB;AACrD,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,WAAO,gCAAgC,KAAK,OAAO,QAAQ;AAAA,EAC7D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,cAAc,KAA4B;AACxD,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,UAAM,OAAO,OAAO,SAAS,QAAQ,UAAU,EAAE;AAEjD,QAAI,SAAS,iBAAiB,SAAS,iBAAiB;AACtD,YAAM,KAAK,OAAO,aAAa,IAAI,GAAG;AACtC,aAAO,KAAK,iCAAiC,mBAAmB,EAAE,CAAC,KAAK;AAAA,IAC1E;AAEA,QAAI,SAAS,YAAY;AACvB,YAAM,KAAK,OAAO,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,CAAC;AACvD,aAAO,KAAK,iCAAiC,mBAAmB,EAAE,CAAC,KAAK;AAAA,IAC1E;AAEA,QAAI,SAAS,wBAAwB;AACnC,aAAO,OAAO,SAAS;AAAA,IACzB;AAEA,QAAI,SAAS,aAAa;AACxB,YAAM,KAAK,OAAO,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,CAAC;AACvD,aAAO,KAAK,kCAAkC,mBAAmB,EAAE,CAAC,KAAK;AAAA,IAC3E;AAEA,QAAI,SAAS,oBAAoB;AAC/B,aAAO,OAAO,SAAS;AAAA,IACzB;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -2,7 +2,7 @@ export { CreateNotionWebhookRouteOptions, NotionWebhookParserFn, RevalidateConte
|
|
|
2
2
|
import 'next/server';
|
|
3
3
|
import '../webhook.js';
|
|
4
4
|
import '../../platform/runtime.js';
|
|
5
|
-
import '../../env-
|
|
5
|
+
import '../../env-hoez1e-n.js';
|
|
6
6
|
import '../property-mappers.js';
|
|
7
7
|
import '../types.js';
|
|
8
8
|
import '../config.js';
|
|
@@ -9,7 +9,6 @@ function readProcessEnv() {
|
|
|
9
9
|
const env2 = {
|
|
10
10
|
NOTION_TOKEN: process.env.NOTION_TOKEN,
|
|
11
11
|
NOTION_DATA_SOURCE_ID: process.env.NOTION_DATA_SOURCE_ID,
|
|
12
|
-
NOTION_MOVIES_DATA_SOURCE_ID: process.env.NOTION_MOVIES_DATA_SOURCE_ID,
|
|
13
12
|
NOTION_API_BASE_URL: process.env.NOTION_API_BASE_URL,
|
|
14
13
|
NOTION_EDIT_BASE_URL: process.env.NOTION_EDIT_BASE_URL,
|
|
15
14
|
NOTION_WEBHOOK_VERIFICATION_TOKEN: process.env.NOTION_WEBHOOK_VERIFICATION_TOKEN
|