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.
Files changed (56) hide show
  1. package/README.ja.md +20 -12
  2. package/README.md +26 -17
  3. package/dist/exporter/api.d.ts +11 -1
  4. package/dist/exporter/api.js +35 -30
  5. package/dist/exporter/api.js.map +1 -1
  6. package/dist/exporter/bin.d.ts +2 -0
  7. package/dist/exporter/bin.js +4 -0
  8. package/dist/exporter/bin.js.map +1 -0
  9. package/dist/exporter/blocks.js +355 -322
  10. package/dist/exporter/blocks.js.map +1 -1
  11. package/dist/exporter/breadcrumbs.js +3 -3
  12. package/dist/exporter/breadcrumbs.js.map +1 -1
  13. package/dist/exporter/cli.d.ts +16 -0
  14. package/dist/exporter/cli.js +126 -0
  15. package/dist/exporter/cli.js.map +1 -0
  16. package/dist/exporter/database.js +82 -75
  17. package/dist/exporter/database.js.map +1 -1
  18. package/dist/exporter/dependencies.d.ts +38 -0
  19. package/dist/exporter/dependencies.js +102 -0
  20. package/dist/exporter/dependencies.js.map +1 -0
  21. package/dist/exporter/failures.d.ts +52 -0
  22. package/dist/exporter/failures.js +105 -0
  23. package/dist/exporter/failures.js.map +1 -0
  24. package/dist/exporter/files.d.ts +21 -0
  25. package/dist/exporter/files.js +164 -94
  26. package/dist/exporter/files.js.map +1 -1
  27. package/dist/exporter/github.d.ts +8 -0
  28. package/dist/exporter/github.js +22 -5
  29. package/dist/exporter/github.js.map +1 -1
  30. package/dist/exporter/index.d.ts +4 -0
  31. package/dist/exporter/index.js +2 -0
  32. package/dist/exporter/index.js.map +1 -1
  33. package/dist/exporter/log.d.ts +6 -0
  34. package/dist/exporter/log.js +15 -0
  35. package/dist/exporter/log.js.map +1 -0
  36. package/dist/exporter/mutex.js +55 -16
  37. package/dist/exporter/mutex.js.map +1 -1
  38. package/dist/exporter/page.js +51 -35
  39. package/dist/exporter/page.js.map +1 -1
  40. package/dist/exporter/prune.d.ts +27 -0
  41. package/dist/exporter/prune.js +95 -0
  42. package/dist/exporter/prune.js.map +1 -0
  43. package/dist/exporter/types.d.ts +13 -0
  44. package/dist/exporter/variables.d.ts +61 -17
  45. package/dist/exporter/variables.js +86 -23
  46. package/dist/exporter/variables.js.map +1 -1
  47. package/dist/ui/components/Gallery/GalleryCard/options.d.ts +11 -0
  48. package/dist/ui/esm/components/Gallery/GalleryCard/GalleryCard.js +2 -17
  49. package/dist/ui/esm/components/Gallery/GalleryCard/GalleryCard.js.map +1 -1
  50. package/dist/ui/esm/components/Gallery/GalleryCard/options.js +27 -0
  51. package/dist/ui/esm/components/Gallery/GalleryCard/options.js.map +1 -0
  52. package/dist/ui/esm/components/Page/CodeBlock/Code/Code.js +5 -0
  53. package/dist/ui/esm/components/Page/CodeBlock/Code/Code.js.map +1 -1
  54. package/dist/ui/index-without-dark.css +1 -1
  55. package/dist/ui/index.css +1 -1
  56. package/package.json +32 -25
@@ -1,15 +1,32 @@
1
1
  import { fetchWithTimeout } from './api.js';
2
2
  import { saveImage } from './files.js';
3
- import { debug } from './variables.js';
3
+ import { config } from './variables.js';
4
+ import { HTTPStatusError } from './failures.js';
4
5
  const reqInit = {
5
6
  headers: {
6
7
  'Accept': 'application/vnd.github+json',
7
8
  'X-GitHub-Api-Version': '2022-11-28',
8
9
  }
9
10
  };
