Turned the connected-but-inert Notion link into working features. Both
directions go through a shared page picker (/v1/search).
Added
lib/notion-shared.ts— client+server-safe DTOs (NotionPage,NotionImportItem) so block↔card mapping stays UI-side.lib/notion.ts—getNotionToken()(reads the stored token via the admin client),searchNotionPages(),cardsToNotionBlocks()(all 9 card kinds → paragraphs / bookmarks / callouts; data-URL images are marked, not exported),createNotionExport()(creates a sub-page, chunks >100 blocks), andfetchNotionPageItems()(paginated block read → neutral items).- Routes —
GET /api/integrations/notion/pages,POST …/export(cards in the body → new Notion page, returns its URL),POST …/import(page id → import items). Canvas.addCards()— bulk-places pre-built cards at the viewport center (incoming x/y treated as relative offsets), persisted + synced like any add.- IntegrationsPanel — when Notion is connected, the content-source row shows
Import and the export row shows Export, both opening a
NotionPickermodal. Import drops cards on the canvas and closes the drawer; export opens the new Notion page. Skeleton, empty ("add this integration under Connections"), and error states included.
Notes
- Notion-hosted image URLs are time-limited signed links, so imported images may expire; external image URLs persist.
- Export requires picking a parent page (Notion's API can't create top-level workspace pages), which is why the picker is shared with import.