Skip to content

Commit 1df3a71

Browse files
committed
Merge main into release
2 parents 702a0ff + 2ad2ab1 commit 1df3a71

File tree

6 files changed

+105
-17
lines changed

6 files changed

+105
-17
lines changed

README.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,29 +31,29 @@ Currently, docu-notion expects that each page has only one of the following: sub
3131

3232
## 6. Pull your pages
3333

34-
First, determine the id of your root page by clicking "Share" and looking at the the url it gives you. E.g.
34+
First, determine the id of your root page by clicking "Share" and looking at the url it gives you. E.g.
3535
https://www.notion.so/hattonjohn/My-Docs-0456aa5842946bdbea3a4f37c97a0e5
3636
means that the id is "0456aa5842946PRETEND4f37c97a0e5".
3737

3838
Determine where you want the markdown files and images to land. The following works well for Docusaurus instances:
3939

4040
```
41-
npx docu-notion -n secret_PRETEND123456789PRETEND123456789PRETEND6789 -r 0456aa5842946PRETEND4f37c97a0e5"
41+
npx @sillsdev/docu-notion -n secret_PRETEND123456789PRETEND123456789PRETEND6789 -r 0456aa5842946PRETEND4f37c97a0e5"
4242
```
4343

4444
Likely, you will want to store these codes in your environment variables and then use them like this:
4545

4646
```
4747
(windows)
48-
npx docu-notion -n %MY_NOTION_TOKEN% -r %MY_NOTION_DOCS_ROOT_PAGE_ID%
48+
npx @sillsdev/docu-notion -n %MY_NOTION_TOKEN% -r %MY_NOTION_DOCS_ROOT_PAGE_ID%
4949
```
5050

5151
```
5252
(linux / mac)
53-
npx docu-notion -n $MY_NOTION_TOKEN -r $MY_NOTION_DOCS_ROOT_PAGE_ID
53+
npx @sillsdev/docu-notion -n $MY_NOTION_TOKEN -r $MY_NOTION_DOCS_ROOT_PAGE_ID
5454
```
5555

56-
NOTE: In the above, we are using `npx` to use the latest `docu-notion`. A more conservative approach would be to `npm i cross-var docu-notion` and then create a script in your package.json like this:
56+
NOTE: In the above, we are using `npx` to use the latest `docu-notion`. A more conservative approach would be to `npm i cross-var @sillsdev/docu-notion` and then create a script in your package.json like this:
5757

