diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..5a7704c
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,6 @@
+{
+ "singleQuote": false,
+ "trailingComma": "es5",
+ "tabWidth": 2,
+ "semi": true
+}
diff --git a/package-lock.json b/package-lock.json
index b2fdc11..35239bb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,8 @@
"version": "0.0.1",
"license": "ISC",
"dependencies": {
- "@notionhq/client": "^2.2.3"
+ "@notionhq/client": "^2.2.3",
+ "cheerio": "^1.0.0"
},
"devDependencies": {
"cp": "^0.2.0",
@@ -54,6 +55,51 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
+ },
+ "node_modules/cheerio": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz",
+ "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==",
+ "dependencies": {
+ "cheerio-select": "^2.1.0",
+ "dom-serializer": "^2.0.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.1.0",
+ "encoding-sniffer": "^0.2.0",
+ "htmlparser2": "^9.1.0",
+ "parse5": "^7.1.2",
+ "parse5-htmlparser2-tree-adapter": "^7.0.0",
+ "parse5-parser-stream": "^7.1.2",
+ "undici": "^6.19.5",
+ "whatwg-mimetype": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18.17"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ }
+ },
+ "node_modules/cheerio-select": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+ "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-select": "^5.1.0",
+ "css-what": "^6.1.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -73,6 +119,32 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/css-select": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+ "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+ "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -82,6 +154,80 @@
"node": ">=0.4.0"
}
},
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ]
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/encoding-sniffer": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz",
+ "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==",
+ "dependencies": {
+ "iconv-lite": "^0.6.3",
+ "whatwg-encoding": "^3.1.1"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
+ }
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/form-data": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
@@ -96,6 +242,35 @@
"node": ">= 6"
}
},
+ "node_modules/htmlparser2": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
+ "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.1.0",
+ "entities": "^4.5.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@@ -137,6 +312,56 @@
}
}
},
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz",
+ "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==",
+ "dependencies": {
+ "entities": "^4.5.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-htmlparser2-tree-adapter": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
+ "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
+ "dependencies": {
+ "domhandler": "^5.0.3",
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-parser-stream": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
+ "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
+ "dependencies": {
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@@ -157,6 +382,14 @@
"node": ">=4.2.0"
}
},
+ "node_modules/undici": {
+ "version": "6.21.2",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.2.tgz",
+ "integrity": "sha512-uROZWze0R0itiAKVPsYhFov9LxrPMHLMEQFszeI2gCN6bnIIZ8twzBCJcN2LJrBBLfrP0t1FW0g+JmKVl8Vk1g==",
+ "engines": {
+ "node": ">=18.17"
+ }
+ },
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
@@ -169,6 +402,25 @@
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
},
+ "node_modules/whatwg-encoding": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
diff --git a/package.json b/package.json
index 6b6904b..5b490e0 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,9 @@
"name": "@notionpresso/api-sdk",
"version": "0.0.1",
"description": "",
+ "main": "./package/index.js",
+ "module": "./package/index.js",
+ "types": "./package/index.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"sync": "tsc --build .",
@@ -23,7 +26,8 @@
"typescript": "^4.9.4"
},
"dependencies": {
- "@notionhq/client": "^2.2.3"
+ "@notionhq/client": "^2.2.3",
+ "cheerio": "^1.0.0"
},
"type": "module",
"exports": {
diff --git a/src/embed/tweet/index.ts b/src/embed/tweet/index.ts
new file mode 100644
index 0000000..0bf818a
--- /dev/null
+++ b/src/embed/tweet/index.ts
@@ -0,0 +1 @@
+export * from "./process.js";
diff --git a/src/embed/tweet/process.ts b/src/embed/tweet/process.ts
new file mode 100644
index 0000000..604f6b4
--- /dev/null
+++ b/src/embed/tweet/process.ts
@@ -0,0 +1,22 @@
+import type { EmbedBlockObjectResponse } from "@notionhq/client/build/src/api-endpoints";
+import { convertToNotionpressoTweet } from "./tweet";
+
+export function processTwitterEmbeds(blocks: any[]): any[] {
+ return blocks.map((block) => {
+ if ("type" in block) {
+ if (block.type === "embed") {
+ const embedBlock = block as EmbedBlockObjectResponse;
+
+ if (
+ embedBlock.embed.url &&
+ (embedBlock.embed.url.includes("twitter") ||
+ embedBlock.embed.url.includes("x.com"))
+ ) {
+ console.log("트위터/X 임베드 변환:", embedBlock.embed.url);
+ return convertToNotionpressoTweet(embedBlock);
+ }
+ }
+ }
+ return block;
+ });
+}
diff --git a/src/embed/tweet/script.ts b/src/embed/tweet/script.ts
new file mode 100644
index 0000000..6705cf0
--- /dev/null
+++ b/src/embed/tweet/script.ts
@@ -0,0 +1,27 @@
+export const themeScript = `
+
+`;
diff --git a/src/embed/tweet/tweet.ts b/src/embed/tweet/tweet.ts
new file mode 100644
index 0000000..16defc6
--- /dev/null
+++ b/src/embed/tweet/tweet.ts
@@ -0,0 +1,207 @@
+import type { OEmbedResponse } from "./types.js";
+import { themeScript } from "./script.js";
+
+export async function fetchOEmbedData(
+ url: string
+): Promise {
+ try {
+ const isTwitterUrl = isTwitter(url);
+
+ if (isTwitterUrl) {
+ return await handleTwitterEmbed(url);
+ }
+
+ return {
+ type: "link",
+ provider_name: safeGetHostname(url),
+ title: "View Link",
+ url: url,
+ };
+ } catch (error) {
+ console.error("Failed to fetch OEmbed data:", error);
+
+ return {
+ type: "link",
+ provider_name: safeGetHostname(url),
+ title: "View Link",
+ url: url,
+ };
+ }
+}
+
+function isTwitter(url: string): boolean {
+ try {
+ const hostname = new URL(url).hostname.toLowerCase();
+ return hostname.includes("twitter.com") || hostname.includes("x.com");
+ } catch (e) {
+ return false;
+ }
+}
+
+export function convertToNotionpressoTweet(embedData: any): any {
+ if (embedData.type === "embed") {
+ const embedUrl = embedData.embed?.url;
+
+ if (
+ embedUrl &&
+ (embedUrl.includes("twitter") || embedUrl.includes("x.com"))
+ ) {
+ const { embed, ...rest } = embedData;
+
+ const tweetId = extractTweetId(embedUrl);
+
+ if (!tweetId) {
+ console.error("Cannot extract tweet ID:", embedUrl);
+ return embedData;
+ }
+
+ const iframeUrl = createTwitterEmbedUrl(tweetId, "light");
+
+ const html = `
+
+ ${themeScript}`;
+
+ return {
+ ...rest,
+ type: "notionpresso_tweet",
+ notionpresso_tweet: {
+ url: embedUrl,
+ iframe_url: iframeUrl,
+ source: "twitter",
+ tweet_id: tweetId,
+ html: html,
+ theme: "auto",
+ },
+ };
+ }
+ }
+
+ return embedData;
+}
+
+async function handleTwitterEmbed(url: string): Promise {
+ try {
+ const tweetId = extractTweetId(url);
+
+ if (!tweetId) {
+ throw new Error("Cannot extract tweet ID.");
+ }
+
+ const iframeUrl = createTwitterEmbedUrl(tweetId, "light");
+
+ const html = `
+
+ ${themeScript}`;
+
+ return {
+ type: "notionpresso_tweet",
+ provider_name: "Twitter",
+ provider_url: "https://twitter.com",
+ url: url,
+ html: html,
+ width: 420,
+ height: 592,
+ title: "Twitter Tweet",
+ notionpresso_tweet: {
+ url: url,
+ iframe_url: iframeUrl,
+ source: "twitter",
+ tweet_id: tweetId,
+ theme: "auto",
+ },
+ } as OEmbedResponse;
+ } catch (error) {
+ console.error("Error processing Twitter embed:", error);
+
+ return {
+ type: "link",
+ provider_name: "Twitter",
+ provider_url: "https://twitter.com",
+ url: url,
+ title: "View Tweet",
+ };
+ }
+}
+
+function extractTweetId(twitterUrl: string): string | null {
+ try {
+ const url = new URL(twitterUrl);
+ const pathname = url.pathname;
+
+ const statusMatch = pathname.match(/\/status\/(\d+)/);
+ if (statusMatch && statusMatch[1]) {
+ return statusMatch[1];
+ }
+
+ const xMatch = pathname.match(/\/(\w+)\/status\/(\d+)/);
+ if (xMatch && xMatch[2]) {
+ return xMatch[2];
+ }
+
+ return null;
+ } catch (e) {
+ console.error("Error extracting tweet ID:", e);
+ return null;
+ }
+}
+
+function createTwitterEmbedUrl(
+ tweetId: string,
+ theme: string = "light"
+): string {
+ const baseUrl = "https://platform.twitter.com/embed/Tweet.html";
+
+ const params = new URLSearchParams({
+ id: tweetId,
+ dnt: "true",
+ embedId: "twitter-widget-0",
+ frame: "false",
+ hideCard: "false",
+ hideThread: "false",
+ lang: "en",
+ theme: theme,
+ siteScreenName: "NotionpressoHQ",
+ widgetsVersion: "2b959255e8896:1673658205745",
+ width: "100%",
+ });
+
+ const features =
+ "eyJ0ZndfdGltZWxpbmVfbGlzdCI6eyJidWNrZXQiOltdLCJ2ZXJzaW9uIjpudWxsfSwidGZ3X2ZvbGxvd2VyX2NvdW50X3N1bnNldCI6eyJidWNrZXQiOnRydWUsInZlcnNpb24iOm51bGx9LCJ0ZndfdHdlZXRfZWRpdF9iYWNrZW5kIjp7ImJ1Y2tldCI6Im9uIiwidmVyc2lvbiI6bnVsbH0sInRmd19yZWZzcmNfc2Vzc2lvbiI6eyJidWNrZXQiOiJvbiIsInZlcnNpb24iOm51bGx9LCJ0ZndfZm9zbnJfc29mdF9pbnRlcnZlbnRpb25zX2VuYWJsZWQiOnsiYnVja2V0Ijoib24iLCJ2ZXJzaW9uIjpudWxsfSwidGZ3X21peGVkX21lZGlhXzE1ODk3Ijp7ImJ1Y2tldCI6InRyZWF0bWVudCIsInZlcnNpb24iOm51bGx9LCJ0ZndfdXNlX3Byb2ZpbGVfaW1hZ2Vfc2hhcGVfZW5hYmxlZCI6eyJidWNrZXQiOiJvbiIsInZlcnNpb24iOm51bGx9LCJ0ZndfdmlkZW9faGxzX2R5bmFtaWNfbWFuaWZlc3RzXzE1MDgyIjp7ImJ1Y2tldCI6InRydWVfYml0cmF0ZSIsInZlcnNpb24iOm51bGx9LCJ0ZndfbGVnYWN5X3RpbWVsaW5lX3N1bnNldCI6eyJidWNrZXQiOnRydWUsInZlcnNpb24iOm51bGx9LCJ0ZndfdHdlZXRfZWRpdF9mcm9udGVuZCI6eyJidWNrZXQiOiJvbiIsInZlcnNpb24iOm51bGx9fQ";
+ params.set("features", features);
+
+ return `${baseUrl}?${params.toString()}`;
+}
+
+function safeGetHostname(url: string): string {
+ try {
+ return new URL(url).hostname.replace(/^www\./, "");
+ } catch (e) {
+ return "link";
+ }
+}
diff --git a/src/embed/tweet/types.ts b/src/embed/tweet/types.ts
new file mode 100644
index 0000000..2c6e490
--- /dev/null
+++ b/src/embed/tweet/types.ts
@@ -0,0 +1,33 @@
+export interface OEmbedResponse {
+ type: string;
+ version?: string;
+ title?: string;
+ url?: string;
+ provider_name: string;
+ provider_url?: string;
+
+ width?: number;
+ height?: number;
+ html?: string;
+
+ thumbnail_url?: string;
+ thumbnail_width?: number;
+ thumbnail_height?: number;
+
+ author_name?: string;
+ author_url?: string;
+
+ cache_age?: number;
+ description?: string;
+}
+
+export interface NotionpressoTweetBlock {
+ type: "notionpresso_tweet";
+ notionpresso_tweet: {
+ url: string;
+ iframe_url: string;
+ source: string;
+ tweet_id?: string;
+ html: string;
+ };
+}
diff --git a/src/index.ts b/src/index.ts
index 0595fd3..afb48af 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,5 @@
-import {Client as _Client} from "@notionhq/client";
-import type {ClientOptions} from "@notionhq/client/build/src/Client";
+import { Client as _Client } from "@notionhq/client";
+import type { ClientOptions } from "@notionhq/client/build/src/Client";
import {
BlockObjectResponse,
PageObjectResponse,
@@ -7,6 +7,8 @@ import {
QueryDatabaseResponse,
} from "@notionhq/client/build/src/api-endpoints";
+import { processTwitterEmbeds } from "./embed/tweet";
+
export class Client extends _Client {
constructor(options: ClientOptions = {}) {
super(options);
@@ -32,10 +34,11 @@ export class Client extends _Client {
} while (cursor);
}
+ blocks = processTwitterEmbeds(blocks);
+
const result = (await Promise.all(
(blocks as BlockObjectResponse[]).map(async (block) => {
if (block.has_children) {
-
const blockId =
block.type === "synced_block" &&
block.synced_block.synced_from != null
@@ -62,11 +65,18 @@ export class Client extends _Client {
return { ...page, blocks };
}
- async fetchPageListFromDatabase(params: QueryDatabaseParameters): Promise {
+ async fetchPageListFromDatabase(
+ params: QueryDatabaseParameters
+ ): Promise {
const response = await this.databases.query(params);
const result = [...response.results];
- if (response.has_more) {
- const nextParams = {...params, database_id: response.next_cursor};
+ if (response.has_more && response.next_cursor) {
+ const { database_id, ...restParams } = params;
+ const nextParams = {
+ database_id: database_id as string,
+ ...restParams,
+ start_cursor: response.next_cursor,
+ };
const nextResult = await this.fetchPageListFromDatabase(nextParams);
result.push(...nextResult);
}
@@ -77,6 +87,6 @@ export class Client extends _Client {
export type Block = BlockObjectResponse & { blocks: Block[] };
export type ContentfulPage = PageObjectResponse & { blocks: Block[] };
-export type QueryDatabaseResults = QueryDatabaseResponse['results'];
+export type QueryDatabaseResults = QueryDatabaseResponse["results"];
export { ClientOptions };
export default Client;