rotion 1.14.0 → 1.15.0
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/dist/exporter/database.d.ts +1 -1
- package/dist/exporter/database.js +66 -61
- package/dist/exporter/database.js.map +1 -1
- package/dist/exporter/mutex.d.ts +10 -0
- package/dist/exporter/mutex.js +110 -0
- package/dist/exporter/mutex.js.map +1 -0
- package/dist/exporter/page.js +51 -47
- package/dist/exporter/page.js.map +1 -1
- package/dist/ui/cjs/types/exporter/database.d.ts +1 -1
- package/dist/ui/cjs/types/exporter/mutex.d.ts +10 -0
- package/dist/ui/esm/types/exporter/database.d.ts +1 -1
- package/dist/ui/esm/types/exporter/mutex.d.ts +10 -0
- package/dist/ui/umd/types/exporter/database.d.ts +1 -1
- package/dist/ui/umd/types/exporter/mutex.d.ts +10 -0
- package/package.json +1 -1
|
@@ -7,6 +7,6 @@ export interface FetchDatabaseRes extends QueryDatabaseResponseEx {
|
|
|
7
7
|
* FetchDatabase retrieves database and download images in from blocks.
|
|
8
8
|
* And create cache that includes filepath of downloaded images.
|
|
9
9
|
*/
|
|
10
|
-
export declare const FetchDatabase: (
|
|
10
|
+
export declare const FetchDatabase: (p: FetchDatabaseArgs) => Promise<FetchDatabaseRes>;
|
|
11
11
|
export declare function saveDatabaseCover(db: GetDatabaseResponseEx): Promise<void>;
|
|
12
12
|
export declare function saveDatabaseIcon(db: GetDatabaseResponseEx): Promise<void>;
|
|
@@ -2,87 +2,92 @@ import { reqAPIWithBackoff, notion, } from './api.js';
|
|
|
2
2
|
import { cacheDir, incrementalCache, debug, } from './variables.js';
|
|
3
3
|
import { atoh, createDirWhenNotfound, saveImage, readCache, writeCache, isAvailableCache, isEmpty, } from './files.js';
|
|
4
4
|
import { savePageCover, savePageIcon, } from './page.js';
|
|
5
|
+
import { withFileLock } from './mutex.js';
|
|
5
6
|
/**
|
|
6
7
|
* FetchDatabase retrieves database and download images in from blocks.
|
|
7
8
|
* And create cache that includes filepath of downloaded images.
|
|
8
9
|
*/
|
|
9
|
-
export const FetchDatabase = async (
|
|
10
|
-
const
|
|
10
|
+
export const FetchDatabase = async (p) => {
|
|
11
|
+
const params = JSON.parse(JSON.stringify(p));
|
|
12
|
+
const { database_id } = params;
|
|
11
13
|
const limit = ('page_size' in params) ? params.page_size : undefined;
|
|
12
14
|
const paramsHash = atoh(JSON.stringify(params));
|
|
13
15
|
await createDirWhenNotfound(cacheDir);
|
|
14
16
|
const cacheFile = `${cacheDir}/notion.databases.query-${paramsHash}${limit !== undefined ? `.limit-${limit}` : ''}`;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
const lockKey = `database-${paramsHash}`;
|
|
18
|
+
return withFileLock(lockKey, async () => {
|
|
19
|
+
let allres;
|
|
20
|
+
let res;
|
|
21
|
+
try {
|
|
22
|
+
const list = await readCache(cacheFile);
|
|
23
|
+
if (!isEmpty(list)) {
|
|
24
|
+
if (!incrementalCache) {
|
|
25
|
+
if (debug) {
|
|
26
|
+
console.log(`use cache in FetchDatabase() with no-incremental-cache: ${cacheFile}`);
|
|
27
|
+
}
|
|
28
|
+
return list;
|
|
29
|
+
}
|
|
30
|
+
if (await isAvailableCache(cacheFile)) {
|
|
31
|
+
if (debug) {
|
|
32
|
+
console.log(`use available cache in FetchDatabase(): ${cacheFile}`);
|
|
33
|
+
}
|
|
34
|
+
return list;
|
|
23
35
|
}
|
|
24
|
-
return list;
|
|
25
|
-
}
|
|
26
|
-
if (await isAvailableCache(cacheFile)) {
|
|
27
36
|
if (debug) {
|
|
28
|
-
console.log(`
|
|
37
|
+
console.log(`requesting to API because an old cache file was found in FetchDatabase(): ${cacheFile}`);
|
|
29
38
|
}
|
|
30
|
-
return list;
|
|
31
39
|
}
|
|
32
|
-
if (debug) {
|
|
33
|
-
console.log(`requesting to API because an old cache file was found in FetchDatabase(): ${cacheFile}`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
catch (_) {
|
|
38
|
-
/* not fatal */
|
|
39
|
-
}
|
|
40
|
-
while (true) {
|
|
41
|
-
if (res && res.next_cursor) {
|
|
42
|
-
params.start_cursor = res.next_cursor;
|
|
43
|
-
}
|
|
44
|
-
res = await reqAPIWithBackoff({
|
|
45
|
-
func: notion.databases.query,
|
|
46
|
-
args: params,
|
|
47
|
-
count: 3,
|
|
48
|
-
});
|
|
49
|
-
if (allres === undefined) {
|
|
50
|
-
allres = res;
|
|
51
40
|
}
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
catch (_) {
|
|
42
|
+
/* not fatal */
|
|
54
43
|
}
|
|
55
|
-
|
|
56
|
-
|
|
44
|
+
while (true) {
|
|
45
|
+
if (res && res.next_cursor) {
|
|
46
|
+
params.start_cursor = res.next_cursor;
|
|
47
|
+
}
|
|
48
|
+
res = await reqAPIWithBackoff({
|
|
49
|
+
func: notion.databases.query,
|
|
50
|
+
args: params,
|
|
51
|
+
count: 3,
|
|
52
|
+
});
|
|
53
|
+
if (allres === undefined) {
|
|
54
|
+
allres = res;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
allres.results.push(...res.results);
|
|
58
|
+
}
|
|
59
|
+
if (res.next_cursor === null || limit !== undefined) {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
57
62
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
for (const result of allres.results) {
|
|
64
|
+
const page = result;
|
|
65
|
+
await savePageCover(page);
|
|
66
|
+
await savePageIcon(page);
|
|
67
|
+
for (const [, v] of Object.entries(page.properties)) {
|
|
68
|
+
// Save avatar in people property type
|
|
69
|
+
if (v.type === 'people') {
|
|
70
|
+
const peoples = v.people;
|
|
71
|
+
for (const people of peoples) {
|
|
72
|
+
if (people.avatar_url) {
|
|
73
|
+
const ipws = await saveImage(people.avatar_url, `database-avatar-${people.id}`);
|
|
74
|
+
people.avatar = ipws.path;
|
|
75
|
+
}
|
|
71
76
|
}
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
const meta = await reqAPIWithBackoff({
|
|
81
|
+
func: notion.databases.retrieve,
|
|
82
|
+
args: { database_id },
|
|
83
|
+
count: 3,
|
|
84
|
+
});
|
|
85
|
+
await saveDatabaseCover(meta);
|
|
86
|
+
await saveDatabaseIcon(meta);
|
|
87
|
+
allres.meta = meta;
|
|
88
|
+
await writeCache(cacheFile, allres);
|
|
89
|
+
return allres;
|
|
80
90
|
});
|
|
81
|
-
await saveDatabaseCover(meta);
|
|
82
|
-
await saveDatabaseIcon(meta);
|
|
83
|
-
allres.meta = meta;
|
|
84
|
-
await writeCache(cacheFile, allres);
|
|
85
|
-
return allres;
|
|
86
91
|
};
|
|
87
92
|
export async function saveDatabaseCover(db) {
|
|
88
93
|
if (db.cover === undefined || db.cover === null) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/exporter/database.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,MAAM,GACP,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,KAAK,GACN,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,IAAI,EACJ,qBAAqB,EACrB,SAAS,EACT,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,OAAO,GACR,MAAM,YAAY,CAAA;AAQnB,OAAO,EACL,aAAa,EACb,YAAY,GACb,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/exporter/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface LockOptions {
|
|
2
|
+
timeout?: number;
|
|
3
|
+
retryInterval?: number;
|
|
4
|
+
maxAge?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Performs exclusive control using file-based mutex
|
|
8
|
+
*/
|
|
9
|
+
export declare function withFileLock<T>(key: string, operation: () => Promise<T>, options?: LockOptions): Promise<T>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { cacheDir, debug } from './variables.js';
|
|
4
|
+
import { createDirWhenNotfound } from './files.js';
|
|
5
|
+
const DEFAULT_OPTIONS = {
|
|
6
|
+
timeout: 30000, // 30 seconds
|
|
7
|
+
retryInterval: 100, // 100ms
|
|
8
|
+
maxAge: 60000, // 1 minute
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Performs exclusive control using file-based mutex
|
|
12
|
+
*/
|
|
13
|
+
export async function withFileLock(key, operation, options = {}) {
|
|
14
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
15
|
+
const lockDir = path.join(cacheDir, 'locks');
|
|
16
|
+
const lockFile = path.join(lockDir, `${key}.lock`);
|
|
17
|
+
await createDirWhenNotfound(lockDir);
|
|
18
|
+
const startTime = Date.now();
|
|
19
|
+
let fd = null;
|
|
20
|
+
while (Date.now() - startTime < opts.timeout) {
|
|
21
|
+
try {
|
|
22
|
+
// Cleanup stale lock files
|
|
23
|
+
await cleanupStalelock(lockFile, opts.maxAge);
|
|
24
|
+
// Create lock file exclusively
|
|
25
|
+
fd = await fs.open(lockFile, 'wx');
|
|
26
|
+
// Write process ID and timestamp
|
|
27
|
+
const lockData = JSON.stringify({
|
|
28
|
+
pid: process.pid,
|
|
29
|
+
timestamp: Date.now(),
|
|
30
|
+
key
|
|
31
|
+
});
|
|
32
|
+
await fd.writeFile(lockData);
|
|
33
|
+
if (debug) {
|
|
34
|
+
console.log(`Lock acquired: ${key} (pid: ${process.pid})`);
|
|
35
|
+
}
|
|
36
|
+
// Execute operation
|
|
37
|
+
try {
|
|
38
|
+
const result = await operation();
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
// Release lock
|
|
43
|
+
await releaseLock(fd, lockFile, key);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error.code === 'EEXIST') {
|
|
48
|
+
// Lock file already exists - wait and retry
|
|
49
|
+
await new Promise(resolve => setTimeout(resolve, opts.retryInterval));
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Failed to acquire lock for "${key}" within ${opts.timeout}ms`);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Cleanup stale lock files
|
|
59
|
+
*/
|
|
60
|
+
async function cleanupStalelock(lockFile, maxAge) {
|
|
61
|
+
try {
|
|
62
|
+
const stats = await fs.stat(lockFile);
|
|
63
|
+
const age = Date.now() - stats.mtime.getTime();
|
|
64
|
+
if (age > maxAge) {
|
|
65
|
+
const lockData = await fs.readFile(lockFile, 'utf-8');
|
|
66
|
+
const lock = JSON.parse(lockData);
|
|
67
|
+
// Check if process is alive
|
|
68
|
+
if (!isProcessAlive(lock.pid)) {
|
|
69
|
+
await fs.unlink(lockFile);
|
|
70
|
+
if (debug) {
|
|
71
|
+
console.log(`Cleaned up stale lock: ${lockFile} (dead pid: ${lock.pid})`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Ignore if file doesn't exist or can't be read
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Check if process is alive
|
|
82
|
+
*/
|
|
83
|
+
function isProcessAlive(pid) {
|
|
84
|
+
try {
|
|
85
|
+
// Signal 0 doesn't actually send a signal, just checks process existence
|
|
86
|
+
process.kill(pid, 0);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Release lock
|
|
95
|
+
*/
|
|
96
|
+
async function releaseLock(fd, lockFile, key) {
|
|
97
|
+
try {
|
|
98
|
+
await fd.close();
|
|
99
|
+
await fs.unlink(lockFile);
|
|
100
|
+
if (debug) {
|
|
101
|
+
console.log(`Lock released: ${key} (pid: ${process.pid})`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
if (debug) {
|
|
106
|
+
console.error(`Failed to release lock: ${key}`, error);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=mutex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutex.js","sourceRoot":"","sources":["../../src/exporter/mutex.ts"],"names":[],"mappings":"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"}
|
package/dist/exporter/page.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { reqAPIWithBackoff, reqAPIWithBackoffAndCache, notion, } from './api.js';
|
|
2
2
|
import { cacheDir, incrementalCache, debug, } from './variables.js';
|
|
3
3
|
import { createDirWhenNotfound, saveImage, readCache, writeCache, isEmpty, } from './files.js';
|
|
4
|
+
import { withFileLock } from './mutex.js';
|
|
4
5
|
/**
|
|
5
6
|
* FetchPage retrieves page properties and download images in from properties.
|
|
6
7
|
* And create cache that includes filepath of downloaded images.
|
|
@@ -9,60 +10,63 @@ import { createDirWhenNotfound, saveImage, readCache, writeCache, isEmpty, } fro
|
|
|
9
10
|
export const FetchPage = async ({ page_id, last_edited_time }) => {
|
|
10
11
|
await createDirWhenNotfound(cacheDir);
|
|
11
12
|
const cacheFile = `${cacheDir}/notion.pages.retrieve-${page_id}`;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
const lockKey = `page-${page_id}`;
|
|
14
|
+
return withFileLock(lockKey, async () => {
|
|
15
|
+
try {
|
|
16
|
+
const page = await readCache(cacheFile);
|
|
17
|
+
if (!isEmpty(page)) {
|
|
18
|
+
if (incrementalCache && last_edited_time === undefined) {
|
|
19
|
+
if (debug) {
|
|
20
|
+
console.log(`use cache in FetchPage(): ${cacheFile}, last_edited_time is required as a FetchPage() args when incremental cache`);
|
|
21
|
+
}
|
|
22
|
+
return page;
|
|
23
|
+
}
|
|
24
|
+
if (!incrementalCache || ('last_edited_time' in page && page.last_edited_time === last_edited_time)) {
|
|
25
|
+
if (debug) {
|
|
26
|
+
console.log(`use cache so same last-edited-time in FetchPage(): ${cacheFile}`);
|
|
27
|
+
}
|
|
28
|
+
return page;
|
|
18
29
|
}
|
|
19
|
-
return page;
|
|
20
|
-
}
|
|
21
|
-
if (!incrementalCache || ('last_edited_time' in page && page.last_edited_time === last_edited_time)) {
|
|
22
30
|
if (debug) {
|
|
23
|
-
console.log(`
|
|
31
|
+
console.log(`requesting to API because an old cache file was found in FetchPage(): ${cacheFile}`);
|
|
24
32
|
}
|
|
25
|
-
return page;
|
|
26
|
-
}
|
|
27
|
-
if (debug) {
|
|
28
|
-
console.log(`requesting to API because an old cache file was found in FetchPage(): ${cacheFile}`);
|
|
29
33
|
}
|
|
30
34
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
35
|
+
catch (_) {
|
|
36
|
+
/* not fatal */
|
|
37
|
+
}
|
|
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);
|
|
61
|
+
}
|
|
58
62
|
}
|
|
63
|
+
page.meta = list;
|
|
59
64
|
}
|
|
60
|
-
page
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return page;
|
|
65
|
+
await savePageCover(page);
|
|
66
|
+
await savePageIcon(page);
|
|
67
|
+
await writeCache(cacheFile, page);
|
|
68
|
+
return page;
|
|
69
|
+
});
|
|
66
70
|
};
|
|
67
71
|
export async function savePageCover(page) {
|
|
68
72
|
if (page.cover === undefined || page.cover === null) {
|
|
@@ -1 +1 @@
|
|
|
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,EACL,QAAQ,EACR,gBAAgB,EAChB,KAAK,GACN,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,qBAAqB,EACrB,SAAS,EACT,SAAS,EACT,UAAU,EACV,OAAO,GACR,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/exporter/page.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,6 @@ export interface FetchDatabaseRes extends QueryDatabaseResponseEx {
|
|
|
7
7
|
* FetchDatabase retrieves database and download images in from blocks.
|
|
8
8
|
* And create cache that includes filepath of downloaded images.
|
|
9
9
|
*/
|
|
10
|
-
export declare const FetchDatabase: (
|
|
10
|
+
export declare const FetchDatabase: (p: FetchDatabaseArgs) => Promise<FetchDatabaseRes>;
|
|
11
11
|
export declare function saveDatabaseCover(db: GetDatabaseResponseEx): Promise<void>;
|
|
12
12
|
export declare function saveDatabaseIcon(db: GetDatabaseResponseEx): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface LockOptions {
|
|
2
|
+
timeout?: number;
|
|
3
|
+
retryInterval?: number;
|
|
4
|
+
maxAge?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Performs exclusive control using file-based mutex
|
|
8
|
+
*/
|
|
9
|
+
export declare function withFileLock<T>(key: string, operation: () => Promise<T>, options?: LockOptions): Promise<T>;
|
|
10
|
+
export {};
|
|
@@ -7,6 +7,6 @@ export interface FetchDatabaseRes extends QueryDatabaseResponseEx {
|
|
|
7
7
|
* FetchDatabase retrieves database and download images in from blocks.
|
|
8
8
|
* And create cache that includes filepath of downloaded images.
|
|
9
9
|
*/
|
|
10
|
-
export declare const FetchDatabase: (
|
|
10
|
+
export declare const FetchDatabase: (p: FetchDatabaseArgs) => Promise<FetchDatabaseRes>;
|
|
11
11
|
export declare function saveDatabaseCover(db: GetDatabaseResponseEx): Promise<void>;
|
|
12
12
|
export declare function saveDatabaseIcon(db: GetDatabaseResponseEx): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface LockOptions {
|
|
2
|
+
timeout?: number;
|
|
3
|
+
retryInterval?: number;
|
|
4
|
+
maxAge?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Performs exclusive control using file-based mutex
|
|
8
|
+
*/
|
|
9
|
+
export declare function withFileLock<T>(key: string, operation: () => Promise<T>, options?: LockOptions): Promise<T>;
|
|
10
|
+
export {};
|
|
@@ -7,6 +7,6 @@ export interface FetchDatabaseRes extends QueryDatabaseResponseEx {
|
|
|
7
7
|
* FetchDatabase retrieves database and download images in from blocks.
|
|
8
8
|
* And create cache that includes filepath of downloaded images.
|
|
9
9
|
*/
|
|
10
|
-
export declare const FetchDatabase: (
|
|
10
|
+
export declare const FetchDatabase: (p: FetchDatabaseArgs) => Promise<FetchDatabaseRes>;
|
|
11
11
|
export declare function saveDatabaseCover(db: GetDatabaseResponseEx): Promise<void>;
|
|
12
12
|
export declare function saveDatabaseIcon(db: GetDatabaseResponseEx): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface LockOptions {
|
|
2
|
+
timeout?: number;
|
|
3
|
+
retryInterval?: number;
|
|
4
|
+
maxAge?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Performs exclusive control using file-based mutex
|
|
8
|
+
*/
|
|
9
|
+
export declare function withFileLock<T>(key: string, operation: () => Promise<T>, options?: LockOptions): Promise<T>;
|
|
10
|
+
export {};
|