5858
```
5959
"scripts": {
@@ -133,3 +133,16 @@ Options:
133133
# Plugins
134134

135135
If your project needs some processing that docu-notion doesn't already provide, you can provide a plugin that does it. See the [plugin readme](src/plugins/README.md).
136+
137+
# Callouts ➜ Admonitions
138+
139+
To map Notion callouts to Docusaurus admonitions, ensure the icon is for the type you want.
140+
141+
- ℹ️ ➜ note
142+
- 📝➜ note
143+
- 💡➜ tip
144+
- ❗➜ info
145+
- ⚠️➜ caution
146+
- 🔥➜ danger
147+
148+
The default admonition type, if no matching icon is found, is "note".

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"// typescript check": "",
1212
"tsc": "tsc",
1313
"// test out with a private sample notion db": "",
14+
"large-site-test": "npm run ts -- -n $SIL_BLOOM_DOCS_NOTION_TOKEN -r $SIL_BLOOM_DOCS_NOTION_ROOT_PAGE --locales en,fr",
1415
"pull-test-tagged": "npm run ts -- -n $DOCU_NOTION_INTEGRATION_TOKEN -r $DOCU_NOTION_TEST_ROOT_PAGE_ID --log-level debug --status-tag test",
1516
"pull-sample-site": "npm run ts -- -n $DOCU_NOTION_INTEGRATION_TOKEN -r $DOCU_NOTION_SAMPLE_ROOT_PAGE --log-level debug",
1617
"// test with a semi-stable/public site:": "",

src/plugins/ColumnTransformer.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { NotionAPI } from "notion-client";
22
import { NotionToMarkdown } from "notion-to-md";
33
import { ListBlockChildrenResponseResult } from "notion-to-md/build/types";
44
import { IGetBlockChildrenFn, IPlugin } from "./pluginTypes";
5+
import { executeWithRateLimitAndRetries } from "../pull";
56

67
export const standardColumnTransformer: IPlugin = {
78
name: "standardColumnTransformer",
@@ -61,8 +62,13 @@ async function getColumnWidth(
6162
): Promise<string> {
6263
const unofficialNotionClient = new NotionAPI();
6364
const blockId = block.id;
64-
// Yes, it is odd to call 'getPage' for a block, but that's how we access the format info.
65-
const recordMap = await unofficialNotionClient.getPage(blockId);
65+
const recordMap = await executeWithRateLimitAndRetries(
66+
`unofficialNotionClient.getPage(${blockId}) in getColumnWidth()`,
67+
() => {
68+
// Yes, it is odd to call 'getPage' for a block, but that's how we access the format info.
69+
return unofficialNotionClient.getPage(blockId);
70+
}
71+
);
6672
const blockResult = recordMap.block[blockId];
6773

6874
// ENHANCE: could we use https://github.com/NotionX/react-notion-x/tree/master/packages/notion-types

src/plugins/internalLinks.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,36 @@ test("does not interfere with mailto links", async () => {
374374
});
375375
expect(results.trim()).toBe(`[mailme](mailto:[email protected])`);
376376
});
377+
378+
test("does not interfere with https links", async () => {
379+
const results = await getMarkdown({
380+
type: "paragraph",
381+
paragraph: {
382+
rich_text: [
383+
{
384+
type: "text",
385+
text: {
386+
content: "google",
387+
link: { url: `https://www.google.com` },
388+
},
389+
annotations: {
390+
bold: false,
391+
italic: false,
392+
strikethrough: false,
393+
underline: false,
394+
code: false,
395+
color: "default",
396+
},
397+
plain_text: "google",
398+
href: `https://www.google.com`,
399+
},
400+
],
401+
color: "default",
402+
},
403+
});
404+
expect(results.trim()).toBe(`[google](https://www.google.com)`);
405+
});
406+
377407
test("links to other notion pages that are not in this site give PROBLEM LINK", async () => {
378408
const results = await getMarkdown({
379409
type: "paragraph",

src/pull.ts

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,49 @@ const notionLimiter = new RateLimiter({
256256
let notionClient: Client;
257257

258258
async function getPageMetadata(id: string): Promise<GetPageResponse> {
259+
return await executeWithRateLimitAndRetries(`pages.retrieve(${id})`, () => {
260+
return notionClient.pages.retrieve({
261+
page_id: id,
262+
});
263+
});
264+
}
265+
266+
// While everything works fine locally, on Github Actions we are getting a lot of timeouts, so
267+
// we're trying this extra retry-able wrapper.
268+
export async function executeWithRateLimitAndRetries<T>(
269+
label: string,
270+
asyncFunction: () => Promise<T>
271+
): Promise<T> {
259272
await rateLimit();
273+
const kRetries = 10;
274+
let lastException = undefined;
275+
for (let i = 0; i < kRetries; i++) {
276+
try {
277+
return await asyncFunction();
278+
} catch (e: any) {
279+
lastException = e;
280+
if (
281+
e?.code === "notionhq_client_request_timeout" ||
282+
e.message.includes("timeout") ||
283+
e.message.includes("Timeout") ||
284+
e.message.includes("limit") ||
285+
e.message.includes("Limit")
286+
) {
287+
const secondsToWait = i + 1;
288+
info(
289+
`While doing "${label}", got error "${
290+
e.message as string
291+
}". Will retry after ${secondsToWait}s...`
292+
);
293+
await new Promise(resolve => setTimeout(resolve, 1000 * secondsToWait));
294+
} else {
295+
throw e;
296+
}
297+
}
298+
}
260299

261-
return await notionClient.pages.retrieve({
262-
page_id: id,
263-
});
300+
error(`Error: could not complete "${label}" after ${kRetries} retries.`);
301+
throw lastException;
264302
}
265303

266304
async function rateLimit() {
@@ -275,18 +313,19 @@ async function getBlockChildren(id: string): Promise<NotionBlock[]> {
275313
// the first response we get, then keep adding to its array of blocks
276314
// with each subsequent response
277315
let overallResult: ListBlockChildrenResponse | undefined = undefined;
278-
let start_cursor = undefined;
316+
let start_cursor: string | undefined | null = undefined;
279317

280318
// Note: there is a now a collectPaginatedAPI() in the notion client, so
281319
// we could switch to using that (I don't know if it does rate limiting?)
282320
do {
283-
await rateLimit();
284-
285321
const response: ListBlockChildrenResponse =
286-
await notionClient.blocks.children.list({
287-
start_cursor: start_cursor,
288-
block_id: id,
322+
await executeWithRateLimitAndRetries(`getBlockChildren(${id})`, () => {
323+
return notionClient.blocks.children.list({
324+
start_cursor: start_cursor as string | undefined,
325+
block_id: id,
326+
});
289327
});
328+
290329
if (!overallResult) {
291330
overallResult = response;
292331
} else {

src/transform.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ async function doTransformsOnMarkdown(
133133
matchAsThePluginWouldExpectIt
134134
);
135135
} else if (mod.replacementPattern) {
136-
console.log(`mod.replacementPattern.replace("$1", ${match[2]}`);
137136
replacement = mod.replacementPattern.replace("$1", match[2]);
138137
}
139138
if (replacement !== undefined) {

0 commit comments

Comments
 (0)