11
+ /**
12
+ * fetchGitHub returns the JSON body of a successful response from the GitHub
13
+ * API. Any other status throws an HTTPStatusError, instead of handing an
14
+ * error message to a caller that expects a repository or an issue. A request
15
+ * over the rate limit (403 or 429 with no requests remaining) is reported as
16
+ * 429, because it succeeds once the limit resets.
17
+ */
18
+ export async function fetchGitHub(url) {
19
+ const res = await fetchWithTimeout(url, reqInit);
20
+ if (!res.ok) {
21
+ await res.body?.cancel();
22
+ const limited = (res.status === 403 || res.status === 429) && res.headers.get('x-ratelimit-remaining') === '0';
23
+ throw new HTTPStatusError(limited ? 429 : res.status, url);
24
+ }
25
+ return await res.json();
26
+ }
10
27
  export async function getRepo({ owner, repo }, func) {
11
28
  const url = `https://api.github.com/repos/${owner}/${repo}`;
12
- return (func) ? func(url, reqInit) : (await fetchWithTimeout(url, reqInit)).json();
29
+ return (func) ? func(url, reqInit) : fetchGitHub(url);
13
30
  }
14
31
  export async function getRepoForLinkPreview({ owner, repo }, func) {
15
32
  const res = await getRepo({ owner, repo }, func);
@@ -20,7 +37,7 @@ export async function getRepoForLinkPreview({ owner, repo }, func) {
20
37
  avatar_src = ipws.path;
21
38
  }
22
39
  catch (e) {
23
- if (debug) {
40
+ if (config().debug) {
24
41
  console.log(`Failed to save github avatar: ${e}`);
25
42
  }
26
43
  }
@@ -34,7 +51,7 @@ export async function getRepoForLinkPreview({ owner, repo }, func) {
34
51
  }
35
52
  export async function getIssue({ owner, repo, number }, func) {
36
53
  const url = `https://api.github.com/repos/${owner}/${repo}/issues/${number}`;
37
- return func ? func(url, reqInit) : (await fetchWithTimeout(url, reqInit)).json();
54
+ return func ? func(url, reqInit) : fetchGitHub(url);
38
55
  }
39
56
  export async function getIssueForLinkPreview({ owner, repo, number }, func) {
40
57
  const res = await getIssue({ owner, repo, number }, func);
@@ -46,7 +63,7 @@ export async function getIssueForLinkPreview({ owner, repo, number }, func) {
46
63
  avatar_src = ipws.path;
47
64
  }
48
65
  catch (e) {
49
- if (debug) {
66
+ if (config().debug) {
50
67
  console.log(`Failed to save github avatar: ${e}`);
51
68
  }
52
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/exporter/github.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/exporter/github.ts"],"names":[],"mappings":"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"}
@@ -4,3 +4,7 @@ export * from './page.js';
4
4
  export * from './types.js';
5
5
  export * from './breadcrumbs.js';
6
6
  export * from './validation.js';
7
+ export { configure } from './variables.js';
8
+ export type { RotionConfig } from './variables.js';
9
+ export { pruneCache } from './prune.js';
10
+ export type { PruneCacheArgs, PruneCacheRes } from './prune.js';
@@ -4,4 +4,6 @@ export * from './page.js';
4
4
  export * from './types.js';
5
5
  export * from './breadcrumbs.js';
6
6
  export * from './validation.js';
7
+ export { configure } from './variables.js';
8
+ export { pruneCache } from './prune.js';
7
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exporter/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exporter/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * warn prints one line to stderr for something that makes the output
3
+ * incomplete or slower, whether or not ROTION_DEBUG is set. Only the first
4
+ * line of the error message is printed; ROTION_DEBUG adds the whole error.
5
+ */
6
+ export declare function warn(message: string, error?: unknown): void;
@@ -0,0 +1,15 @@
1
+ import { config } from './variables.js';
2
+ const messageOf = (error) => error instanceof Error ? error.message : String(error);
3
+ /**
4
+ * warn prints one line to stderr for something that makes the output
5
+ * incomplete or slower, whether or not ROTION_DEBUG is set. Only the first
6
+ * line of the error message is printed; ROTION_DEBUG adds the whole error.
7
+ */
8
+ export function warn(message, error) {
9
+ const reason = error === undefined ? '' : `: ${messageOf(error).split('\n')[0]}`;
10
+ console.warn(`[rotion] ${message}${reason}`);
11
+ if (config().debug && error !== undefined) {
12
+ console.warn(error);
13
+ }
14
+ }
15
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/exporter/log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC,MAAM,SAAS,GAAG,CAAC,KAAc,EAAU,EAAE,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAEpG;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAE,OAAe,EAAE,KAAe;IACpD,MAAM,MAAM,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAChF,OAAO,CAAC,IAAI,CAAC,YAAY,OAAO,GAAG,MAAM,EAAE,CAAC,CAAA;IAC5C,IAAI,MAAM,EAAE,CAAC,KAAK,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC;AACH,CAAC"}
@@ -1,6 +1,8 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import path from 'path';
3
- import { cacheDir, debug } from './variables.js';
3
+ import os from 'os';
4
+ import { config } from './variables.js';
5
+ import { warn } from './log.js';
4
6
  const DEFAULT_OPTIONS = {
5
7
  timeout: 600000, // 10 minutes — must accommodate long operations like
6
8
  // FetchDatabase that wrap many sequential image downloads
@@ -16,7 +18,7 @@ const DEFAULT_OPTIONS = {
16
18
  */
17
19
  export async function withFileLock(key, operation, options = {}) {
18
20
  const opts = { ...DEFAULT_OPTIONS, ...options };
19
- const lockDir = path.join(cacheDir, 'locks');
21
+ const lockDir = path.join(config().cacheDir, 'locks');
20
22
  const lockFile = path.join(lockDir, `${key}.lock`);
21
23
  await fs.mkdir(lockDir, { recursive: true });
22
24
  const startTime = Date.now();
@@ -24,17 +26,18 @@ export async function withFileLock(key, operation, options = {}) {
24
26
  while (Date.now() - startTime < opts.timeout) {
25
27
  try {
26
28
  // Cleanup stale lock files
27
- await cleanupStaleLock(lockFile, opts.maxAge);
29
+ await cleanupStaleLock(lockFile, opts.maxAge, opts.operationTimeout);
28
30
  // Create lock file exclusively
29
31
  fd = await fs.open(lockFile, 'wx');
30
- // Write process ID and timestamp
32
+ // Write process ID, host and timestamp
31
33
  const lockData = JSON.stringify({
32
34
  pid: process.pid,
35
+ hostname: os.hostname(),
33
36
  timestamp: Date.now(),
34
37
  key
35
38
  });
36
39
  await fd.writeFile(lockData);
37
- if (debug) {
40
+ if (config().debug) {
38
41
  console.log(`Lock acquired: ${key} (pid: ${process.pid})`);
39
42
  }
40
43
  // Execute operation, bounded by operationTimeout so a hanging
@@ -62,18 +65,37 @@ export async function withFileLock(key, operation, options = {}) {
62
65
  /**
63
66
  * Cleanup stale lock files
64
67
  */
65
- async function cleanupStaleLock(lockFile, maxAge) {
68
+ async function cleanupStaleLock(lockFile, maxAge, operationTimeout) {
66
69
  try {
67
70
  const stats = await fs.stat(lockFile);
68
71
  const age = Date.now() - stats.mtime.getTime();
69
72
  if (age > maxAge) {
70
- const lockData = await fs.readFile(lockFile, 'utf-8');
71
- const lock = JSON.parse(lockData);
72
- // Check if process is alive
73
- if (!isProcessAlive(lock.pid)) {
73
+ const { pid, hostname } = await readLockHolder(lockFile);
74
+ // A lock holder writes its pid right after creating the file, so a lock
75
+ // older than maxAge without a readable pid was left by a process that
76
+ // died in between. Nothing will ever remove it, and without this it
77
+ // would hold every waiter until the timeout.
78
+ let reason;
79
+ if (pid === undefined) {
80
+ reason = 'no readable pid';
81
+ }
82
+ else if (hostname !== undefined && hostname !== os.hostname()) {
83
+ // A pid means nothing on another host that shares the cache directory
84
+ // (a volume shared by containers, for example): it may belong to an
85
+ // unrelated process here, or to none. The holder releases the lock
86
+ // within operationTimeout, so only a lock older than that is left
87
+ // behind.
88
+ if (age > operationTimeout) {
89
+ reason = `held by ${hostname} for longer than ${operationTimeout}ms`;
90
+ }
91
+ }
92
+ else if (!isProcessAlive(pid)) {
93
+ reason = `dead pid: ${pid}`;
94
+ }
95
+ if (reason !== undefined) {
74
96
  await fs.unlink(lockFile);
75
- if (debug) {
76
- console.log(`Cleaned up stale lock: ${lockFile} (dead pid: ${lock.pid})`);
97
+ if (config().debug) {
98
+ console.log(`Cleaned up stale lock: ${lockFile} (${reason})`);
77
99
  }
78
100
  }
79
101
  }
@@ -82,6 +104,24 @@ async function cleanupStaleLock(lockFile, maxAge) {
82
104
  // Ignore if file doesn't exist or can't be read
83
105
  }
84
106
  }
107
+ /**
108
+ * Read the pid and host a lock file was written with. Either is undefined
109
+ * when the file is empty or does not hold it; a lock written before the host
110
+ * was recorded is taken as one from this host.
111
+ */
112
+ async function readLockHolder(lockFile) {
113
+ const lockData = await fs.readFile(lockFile, 'utf-8');
114
+ try {
115
+ const { pid, hostname } = JSON.parse(lockData);
116
+ return {
117
+ pid: Number.isInteger(pid) ? pid : undefined,
118
+ hostname: typeof hostname === 'string' ? hostname : undefined,
119
+ };
120
+ }
121
+ catch {
122
+ return {};
123
+ }
124
+ }
85
125
  /**
86
126
  * Check if process is alive
87
127
  */
@@ -126,14 +166,13 @@ async function releaseLock(fd, lockFile, key) {
126
166
  try {
127
167
  await fd.close();
128
168
  await fs.unlink(lockFile);
129
- if (debug) {
169
+ if (config().debug) {
130
170
  console.log(`Lock released: ${key} (pid: ${process.pid})`);
131
171
  }
132
172
  }
133
173
  catch (error) {
134
- if (debug) {
135
- console.error(`Failed to release lock: ${key}`, error);
136
- }
174
+ // A lock file left behind makes the next caller wait until it is stale
175
+ warn(`failed to release the lock ${lockFile}`, error);
137
176
  }
138
177
  }
139
178
  //# sourceMappingURL=mutex.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mutex.js","sourceRoot":"","sources":["../../src/exporter/mutex.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mutex.js","sourceRoot":"","sources":["../../src/exporter/mutex.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,20 @@
1
1
  import { reqAPIWithBackoff, reqAPIWithBackoffAndCache, notion, } from './api.js';
2
- import { cacheDir, incrementalCache, debug, } from './variables.js';
2
+ import { config } from './variables.js';
3
3
  import { createDirWhenNotfound, saveImage, readCache, writeCache, isEmpty, } from './files.js';
4
4
  import { withFileLock } from './mutex.js';
5
+ import { collectFailures, reportFailure } from './failures.js';
6
+ import { warn } from './log.js';
7
+ // Only these property types answer pages.properties.retrieve with a list,
8
+ // which is what page.meta collects. Any other type answers with a single
9
+ // item, which page.meta leaves out, so asking for it would be a wasted request.
10
+ const listPropertyTypes = new Set(['title', 'rich_text', 'people', 'relation', 'rollup']);
5
11
  /**
6
12
  * FetchPage retrieves page properties and download images in from properties.
7
13
  * And create cache that includes filepath of downloaded images.
8
14
  * The last_edited_time of 2nd args is for ROTION_INCREMENTAL_CACHE.
9
15
  */
10
16
  export const FetchPage = async ({ page_id, last_edited_time }) => {
17
+ const { cacheDir, incrementalCache, debug } = config();
11
18
  await createDirWhenNotfound(cacheDir);
12
19
  const cacheFile = `${cacheDir}/notion.pages.retrieve-${page_id}`;
13
20
  const lockKey = `page-${page_id}`;
@@ -35,37 +42,50 @@ export const FetchPage = async ({ page_id, last_edited_time }) => {
35
42
  catch (_) {
36
43
  /* not fatal */
37
44
  }
38
- const page = await reqAPIWithBackoff({
39
- func: notion.pages.retrieve,
40
- args: { page_id },
41
- count: 3
42
- });
43
- if ('properties' in page) {
44
- let list;
45
- for (const [, v] of Object.entries(page.properties)) {
46
- const property_id = v.id;
47
- const res = await reqAPIWithBackoffAndCache({
48
- name: 'notion.pages.properties.retrieve',
49
- func: notion.pages.properties.retrieve,
50
- args: { page_id, property_id },
51
- count: 3,
52
- });
53
- if (res.object !== 'list') {
54
- continue;
55
- }
56
- if (list === undefined) {
57
- list = res;
58
- }
59
- else {
60
- list.results.push(...res.results);
45
+ // A result that misses something because of a transient failure is not
46
+ // cached; see FetchBlocks.
47
+ const { value, complete } = await collectFailures(async () => {
48
+ const page = await reqAPIWithBackoff({
49
+ func: notion().pages.retrieve,
50
+ args: { page_id },
51
+ count: 3
52
+ });
53
+ if ('properties' in page) {
54
+ let list;
55
+ for (const [, v] of Object.entries(page.properties)) {
56
+ if (!listPropertyTypes.has(v.type)) {
57
+ continue;
58
+ }
59
+ const property_id = v.id;
60
+ const res = await reqAPIWithBackoffAndCache({
61
+ name: 'notion.pages.properties.retrieve',
62
+ func: notion().pages.properties.retrieve,
63
+ args: { page_id, property_id },
64
+ count: 3,
65
+ });
66
+ if (res.object !== 'list') {
67
+ continue;
68
+ }
69
+ if (list === undefined) {
70
+ list = res;
71
+ }
72
+ else {
73
+ list.results.push(...res.results);
74
+ }
61
75
  }
76
+ page.meta = list;
62
77
  }
63
- page.meta = list;
78
+ await savePageCover(page);
79
+ await savePageIcon(page);
80
+ return page;
81
+ });
82
+ if (complete) {
83
+ await writeCache(cacheFile, value);
84
+ }
85
+ else {
86
+ warn(`not caching page ${page_id} because of a transient failure; it is fetched again on the next call`);
64
87
  }
65
- await savePageCover(page);
66
- await savePageIcon(page);
67
- await writeCache(cacheFile, page);
68
- return page;
88
+ return value;
69
89
  });
70
90
  };
71
91
  export async function savePageCover(page) {
@@ -83,9 +103,7 @@ export async function savePageCover(page) {
83
103
  }
84
104
  }
85
105
  catch (e) {
86
- if (debug) {
87
- console.log(`Failed to save page cover: ${e}`);
88
- }
106
+ reportFailure(`cover of page ${page.id}`, e);
89
107
  }
90
108
  }
91
109
  export function getNotionIconUrl(icon) {
@@ -111,9 +129,7 @@ export async function savePageIcon(page) {
111
129
  }
112
130
  }
113
131
  catch (e) {
114
- if (debug) {
115
- console.log(`Failed to save page icon: ${e}`);
116
- }
132
+ reportFailure(`icon of page ${page.id}`, e);
117
133
  }
118
134
  }
119
135
  //# sourceMappingURL=page.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/exporter/page.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/exporter/page.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,MAAM,GACP,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACvC,OAAO,EACL,qBAAqB,EACrB,SAAS,EACT,SAAS,EACT,UAAU,EACV,OAAO,GACR,MAAM,YAAY,CAAA;AAOnB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAE/B,0EAA0E;AAC1E,yEAAyE;AACzE,gFAAgF;AAChF,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAA;AAUzF;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,EAAE,OAAO,EAAE,gBAAgB,EAAiB,EAAyB,EAAE;IACrG,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,CAAA;IACtD,MAAM,qBAAqB,CAAC,QAAQ,CAAC,CAAA;IACrC,MAAM,SAAS,GAAG,GAAG,QAAQ,0BAA0B,OAAO,EAAE,CAAA;IAChE,MAAM,OAAO,GAAG,QAAQ,OAAO,EAAE,CAAA;IAEjC,OAAO,YAAY,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;QACtC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAoB,SAAS,CAAC,CAAA;YAC1D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnB,IAAI,gBAAgB,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;oBACvD,IAAI,KAAK,EAAE,CAAC;wBACV,OAAO,CAAC,GAAG,CAAC,6BAA6B,SAAS,6EAA6E,CAAC,CAAA;oBAClI,CAAC;oBACD,OAAO,IAAI,CAAA;gBACb,CAAC;gBACD,IAAI,CAAC,gBAAgB,IAAI,CAAC,kBAAkB,IAAI,IAAI,IAAI,IAAI,CAAC,gBAAgB,KAAK,gBAAgB,CAAC,EAAE,CAAC;oBACpG,IAAI,KAAK,EAAE,CAAC;wBACV,OAAO,CAAC,GAAG,CAAC,sDAAsD,SAAS,EAAE,CAAC,CAAA;oBAChF,CAAC;oBACD,OAAO,IAAI,CAAA;gBACb,CAAC;gBACD,IAAI,KAAK,EAAE,CAAC;oBACV,OAAO,CAAC,GAAG,CAAC,yEAAyE,SAAS,EAAE,CAAC,CAAA;gBACnG,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,eAAe;QACjB,CAAC;QAED,uEAAuE;QACvE,2BAA2B;QAC3B,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,eAAe,CAAC,KAAK,IAAI,EAAE;YAC3D,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAoB;gBACtD,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ;gBAC7B,IAAI,EAAE,EAAE,OAAO,EAAE;gBACjB,KAAK,EAAE,CAAC;aACT,CAAC,CAAA;YAEF,IAAI,YAAY,IAAI,IAAI,EAAE,CAAC;gBACzB,IAAI,IAAwC,CAAA;gBAC5C,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;oBACpD,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;wBACnC,SAAQ;oBACV,CAAC;oBACD,MAAM,WAAW,GAAG,CAAC,CAAC,EAAE,CAAA;oBACxB,MAAM,GAAG,GAAG,MAAM,yBAAyB,CAA0B;wBACnE,IAAI,EAAE,kCAAkC;wBACxC,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ;wBACxC,IAAI,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE;wBAC9B,KAAK,EAAE,CAAC;qBACT,CAAC,CAAA;oBACF,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;wBAC1B,SAAQ;oBACV,CAAC;oBACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;wBACvB,IAAI,GAAG,GAAG,CAAA;oBACZ,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;oBACnC,CAAC;gBACH,CAAC;gBACD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;YAClB,CAAC;YAED,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;YACzB,MAAM,YAAY,CAAC,IAAI,CAAC,CAAA;YACxB,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;QAEF,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;QACpC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,oBAAoB,OAAO,uEAAuE,CAAC,CAAA;QAC1G,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAA8C;IAChF,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QACpD,OAAM;IACR,CAAC;IACD,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,cAAc,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;YAC9E,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAA;QAC5B,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;YAC1E,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAA;QAC5B,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,aAAa,CAAC,iBAAiB,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;IAC9C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAqC;IACpE,OAAO,+BAA+B,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;AAC7G,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAA8C;IAC/E,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAClD,OAAM;IACR,CAAC;IACD,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,aAAa,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;YAC5E,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAA;QAC3B,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;YACxE,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAA;QAC3B,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC5C,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,aAAa,IAAI,CAAC,EAAE,EAAE,CAAC,CACxD;YAAC,IAAY,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,CAAA;QAC/E,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,aAAa,CAAC,gBAAgB,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;IAC7C,CAAC;AACH,CAAC"}
@@ -0,0 +1,27 @@
1
+ export interface PruneCacheArgs {
2
+ /** Remove what has not been used since this time */
3
+ before: Date;
4
+ /** List what would be removed without removing it */
5
+ dryRun?: boolean;
6
+ }
7
+ export interface PruneCacheRes {
8
+ /** Paths of the files removed, or that would be removed with dryRun */
9
+ removed: string[];
10
+ }
11
+ /**
12
+ * pruneCache removes cache files, downloaded images and downloaded files that
13
+ * Rotion has not used since `before`. Rotion marks what it uses by setting
14
+ * the access time: a cache file when it is read or written, a download when
15
+ * it is saved or found, and the downloads a cached result refers to when that
16
+ * result is read.
17
+ *
18
+ * Only files named the way Rotion names them are removed: cache files that
19
+ * start with "notion.", and downloads whose name ends with a hash. Other
20
+ * files in the same directories, such as images of the site itself, are
21
+ * kept. A download and its conversions (the WebP of an image, the PNG of a
22
+ * HEIC) are removed together, and only when none of them was used.
23
+ *
24
+ * Run it after a full build with the time the build started, or on a server
25
+ * with a period longer than any page is kept without asking Rotion again.
26
+ */
27
+ export declare function pruneCache({ before, dryRun }: PruneCacheArgs): Promise<PruneCacheRes>;
@@ -0,0 +1,95 @@
1
+ import { readdir, stat, unlink } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { config } from './variables.js';
4
+ // A downloaded file is named <prefix>-<sha1 of the name in its URL><ext>,
5
+ // and its conversions (.webp, .png) share the name without the extension.
6
+ const downloadedName = /^(.+-[0-9a-f]{40})(\.[^.]+)?$/i;
7
+ // Files a write left behind when it failed: <path>.<pid>.<time>.<random>.tmp
8
+ const temporaryName = /\.\d+\.\d+\.[0-9a-z]+\.tmp$/;
9
+ async function listFiles(dir) {
10
+ let names;
11
+ try {
12
+ names = await readdir(dir);
13
+ }
14
+ catch {
15
+ return [];
16
+ }
17
+ const files = [];
18
+ for (const name of names) {
19
+ const file = path.join(dir, name);
20
+ try {
21
+ const s = await stat(file);
22
+ if (s.isFile()) {
23
+ files.push({ name, file, atime: s.atimeMs, mtime: s.mtimeMs });
24
+ }
25
+ }
26
+ catch {
27
+ // Removed in the meantime
28
+ }
29
+ }
30
+ return files;
31
+ }
32
+ /**
33
+ * pruneCache removes cache files, downloaded images and downloaded files that
34
+ * Rotion has not used since `before`. Rotion marks what it uses by setting
35
+ * the access time: a cache file when it is read or written, a download when
36
+ * it is saved or found, and the downloads a cached result refers to when that
37
+ * result is read.
38
+ *
39
+ * Only files named the way Rotion names them are removed: cache files that
40
+ * start with "notion.", and downloads whose name ends with a hash. Other
41
+ * files in the same directories, such as images of the site itself, are
42
+ * kept. A download and its conversions (the WebP of an image, the PNG of a
43
+ * HEIC) are removed together, and only when none of them was used.
44
+ *
45
+ * Run it after a full build with the time the build started, or on a server
46
+ * with a period longer than any page is kept without asking Rotion again.
47
+ */
48
+ export async function pruneCache({ before, dryRun = false }) {
49
+ const { cacheDir, docRoot, imageDir, fileDir } = config();
50
+ const limit = before.getTime();
51
+ const removed = [];
52
+ for (const f of await listFiles(cacheDir)) {
53
+ const unused = f.name.startsWith('notion.') && !temporaryName.test(f.name) && f.atime < limit;
54
+ const leftover = temporaryName.test(f.name) && f.mtime < limit;
55
+ if (unused || leftover) {
56
+ removed.push(f.file);
57
+ }
58
+ }
59
+ for (const dir of [path.join(docRoot, imageDir), path.join(docRoot, fileDir)]) {
60
+ const groups = new Map();
61
+ for (const f of await listFiles(dir)) {
62
+ if (temporaryName.test(f.name)) {
63
+ if (f.mtime < limit) {
64
+ removed.push(f.file);
65
+ }
66
+ continue;
67
+ }
68
+ const m = f.name.match(downloadedName);
69
+ if (m === null) {
70
+ continue;
71
+ }
72
+ const group = groups.get(m[1]) ?? { files: [], used: 0 };
73
+ group.files.push(f.file);
74
+ group.used = Math.max(group.used, f.atime);
75
+ groups.set(m[1], group);
76
+ }
77
+ for (const group of groups.values()) {
78
+ if (group.used < limit) {
79
+ removed.push(...group.files);
80
+ }
81
+ }
82
+ }
83
+ if (!dryRun) {
84
+ for (const file of removed) {
85
+ try {
86
+ await unlink(file);
87
+ }
88
+ catch {
89
+ // Removed in the meantime
90
+ }
91
+ }
92
+ }
93
+ return { removed };
94
+ }
95
+ //# sourceMappingURL=prune.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prune.js","sourceRoot":"","sources":["../../src/exporter/prune.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAcvC,0EAA0E;AAC1E,0EAA0E;AAC1E,MAAM,cAAc,GAAG,gCAAgC,CAAA;AACvD,6EAA6E;AAC7E,MAAM,aAAa,GAAG,6BAA6B,CAAA;AAEnD,KAAK,UAAU,SAAS,CAAE,GAAW;IACnC,IAAI,KAAe,CAAA;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;IACD,MAAM,KAAK,GAAG,EAAE,CAAA;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACjC,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1B,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;gBACf,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;YAChE,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAE,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK,EAAkB;IAC1E,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAA;IACzD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,EAAE,CAAA;IAC9B,MAAM,OAAO,GAAa,EAAE,CAAA;IAE5B,KAAK,MAAM,CAAC,IAAI,MAAM,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,KAAK,CAAA;QAC7F,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,KAAK,CAAA;QAC9D,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;QAC9E,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6C,CAAA;QACnE,KAAK,MAAM,CAAC,IAAI,MAAM,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC,CAAC,KAAK,GAAG,KAAK,EAAE,CAAC;oBACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;gBACtB,CAAC;gBACD,SAAQ;YACV,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;YACtC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gBACf,SAAQ;YACV,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;YACxD,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YACxB,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAA;YAC1C,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;QACzB,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YACpC,IAAI,KAAK,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;YACpB,CAAC;YAAC,MAAM,CAAC;gBACP,0BAA0B;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,CAAA;AACpB,CAAC"}
@@ -278,10 +278,23 @@ export type SyncedBlockBlockObjectResponseEx = SyncedBlockBlockObjectResponse &
278
278
  children?: ListBlockChildrenResponseEx;
279
279
  };
280
280
  export type BlockObjectResponse = ParagraphBlockObjectResponseEx | Heading1BlockObjectResponse | Heading2BlockObjectResponse | Heading3BlockObjectResponse | BulletedListItemBlockObjectResponseEx | NumberedListItemBlockObjectResponseEx | QuoteBlockObjectResponse | ToDoBlockObjectResponse | ToggleBlockObjectResponseEx | TemplateBlockObjectResponse | SyncedBlockBlockObjectResponseEx | ChildPageBlockObjectResponseEx | ChildDatabaseBlockObjectResponseEx | EquationBlockObjectResponse | CodeBlockObjectResponse | CalloutBlockObjectResponseEx | DividerBlockObjectResponse | BreadcrumbBlockObjectResponseEx | TableOfContentsBlockObjectResponse | ColumnListBlockObjectResponseEx | ColumnBlockObjectResponse | LinkToPageBlockObjectResponse | TableBlockObjectResponseEx | TableRowBlockObjectResponse | EmbedBlockObjectResponseEx | BookmarkBlockObjectResponseEx | ImageBlockObjectResponseEx | VideoBlockObjectResponseEx | PdfBlockObjectResponseEx | FileBlockObjectResponseEx | AudioBlockObjectResponse | LinkPreviewBlockObjectResponseEx | UnsupportedBlockObjectResponse;
281
+ /**
282
+ * Dependency is a page or database whose content is copied into a result of
283
+ * FetchBlocks: the source of a synced block, a mentioned page or database, a
284
+ * child page or a child database. Editing it does not change the
285
+ * last_edited_time of the page that shows it, so the incremental cache checks
286
+ * the dependency itself before it reuses the result.
287
+ */
288
+ export interface Dependency {
289
+ type: 'page' | 'database';
290
+ id: string;
291
+ last_edited_time: string;
292
+ }
281
293
  export type ListBlockChildrenResponseEx = ListBlockChildrenResponse & {
282
294
  results: Array<BlockObjectResponse>;
283
295
  children?: ListBlockChildrenResponse;
284
296
  last_edited_time?: string;
297
+ dependencies?: Dependency[];
285
298
  };
286
299
  export type LinkPreviewBlockObjectResponseEx = LinkPreviewBlockObjectResponse & {
287
300
  link_preview: {