1 | |
2 |
|
3 | |
4 | * Duplicate Page |
5 | * Copy a page's title, icon, cover and content into a new page under a parent page, via Notion-flavored Markdown. Database properties, comments and child pages' own content are not copied; uploaded-file icons and covers are skipped. |
6 | */ |
7 | export async function main( |
8 | auth: RT.Notion, |
9 | page_id: string, |
10 | parent_page_id: string, |
11 | title: string | undefined |
12 | ) { |
13 | const headers = { |
14 | Authorization: `Bearer ${auth.token}`, |
15 | Accept: "application/json", |
16 | "Notion-Version": "2026-03-11", |
17 | } |
18 | const get = async (path: string) => { |
19 | const response = await fetch(`https://api.notion.com/v1/${path}`, { |
20 | headers, |
21 | }) |
22 | if (!response.ok) { |
23 | throw new Error(`${response.status} ${await response.text()}`) |
24 | } |
25 | return await response.json() |
26 | } |
27 |
|
28 | const page = await get(`pages/${page_id}`) |
29 | const content = await get(`pages/${page_id}/markdown`) |
30 | if (content.truncated) { |
31 | throw new Error( |
32 | "Page is too large to copy in one request (truncated markdown)" |
33 | ) |
34 | } |
35 | const source = Object.values(page.properties).find( |
36 | (p: any) => p.type === "title" |
37 | ) as { title: { plain_text: string }[] } |
38 | const keep = (v: any) => |
39 | v && v.type !== "file" && v.type !== "file_upload" ? v : undefined |
40 |
|
41 | const body: { [key: string]: any } = { |
42 | parent: { type: "page_id", page_id: parent_page_id }, |
43 | properties: { |
44 | title: { |
45 | title: [ |
46 | { |
47 | text: { |
48 | content: title || source.title.map((t) => t.plain_text).join(""), |
49 | }, |
50 | }, |
51 | ], |
52 | }, |
53 | }, |
54 | icon: keep(page.icon), |
55 | cover: keep(page.cover), |
56 | } |
57 | if (content.markdown) body.markdown = content.markdown |
58 |
|
59 | const response = await fetch("https://api.notion.com/v1/pages", { |
60 | method: "POST", |
61 | headers: { ...headers, "Content-Type": "application/json" }, |
62 | body: JSON.stringify(body), |
63 | }) |
64 |
|
65 | if (!response.ok) { |
66 | throw new Error(`${response.status} ${await response.text()}`) |
67 | } |
68 |
|
69 | return await response.json() |
70 | } |
71 |
|