(notion: NotionAPI, pageId: string)
| 44 | // k8s datacenter egress IP get hard-blocked with a 403 "Attention Required" Cloudflare |
| 45 | // page on the endpoints notion-client normally uses (`loadPageChunk`, `syncRecordValues`, |
| 46 | // `queryCollection`), which took down every track/problem page with a 500. |
| 47 | // |
| 48 | // Empirically, `loadCachedPageChunkV2` is NOT blocked from the cluster and returns the |
| 49 | // full page recordMap in a single request, so we fetch through that endpoint directly |
| 50 | // (via the client's public `fetch`) instead of `getPage`. We also authenticate with |
| 51 | // NOTION_TOKEN_V2 (private-page access) and aggressively throttle + cache, because the |
| 52 | // block is IP-reputation based: bursts of requests re-trigger a broader Cloudflare block, |
| 53 | // so keeping request volume low is what keeps this endpoint working. |
| 54 | let notionSingleton: NotionAPI | null = null; |
| 55 | |
| 56 | export function getNotionClient(): NotionAPI { |
| 57 | if (notionSingleton) return notionSingleton; |
| 58 | notionSingleton = new NotionAPI({ |
| 59 | // eslint-disable-next-line turbo/no-undeclared-env-vars |
| 60 | authToken: process.env.NOTION_TOKEN_V2 || undefined, |
| 61 | // eslint-disable-next-line turbo/no-undeclared-env-vars |
no test coverage detected