rotion 3.6.3 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +20 -12
- package/README.md +26 -17
- package/dist/exporter/api.d.ts +11 -1
- package/dist/exporter/api.js +35 -30
- package/dist/exporter/api.js.map +1 -1
- package/dist/exporter/bin.d.ts +2 -0
- package/dist/exporter/bin.js +4 -0
- package/dist/exporter/bin.js.map +1 -0
- package/dist/exporter/blocks.js +355 -322
- package/dist/exporter/blocks.js.map +1 -1
- package/dist/exporter/breadcrumbs.js +3 -3
- package/dist/exporter/breadcrumbs.js.map +1 -1
- package/dist/exporter/cli.d.ts +16 -0
- package/dist/exporter/cli.js +126 -0
- package/dist/exporter/cli.js.map +1 -0
- package/dist/exporter/database.js +82 -75
- package/dist/exporter/database.js.map +1 -1
- package/dist/exporter/dependencies.d.ts +38 -0
- package/dist/exporter/dependencies.js +102 -0
- package/dist/exporter/dependencies.js.map +1 -0
- package/dist/exporter/failures.d.ts +52 -0
- package/dist/exporter/failures.js +105 -0
- package/dist/exporter/failures.js.map +1 -0
- package/dist/exporter/files.d.ts +21 -0
- package/dist/exporter/files.js +164 -94
- package/dist/exporter/files.js.map +1 -1
- package/dist/exporter/github.d.ts +8 -0
- package/dist/exporter/github.js +22 -5
- package/dist/exporter/github.js.map +1 -1
- package/dist/exporter/index.d.ts +4 -0
- package/dist/exporter/index.js +2 -0
- package/dist/exporter/index.js.map +1 -1
- package/dist/exporter/log.d.ts +6 -0
- package/dist/exporter/log.js +15 -0
- package/dist/exporter/log.js.map +1 -0
- package/dist/exporter/mutex.js +55 -16
- package/dist/exporter/mutex.js.map +1 -1
- package/dist/exporter/page.js +51 -35
- package/dist/exporter/page.js.map +1 -1
- package/dist/exporter/prune.d.ts +27 -0
- package/dist/exporter/prune.js +95 -0
- package/dist/exporter/prune.js.map +1 -0
- package/dist/exporter/types.d.ts +13 -0
- package/dist/exporter/variables.d.ts +61 -17
- package/dist/exporter/variables.js +86 -23
- package/dist/exporter/variables.js.map +1 -1
- package/dist/ui/components/Gallery/GalleryCard/options.d.ts +11 -0
- package/dist/ui/esm/components/Gallery/GalleryCard/GalleryCard.js +2 -17
- package/dist/ui/esm/components/Gallery/GalleryCard/GalleryCard.js.map +1 -1
- package/dist/ui/esm/components/Gallery/GalleryCard/options.js +27 -0
- package/dist/ui/esm/components/Gallery/GalleryCard/options.js.map +1 -0
- package/dist/ui/esm/components/Page/CodeBlock/Code/Code.js +5 -0
- package/dist/ui/esm/components/Page/CodeBlock/Code/Code.js.map +1 -1
- package/dist/ui/index-without-dark.css +1 -1
- package/dist/ui/index.css +1 -1
- package/package.json +32 -25
package/dist/exporter/blocks.js
CHANGED
|
@@ -1,375 +1,408 @@
|
|
|
1
1
|
import { reqAPIWithBackoff, reqAPIWithBackoffAndCache, notion, } from './api.js';
|
|
2
|
-
import {
|
|
2
|
+
import { config } from './variables.js';
|
|
3
3
|
import { FetchPage, getNotionIconUrl } from './page.js';
|
|
4
4
|
import { createDirWhenNotfound, saveImage, saveFile, readCache, writeCache, getHtmlMeta, getVideoHtml, getEmbedHtml, isEmpty, getVideoType } from './files.js';
|
|
5
5
|
import { FetchBreadcrumbs } from './breadcrumbs.js';
|
|
6
6
|
import { getIssueForLinkPreview, getRepoForLinkPreview } from './github.js';
|
|
7
|
+
import { collectFailures, reportFailure, reportExtraFailure } from './failures.js';
|
|
8
|
+
import { warn } from './log.js';
|
|
9
|
+
import { withFileLock } from './mutex.js';
|
|
10
|
+
import { collectDependencies, recordDependency, recordDependencies, isAnyDependencyChanged, editedTimeOf, pageOfBlock, } from './dependencies.js';
|
|
7
11
|
/**
|
|
8
12
|
* FetchBlocks retrieves page blocks and download images in from blocks.
|
|
9
13
|
* And create cache that includes filepath of downloaded images.
|
|
10
14
|
* The last_edited_time of 2nd args is for ROTION_INCREMENTAL_CACHE.
|
|
11
15
|
*/
|
|
12
16
|
export const FetchBlocks = async ({ block_id, last_edited_time }) => {
|
|
17
|
+
const { cacheDir, incrementalCache, debug } = config();
|
|
13
18
|
await createDirWhenNotfound(cacheDir);
|
|
14
19
|
const cacheFile = `${cacheDir}/notion.blocks.children.list-${block_id}`;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
const lockKey = `blocks-${block_id}`;
|
|
21
|
+
// Parallel build workers, or concurrent requests to a server, wait here
|
|
22
|
+
// for the one that fetches the blocks, and then read its cache.
|
|
23
|
+
return withFileLock(lockKey, async () => {
|
|
24
|
+
try {
|
|
25
|
+
const list = await readCache(cacheFile);
|
|
26
|
+
if (!isEmpty(list)) {
|
|
27
|
+
if (incrementalCache && last_edited_time === undefined && debug) {
|
|
20
28
|
console.log(`use cache in FetchBlocks(): ${cacheFile}, last_edited_time is required as a FetchBlocks() args when incremental cache`);
|
|
21
29
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
const sameEditedTime = !incrementalCache || last_edited_time === undefined || list.last_edited_time === last_edited_time;
|
|
31
|
+
// A page or database the blocks show may have been edited even though
|
|
32
|
+
// the page itself was not
|
|
33
|
+
if (sameEditedTime && !(incrementalCache && await isAnyDependencyChanged(list.dependencies))) {
|
|
34
|
+
if (debug) {
|
|
35
|
+
console.log(`use cache so same last-edited-time in FetchBlocks(): ${cacheFile}`);
|
|
36
|
+
}
|
|
37
|
+
recordDependencies(list.dependencies);
|
|
38
|
+
return list;
|
|
39
|
+
}
|
|
25
40
|
if (debug) {
|
|
26
|
-
|
|
41
|
+
const reason = sameEditedTime ? 'a page or database it shows was edited' : 'an old cache file was found';
|
|
42
|
+
console.log(`requesting to API because ${reason} in FetchBlocks(): ${cacheFile}`);
|
|
27
43
|
}
|
|
28
|
-
return list;
|
|
29
|
-
}
|
|
30
|
-
if (debug) {
|
|
31
|
-
console.log(`requesting to API because an old cache file was found in FetchBlocks(): ${cacheFile}`);
|
|
32
44
|
}
|
|
33
45
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
/* not fatal */
|
|
37
|
-
}
|
|
38
|
-
let allres;
|
|
39
|
-
let res;
|
|
40
|
-
let params = { block_id, start_cursor: undefined };
|
|
41
|
-
while (true) {
|
|
42
|
-
if (res && res.next_cursor) {
|
|
43
|
-
params.start_cursor = res.next_cursor;
|
|
46
|
+
catch (_) {
|
|
47
|
+
/* not fatal */
|
|
44
48
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (res.next_cursor === null) {
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
// With the blocks api, you can get the last modified date of a block,
|
|
61
|
-
// but not the last modified date of all blocks. So extend the type and add it.
|
|
62
|
-
if (last_edited_time) {
|
|
63
|
-
allres.last_edited_time = last_edited_time;
|
|
64
|
-
}
|
|
65
|
-
// Editing a nested block does not update its parent block's last_edited_time,
|
|
66
|
-
// only the page's. So pass the page's last_edited_time down to nested blocks.
|
|
67
|
-
for (const block of allres.results) {
|
|
68
|
-
try {
|
|
69
|
-
const { type } = block;
|
|
70
|
-
switch (type) {
|
|
71
|
-
case 'bookmark':
|
|
72
|
-
block.bookmark.site = await getHtmlMeta(block.bookmark.url);
|
|
73
|
-
break;
|
|
74
|
-
case 'bulleted_list_item':
|
|
75
|
-
if (block.has_children) {
|
|
76
|
-
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
77
|
-
}
|
|
78
|
-
break;
|
|
79
|
-
case 'breadcrumb':
|
|
80
|
-
block.list = await FetchBreadcrumbs({ id: block_id, type: 'page_id' });
|
|
81
|
-
break;
|
|
82
|
-
case 'callout':
|
|
83
|
-
if (block.callout.icon?.type === 'external') {
|
|
84
|
-
const iconUrl = block.callout.icon.external.url;
|
|
85
|
-
try {
|
|
86
|
-
const ipws = await saveImage(iconUrl, `block-${block.id}`);
|
|
87
|
-
block.callout.icon.src = ipws.path;
|
|
88
|
-
}
|
|
89
|
-
catch (e) {
|
|
90
|
-
if (debug) {
|
|
91
|
-
console.log(`Failed to save callout icon: ${e}`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
else if (block.callout.icon?.type === 'icon') {
|
|
96
|
-
const url = getNotionIconUrl(block.callout.icon.icon);
|
|
97
|
-
try {
|
|
98
|
-
const ipws = await saveImage(url, `block-${block.id}`);
|
|
99
|
-
block.callout.icon = { type: 'external', external: { url }, src: ipws.path };
|
|
100
|
-
}
|
|
101
|
-
catch (e) {
|
|
102
|
-
if (debug) {
|
|
103
|
-
console.log(`Failed to save callout icon: ${e}`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
49
|
+
// A result that misses something because of a transient failure, such as
|
|
50
|
+
// a rate limit or a download that timed out, is not cached, so that the
|
|
51
|
+
// next call fetches it again instead of keeping the gap.
|
|
52
|
+
const { value: allres, complete } = await collectFailures(async () => {
|
|
53
|
+
const { value: allres, dependencies } = await collectDependencies(async () => {
|
|
54
|
+
let allres;
|
|
55
|
+
let res;
|
|
56
|
+
let params = { block_id, start_cursor: undefined };
|
|
57
|
+
while (true) {
|
|
58
|
+
if (res && res.next_cursor) {
|
|
59
|
+
params.start_cursor = res.next_cursor;
|
|
106
60
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
case 'child_database':
|
|
112
|
-
// if (block.has_children) {
|
|
113
|
-
const database_id = block.id;
|
|
114
|
-
block.database = await reqAPIWithBackoffAndCache({
|
|
115
|
-
name: 'notion.databases.retrieve',
|
|
116
|
-
func: notion.databases.retrieve,
|
|
117
|
-
args: { database_id },
|
|
118
|
-
count: 3,
|
|
61
|
+
res = await reqAPIWithBackoff({
|
|
62
|
+
func: notion().blocks.children.list,
|
|
63
|
+
args: params,
|
|
64
|
+
count: 3
|
|
119
65
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
case 'child_page':
|
|
123
|
-
block.page = await FetchPage({ page_id: block.id, last_edited_time: block.last_edited_time });
|
|
124
|
-
// Unnecessary?
|
|
125
|
-
// block.children = await FetchBlocks(block.id, block.last_edited_time)
|
|
126
|
-
break;
|
|
127
|
-
case 'column_list':
|
|
128
|
-
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
129
|
-
block.columns = [];
|
|
130
|
-
for (const b of block.children.results) {
|
|
131
|
-
block.columns.push(await FetchBlocks({ block_id: b.id, last_edited_time: last_edited_time ?? b.last_edited_time }));
|
|
66
|
+
if (allres === undefined) {
|
|
67
|
+
allres = res;
|
|
132
68
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
block.embed.html = await getEmbedHtml(block);
|
|
136
|
-
break;
|
|
137
|
-
case 'image':
|
|
138
|
-
const { id, image } = block;
|
|
139
|
-
if (image !== undefined) {
|
|
140
|
-
const imageUrl = image.type === 'file' ? image.file.url : image.external.url;
|
|
141
|
-
try {
|
|
142
|
-
const ipws = await saveImage(imageUrl, `block-${id}`);
|
|
143
|
-
block.image.src = ipws.path;
|
|
144
|
-
if (ipws.width) {
|
|
145
|
-
block.image.width = ipws.width;
|
|
146
|
-
}
|
|
147
|
-
if (ipws.height) {
|
|
148
|
-
block.image.height = ipws.height;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
catch (e) {
|
|
152
|
-
if (debug) {
|
|
153
|
-
console.log(`Failed to save image: ${e}`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
69
|
+
else {
|
|
70
|
+
allres.results.push(...res.results);
|
|
156
71
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (block.has_children) {
|
|
160
|
-
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
72
|
+
if (res.next_cursor === null) {
|
|
73
|
+
break;
|
|
161
74
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
75
|
+
}
|
|
76
|
+
// With the blocks api, you can get the last modified date of a block,
|
|
77
|
+
// but not the last modified date of all blocks. So extend the type and add it.
|
|
78
|
+
if (last_edited_time) {
|
|
79
|
+
allres.last_edited_time = last_edited_time;
|
|
80
|
+
}
|
|
81
|
+
// Editing a nested block does not update its parent block's last_edited_time,
|
|
82
|
+
// only the page's. So pass the page's last_edited_time down to nested blocks.
|
|
83
|
+
for (const block of allres.results) {
|
|
84
|
+
try {
|
|
85
|
+
const { type } = block;
|
|
86
|
+
switch (type) {
|
|
87
|
+
case 'bookmark':
|
|
88
|
+
block.bookmark.site = await getHtmlMeta(block.bookmark.url);
|
|
89
|
+
break;
|
|
90
|
+
case 'bulleted_list_item':
|
|
91
|
+
if (block.has_children) {
|
|
92
|
+
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
case 'breadcrumb':
|
|
96
|
+
block.list = await FetchBreadcrumbs({ id: block_id, type: 'page_id' });
|
|
97
|
+
break;
|
|
98
|
+
case 'callout':
|
|
99
|
+
if (block.callout.icon?.type === 'external') {
|
|
100
|
+
const iconUrl = block.callout.icon.external.url;
|
|
101
|
+
try {
|
|
102
|
+
const ipws = await saveImage(iconUrl, `block-${block.id}`);
|
|
103
|
+
block.callout.icon.src = ipws.path;
|
|
182
104
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
105
|
+
catch (e) {
|
|
106
|
+
reportFailure(`icon of callout block ${block.id}`, e);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (block.callout.icon?.type === 'icon') {
|
|
110
|
+
const url = getNotionIconUrl(block.callout.icon.icon);
|
|
111
|
+
try {
|
|
112
|
+
const ipws = await saveImage(url, `block-${block.id}`);
|
|
113
|
+
block.callout.icon = { type: 'external', external: { url }, src: ipws.path };
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
reportFailure(`icon of callout block ${block.id}`, e);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (block.has_children) {
|
|
120
|
+
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
case 'child_database':
|
|
124
|
+
// if (block.has_children) {
|
|
125
|
+
const database_id = block.id;
|
|
126
|
+
block.database = await reqAPIWithBackoffAndCache({
|
|
127
|
+
name: 'notion.databases.retrieve',
|
|
128
|
+
func: notion().databases.retrieve,
|
|
129
|
+
args: { database_id },
|
|
130
|
+
count: 3,
|
|
131
|
+
});
|
|
132
|
+
recordDependency({ type: 'database', id: database_id, last_edited_time: block.database.last_edited_time });
|
|
133
|
+
// }
|
|
134
|
+
break;
|
|
135
|
+
case 'child_page':
|
|
136
|
+
{
|
|
137
|
+
// The title and icon come from the child page; its own
|
|
138
|
+
// last_edited_time tells whether they changed
|
|
139
|
+
const edited = await editedTimeOf('page', block.id);
|
|
140
|
+
recordDependency({ type: 'page', id: block.id, last_edited_time: edited });
|
|
141
|
+
block.page = await FetchPage({ page_id: block.id, last_edited_time: edited });
|
|
142
|
+
}
|
|
143
|
+
// Unnecessary?
|
|
144
|
+
// block.children = await FetchBlocks(block.id, block.last_edited_time)
|
|
145
|
+
break;
|
|
146
|
+
case 'column_list':
|
|
147
|
+
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
148
|
+
block.columns = [];
|
|
149
|
+
for (const b of block.children.results) {
|
|
150
|
+
block.columns.push(await FetchBlocks({ block_id: b.id, last_edited_time: last_edited_time ?? b.last_edited_time }));
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
case 'embed':
|
|
154
|
+
block.embed.html = await getEmbedHtml(block);
|
|
155
|
+
break;
|
|
156
|
+
case 'image':
|
|
157
|
+
const { id, image } = block;
|
|
158
|
+
if (image !== undefined) {
|
|
159
|
+
const imageUrl = image.type === 'file' ? image.file.url : image.external.url;
|
|
160
|
+
try {
|
|
161
|
+
const ipws = await saveImage(imageUrl, `block-${id}`);
|
|
162
|
+
block.image.src = ipws.path;
|
|
163
|
+
if (ipws.width) {
|
|
164
|
+
block.image.width = ipws.width;
|
|
188
165
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
console.log(`Failed to save database icon: ${e}`);
|
|
192
|
-
}
|
|
166
|
+
if (ipws.height) {
|
|
167
|
+
block.image.height = ipws.height;
|
|
193
168
|
}
|
|
194
169
|
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
reportFailure(`image of block ${id}`, e);
|
|
172
|
+
}
|
|
195
173
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
174
|
+
break;
|
|
175
|
+
case 'numbered_list_item':
|
|
176
|
+
if (block.has_children) {
|
|
177
|
+
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
case 'paragraph':
|
|
181
|
+
for (const richText of block.paragraph.rich_text) {
|
|
182
|
+
if (richText.type !== 'mention') {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const mention = richText.mention;
|
|
186
|
+
switch (mention.type) {
|
|
187
|
+
case 'database':
|
|
188
|
+
try {
|
|
189
|
+
const database_id = mention.database.id;
|
|
190
|
+
const db = await reqAPIWithBackoffAndCache({
|
|
191
|
+
name: 'notion.databases.retrieve',
|
|
192
|
+
func: notion().databases.retrieve,
|
|
193
|
+
args: { database_id },
|
|
194
|
+
count: 3,
|
|
195
|
+
});
|
|
196
|
+
recordDependency({ type: 'database', id: database_id, last_edited_time: db.last_edited_time });
|
|
197
|
+
mention.database.name = db.title.map(v => v.plain_text).join('');
|
|
198
|
+
if (db.icon?.type === 'emoji') {
|
|
199
|
+
mention.database.icon = { type: 'emoji', emoji: db.icon.emoji };
|
|
200
|
+
}
|
|
201
|
+
else if (db.icon?.type === 'external' || db.icon?.type === 'file') {
|
|
202
|
+
const iconUrl = (db.icon.type === 'external') ? db.icon.external.url : db.icon.file.url;
|
|
203
|
+
try {
|
|
204
|
+
const ipws = await saveImage(iconUrl, `block-${block.id}`);
|
|
205
|
+
mention.database.icon = { type: db.icon.type, src: ipws.path, url: ipws.path };
|
|
206
|
+
}
|
|
207
|
+
catch (e) {
|
|
208
|
+
reportFailure(`icon of the database mentioned in block ${block.id}`, e);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (e) {
|
|
213
|
+
reportFailure(`database mentioned in block ${block.id}`, e);
|
|
214
|
+
mention.database.name = '--';
|
|
215
|
+
mention.database.icon = { type: 'emoji', emoji: '@' };
|
|
216
|
+
}
|
|
217
|
+
break;
|
|
218
|
+
case 'page':
|
|
219
|
+
try {
|
|
220
|
+
const page_id = mention.page.id;
|
|
221
|
+
const page = await reqAPIWithBackoff({
|
|
222
|
+
func: notion().pages.retrieve,
|
|
223
|
+
args: { page_id },
|
|
224
|
+
count: 3,
|
|
225
|
+
});
|
|
226
|
+
recordDependency({ type: 'page', id: page_id, last_edited_time: page.last_edited_time });
|
|
227
|
+
for (const prop of Object.values(page.properties)) {
|
|
228
|
+
if (prop.type === 'title') {
|
|
229
|
+
mention.page.name = prop.title.map(v => v.plain_text).join('');
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (page.icon?.type === 'emoji') {
|
|
234
|
+
mention.page.icon = {
|
|
235
|
+
type: page.icon.type,
|
|
236
|
+
emoji: page.icon.emoji,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
else if (page.icon?.type === 'external' || page.icon?.type === 'file') {
|
|
240
|
+
const iconUrl = (page.icon.type === 'external') ? page.icon.external.url : page.icon.file.url;
|
|
241
|
+
try {
|
|
242
|
+
const ipws = await saveImage(iconUrl, `block-${block.id}`);
|
|
243
|
+
mention.page.icon = {
|
|
244
|
+
type: page.icon.type,
|
|
245
|
+
src: ipws.path,
|
|
246
|
+
url: ipws.path,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
catch (e) {
|
|
250
|
+
reportFailure(`icon of the page mentioned in block ${block.id}`, e);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch (e) {
|
|
255
|
+
reportFailure(`page mentioned in block ${block.id}`, e);
|
|
256
|
+
mention.page.name = '--';
|
|
257
|
+
mention.page.icon = { type: 'emoji', emoji: '@' };
|
|
258
|
+
}
|
|
259
|
+
break;
|
|
199
260
|
}
|
|
200
|
-
mention.database.name = '--';
|
|
201
|
-
mention.database.icon = { type: 'emoji', emoji: '@' };
|
|
202
261
|
}
|
|
203
262
|
break;
|
|
204
|
-
case '
|
|
263
|
+
case 'file': {
|
|
264
|
+
const url = block.file.type === 'external' ? block.file.external.url : block.file.file.url;
|
|
205
265
|
try {
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
266
|
+
const { src, size } = await saveFile(url, `block-${block.id}`);
|
|
267
|
+
block.file.src = src;
|
|
268
|
+
block.file.size = size;
|
|
269
|
+
}
|
|
270
|
+
catch (e) {
|
|
271
|
+
reportFailure(`file of block ${block.id}`, e);
|
|
272
|
+
}
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
case 'pdf': {
|
|
276
|
+
const url = block.pdf.type === 'external' ? block.pdf.external.url : block.pdf.file.url;
|
|
277
|
+
try {
|
|
278
|
+
const { src, size } = await saveFile(url, `block-${block.id}`);
|
|
279
|
+
block.pdf.src = src;
|
|
280
|
+
block.pdf.size = size;
|
|
281
|
+
}
|
|
282
|
+
catch (e) {
|
|
283
|
+
reportFailure(`PDF of block ${block.id}`, e);
|
|
284
|
+
}
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
case 'synced_block':
|
|
288
|
+
if (block.has_children) {
|
|
289
|
+
if (block.synced_block.synced_from === null) {
|
|
290
|
+
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
291
|
+
}
|
|
292
|
+
else if (block.synced_block.synced_from.type === 'block_id') {
|
|
293
|
+
const block_id = block.synced_block.synced_from.block_id;
|
|
294
|
+
// The source is edited in its own page, which does not change
|
|
295
|
+
// the last_edited_time of this one. Cache its blocks with the
|
|
296
|
+
// time of that page, the same key the page itself uses.
|
|
297
|
+
const sourcePage = await pageOfBlock(block_id);
|
|
298
|
+
let sourceEdited;
|
|
299
|
+
if (sourcePage !== undefined) {
|
|
300
|
+
sourceEdited = await editedTimeOf('page', sourcePage);
|
|
301
|
+
recordDependency({ type: 'page', id: sourcePage, last_edited_time: sourceEdited });
|
|
216
302
|
}
|
|
303
|
+
block.children = await FetchBlocks({ block_id, last_edited_time: sourceEdited ?? last_edited_time ?? block.last_edited_time });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
break;
|
|
307
|
+
case 'table':
|
|
308
|
+
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
309
|
+
break;
|
|
310
|
+
case 'toggle':
|
|
311
|
+
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
312
|
+
break;
|
|
313
|
+
case 'video':
|
|
314
|
+
if (block.video.type === 'file') {
|
|
315
|
+
try {
|
|
316
|
+
const { src } = await saveFile(block.video.file.url, `block-${block.id}`);
|
|
317
|
+
block.video.src = src;
|
|
318
|
+
block.video.videoType = getVideoType(src);
|
|
217
319
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
type: page.icon.type,
|
|
221
|
-
emoji: page.icon.emoji,
|
|
222
|
-
};
|
|
320
|
+
catch (e) {
|
|
321
|
+
reportFailure(`video of block ${block.id}`, e);
|
|
223
322
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
323
|
+
}
|
|
324
|
+
else if (block.video.type === 'external') {
|
|
325
|
+
block.video.html = await getVideoHtml(block);
|
|
326
|
+
}
|
|
327
|
+
break;
|
|
328
|
+
case 'link_preview':
|
|
329
|
+
const { url } = block.link_preview;
|
|
330
|
+
if (url.includes('figma.com')) {
|
|
331
|
+
// https://www.figma.com/file/GfHZFRpWGd0QXsRg9igdw8/Google-Material-Design?node-id=0%3A1
|
|
332
|
+
block.link_preview.figma = {
|
|
333
|
+
html: `<iframe style="border: 1px solid rgba(0, 0, 0, 0.1);" width="100%" height="450" src="https://www.figma.com/embed?embed_host=share&url=${encodeURI(url)}" allowfullscreen></iframe>`
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
else if (url.includes('github.com')) {
|
|
337
|
+
// Like bookmarks and embeds, the preview comes from a third party,
|
|
338
|
+
// so GitHub being unavailable does not keep the whole page out of
|
|
339
|
+
// the cache.
|
|
340
|
+
try {
|
|
341
|
+
const u = new URL(url).pathname;
|
|
342
|
+
if (u.split('/').length > 1) {
|
|
343
|
+
const [owner, repo, type, num] = u.split('/').slice(1);
|
|
344
|
+
if (owner && repo && (type === 'issues' || type === 'pull') && num) {
|
|
345
|
+
const res = await getIssueForLinkPreview({ owner, repo, number: num });
|
|
346
|
+
block.link_preview.github = {
|
|
347
|
+
type: 'issue',
|
|
348
|
+
issue: res,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
else if (owner && repo) {
|
|
352
|
+
const res = await getRepoForLinkPreview({ owner, repo });
|
|
353
|
+
block.link_preview.github = {
|
|
354
|
+
type: 'repo',
|
|
355
|
+
repo: res,
|
|
356
|
+
};
|
|
237
357
|
}
|
|
238
358
|
}
|
|
239
359
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if (debug) {
|
|
243
|
-
console.log(`page mention is unsupported ${block.type}`, block, e);
|
|
360
|
+
catch (e) {
|
|
361
|
+
reportExtraFailure(`GitHub preview of block ${block.id}`, e);
|
|
244
362
|
}
|
|
245
|
-
|
|
246
|
-
|
|
363
|
+
}
|
|
364
|
+
break;
|
|
365
|
+
case 'audio':
|
|
366
|
+
case 'code':
|
|
367
|
+
case 'column':
|
|
368
|
+
case 'divider':
|
|
369
|
+
case 'equation':
|
|
370
|
+
case 'heading_1':
|
|
371
|
+
case 'heading_2':
|
|
372
|
+
case 'heading_3':
|
|
373
|
+
case 'link_to_page':
|
|
374
|
+
case 'quote':
|
|
375
|
+
case 'table_of_contents':
|
|
376
|
+
case 'table_row':
|
|
377
|
+
case 'template':
|
|
378
|
+
case 'to_do':
|
|
379
|
+
case 'unsupported':
|
|
380
|
+
break;
|
|
381
|
+
default:
|
|
382
|
+
if (debug) {
|
|
383
|
+
console.log(`unknown block error`, block);
|
|
247
384
|
}
|
|
248
385
|
break;
|
|
249
386
|
}
|
|
250
387
|
}
|
|
251
|
-
break;
|
|
252
|
-
case 'file': {
|
|
253
|
-
const url = block.file.type === 'external' ? block.file.external.url : block.file.file.url;
|
|
254
|
-
try {
|
|
255
|
-
const { src, size } = await saveFile(url, `block-${block.id}`);
|
|
256
|
-
block.file.src = src;
|
|
257
|
-
block.file.size = size;
|
|
258
|
-
}
|
|
259
|
-
catch (e) {
|
|
260
|
-
if (debug) {
|
|
261
|
-
console.log(`Failed to save file: ${e}`);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
break;
|
|
265
|
-
}
|
|
266
|
-
case 'pdf': {
|
|
267
|
-
const url = block.pdf.type === 'external' ? block.pdf.external.url : block.pdf.file.url;
|
|
268
|
-
try {
|
|
269
|
-
const { src, size } = await saveFile(url, `block-${block.id}`);
|
|
270
|
-
block.pdf.src = src;
|
|
271
|
-
block.pdf.size = size;
|
|
272
|
-
}
|
|
273
388
|
catch (e) {
|
|
274
|
-
|
|
275
|
-
console.log(`Failed to save PDF: ${e}`);
|
|
276
|
-
}
|
|
389
|
+
reportFailure(`contents of ${block.type} block ${block.id}`, e);
|
|
277
390
|
}
|
|
278
|
-
break;
|
|
279
391
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
else if (block.synced_block.synced_from.type === 'block_id') {
|
|
286
|
-
const block_id = block.synced_block.synced_from.block_id;
|
|
287
|
-
block.children = await FetchBlocks({ block_id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
break;
|
|
291
|
-
case 'table':
|
|
292
|
-
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
293
|
-
break;
|
|
294
|
-
case 'toggle':
|
|
295
|
-
block.children = await FetchBlocks({ block_id: block.id, last_edited_time: last_edited_time ?? block.last_edited_time });
|
|
296
|
-
break;
|
|
297
|
-
case 'video':
|
|
298
|
-
if (block.video.type === 'file') {
|
|
299
|
-
try {
|
|
300
|
-
const { src } = await saveFile(block.video.file.url, `block-${block.id}`);
|
|
301
|
-
block.video.src = src;
|
|
302
|
-
block.video.videoType = getVideoType(src);
|
|
303
|
-
}
|
|
304
|
-
catch (e) {
|
|
305
|
-
if (debug) {
|
|
306
|
-
console.log(`Failed to save video: ${e}`);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
else if (block.video.type === 'external') {
|
|
311
|
-
block.video.html = await getVideoHtml(block);
|
|
312
|
-
}
|
|
313
|
-
break;
|
|
314
|
-
case 'link_preview':
|
|
315
|
-
const { url } = block.link_preview;
|
|
316
|
-
if (url.includes('figma.com')) {
|
|
317
|
-
// https://www.figma.com/file/GfHZFRpWGd0QXsRg9igdw8/Google-Material-Design?node-id=0%3A1
|
|
318
|
-
block.link_preview.figma = {
|
|
319
|
-
html: `<iframe style="border: 1px solid rgba(0, 0, 0, 0.1);" width="100%" height="450" src="https://www.figma.com/embed?embed_host=share&url=${encodeURI(url)}" allowfullscreen></iframe>`
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
else if (url.includes('github.com')) {
|
|
323
|
-
const u = new URL(url).pathname;
|
|
324
|
-
if (u.split('/').length > 1) {
|
|
325
|
-
const [owner, repo, type, num] = u.split('/').slice(1);
|
|
326
|
-
if (owner && repo && (type === 'issues' || type === 'pull') && num) {
|
|
327
|
-
const res = await getIssueForLinkPreview({ owner, repo, number: num });
|
|
328
|
-
block.link_preview.github = {
|
|
329
|
-
type: 'issue',
|
|
330
|
-
issue: res,
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
else if (owner && repo) {
|
|
334
|
-
const res = await getRepoForLinkPreview({ owner, repo });
|
|
335
|
-
block.link_preview.github = {
|
|
336
|
-
type: 'repo',
|
|
337
|
-
repo: res,
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
break;
|
|
343
|
-
case 'audio':
|
|
344
|
-
case 'code':
|
|
345
|
-
case 'column':
|
|
346
|
-
case 'divider':
|
|
347
|
-
case 'equation':
|
|
348
|
-
case 'heading_1':
|
|
349
|
-
case 'heading_2':
|
|
350
|
-
case 'heading_3':
|
|
351
|
-
case 'link_to_page':
|
|
352
|
-
case 'quote':
|
|
353
|
-
case 'table_of_contents':
|
|
354
|
-
case 'table_row':
|
|
355
|
-
case 'template':
|
|
356
|
-
case 'to_do':
|
|
357
|
-
case 'unsupported':
|
|
358
|
-
break;
|
|
359
|
-
default:
|
|
360
|
-
if (debug) {
|
|
361
|
-
console.log(`unknown block error`, block);
|
|
362
|
-
}
|
|
363
|
-
break;
|
|
392
|
+
return allres;
|
|
393
|
+
});
|
|
394
|
+
if (dependencies.length > 0) {
|
|
395
|
+
allres.dependencies = dependencies;
|
|
364
396
|
}
|
|
397
|
+
return allres;
|
|
398
|
+
});
|
|
399
|
+
if (complete) {
|
|
400
|
+
await writeCache(cacheFile, allres);
|
|
365
401
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
console.log(`error for ${block.type} contents get`, block, e);
|
|
369
|
-
}
|
|
402
|
+
else {
|
|
403
|
+
warn(`not caching the blocks of ${block_id} because of a transient failure; they are fetched again on the next call`);
|
|
370
404
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
return allres;
|
|
405
|
+
return allres;
|
|
406
|
+
});
|
|
374
407
|
};
|
|
375
408
|
//# sourceMappingURL=blocks.js.map
|