@adobe/helix-google-support 1.0.1 → 1.2.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/CHANGELOG.md +21 -0
- package/package.json +4 -4
- package/src/GoogleClient.d.ts +140 -0
- package/src/GoogleClient.js +150 -25
- package/src/cache.js +0 -78
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## [1.2.1](https://github.com/adobe/helix-google-support/compare/v1.2.0...v1.2.1) (2022-04-28)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* include mimeType ([#10](https://github.com/adobe/helix-google-support/issues/10)) ([993e24a](https://github.com/adobe/helix-google-support/commit/993e24acdd723402a6d85a8bf74e3b93df8c5d0e))
|
|
7
|
+
|
|
8
|
+
# [1.2.0](https://github.com/adobe/helix-google-support/compare/v1.1.0...v1.2.0) (2022-04-28)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add get file|doc from path ([#9](https://github.com/adobe/helix-google-support/issues/9)) ([4a2e927](https://github.com/adobe/helix-google-support/commit/4a2e9272f4328e936e65b7144d04e516ac602625))
|
|
14
|
+
|
|
15
|
+
# [1.1.0](https://github.com/adobe/helix-google-support/compare/v1.0.1...v1.1.0) (2022-04-28)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* add cache invalidate for drive items ([#8](https://github.com/adobe/helix-google-support/issues/8)) ([7aa2c80](https://github.com/adobe/helix-google-support/commit/7aa2c8061facb2d3c45929356c23370d83686f55))
|
|
21
|
+
|
|
1
22
|
## [1.0.1](https://github.com/adobe/helix-google-support/compare/v1.0.0...v1.0.1) (2022-04-20)
|
|
2
23
|
|
|
3
24
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-google-support",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Helix Google Support",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -40,14 +40,14 @@
|
|
|
40
40
|
"@semantic-release/changelog": "6.0.1",
|
|
41
41
|
"@semantic-release/git": "10.0.1",
|
|
42
42
|
"@semantic-release/npm": "9.0.1",
|
|
43
|
-
"c8": "7.11.
|
|
43
|
+
"c8": "7.11.2",
|
|
44
44
|
"codecov": "3.8.3",
|
|
45
|
-
"eslint": "8.
|
|
45
|
+
"eslint": "8.14.0",
|
|
46
46
|
"eslint-plugin-header": "3.1.1",
|
|
47
47
|
"eslint-plugin-import": "2.26.0",
|
|
48
48
|
"husky": "7.0.4",
|
|
49
49
|
"junit-report-builder": "3.0.0",
|
|
50
|
-
"lint-staged": "12.
|
|
50
|
+
"lint-staged": "12.4.0",
|
|
51
51
|
"mocha": "9.2.2",
|
|
52
52
|
"mocha-multi-reporters": "1.5.1",
|
|
53
53
|
"nock": "13.2.4",
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
declare interface ICachePlugin {}
|
|
13
|
+
|
|
14
|
+
declare interface DriveItemInfo {}
|
|
15
|
+
|
|
16
|
+
declare interface GoogleClientOptions {
|
|
17
|
+
log:Console;
|
|
18
|
+
clientId:string;
|
|
19
|
+
clientSecret:string;
|
|
20
|
+
redirectUri:string;
|
|
21
|
+
cachePlugin?:ICachePlugin;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Google client
|
|
26
|
+
*/
|
|
27
|
+
declare class GoogleClient {
|
|
28
|
+
/**
|
|
29
|
+
* Sets the global item cache options. It internally creates a new LRU
|
|
30
|
+
* with the given options
|
|
31
|
+
*
|
|
32
|
+
* @param opts
|
|
33
|
+
*/
|
|
34
|
+
static setItemCacheOptions(opts:object);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns a url for a google drive id.
|
|
38
|
+
* @param {string} id
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
static id2Url(id:string):string;
|
|
42
|
+
|
|
43
|
+
constructor(opts:GoogleClientOptions);
|
|
44
|
+
|
|
45
|
+
init():Promise<GoogleClient>;
|
|
46
|
+
|
|
47
|
+
generateAuthUrl(...args):Promise<string>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Sets the credentials
|
|
51
|
+
* @param tokens
|
|
52
|
+
* @returns {Promise<void>}
|
|
53
|
+
*/
|
|
54
|
+
setCredentials(tokens:object):Promise<void>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Returns the token for the given code
|
|
58
|
+
* @param {string} code
|
|
59
|
+
* @returns {Promise<*>}
|
|
60
|
+
*/
|
|
61
|
+
getToken(code:string):Promise<object>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {string} parentId
|
|
65
|
+
* @param {string[]} pathSegments
|
|
66
|
+
* @param {string} parentPath
|
|
67
|
+
* @returns {Promise<DriveItemInfo[]>|null}
|
|
68
|
+
*/
|
|
69
|
+
getUncachedItemsFromSegments(parentId:string, pathSegments:string[], parentPath:string):Promise<DriveItemInfo[]>;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {string} parentId
|
|
73
|
+
* @param {string} pathSegments
|
|
74
|
+
* @param {string} parentPath
|
|
75
|
+
* @returns {Promise<DriveItemInfo[]>|null}
|
|
76
|
+
*/
|
|
77
|
+
getDriveItemsFromSegments(parentId:string, pathSegments:string[], parentPath:string):Promise<DriveItemInfo[]>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* returns the items hierarchy for the given path and root id, starting with the given path.
|
|
81
|
+
* @param {string} parentId
|
|
82
|
+
* @param {string} path
|
|
83
|
+
* @return {DriveItemInfo[]}
|
|
84
|
+
*/
|
|
85
|
+
getDriveItemsFromSegments(parentId:string, path:string):Promise<DriveItemInfo[]>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* returns the items hierarchy for the given item, starting with the given id
|
|
89
|
+
* @param {string} fileId
|
|
90
|
+
* @param {object} roots
|
|
91
|
+
* @returns {Promise<DriveItemInfo[]>}
|
|
92
|
+
*/
|
|
93
|
+
getItemsFromId(fileId:string, roots:object):Promise<DriveItemInfo[]>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Returns the (cached) item for the given path or {@code null} if the item cannot be found.
|
|
97
|
+
* The item will contains a `invalidate()` method which can be used to remove it from the cache.
|
|
98
|
+
*
|
|
99
|
+
* @param {string} parentId
|
|
100
|
+
* @param {string} path
|
|
101
|
+
* @returns {Promise<DriveItemInfo>}
|
|
102
|
+
*/
|
|
103
|
+
getItemFromPath(parentId:string, path:string):Promise<DriveItemInfo>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Returns an (uncached) file directly via the google api
|
|
107
|
+
* @param {string} fileId
|
|
108
|
+
* @returns {string} file data
|
|
109
|
+
*/
|
|
110
|
+
getFile(fileId:string):Promise<string>;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Fetches the file data from the give path. If the file with the internal id could not be
|
|
114
|
+
* fetched, the item cache is invalidated and the operation is retried. this is to support
|
|
115
|
+
* moved items.
|
|
116
|
+
* @param {string} parentId
|
|
117
|
+
* @param {string} path
|
|
118
|
+
* @param {boolean} noRetry {@code true} to avoid retry
|
|
119
|
+
* @returns {Promise<string>|null} The data of the file or {@code null} if the file does not exist
|
|
120
|
+
*/
|
|
121
|
+
getFileFromPath(parentId:string, path:string, noRetry:boolean):Promise<string>;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Returns an (uncached) document directly via the google api
|
|
125
|
+
* @param {string} documentId
|
|
126
|
+
* @returns {object} document
|
|
127
|
+
*/
|
|
128
|
+
getDocument(documentId:string):Promise<object>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Fetches the document from the give path. If the document with the internal id could not be
|
|
132
|
+
* fetched, the item cache is invalidated and the operation is retried. this is to support
|
|
133
|
+
* moved items.
|
|
134
|
+
* @param {string} parentId
|
|
135
|
+
* @param {string} path
|
|
136
|
+
* @param {boolean} noRetry {@code true} to avoid retry
|
|
137
|
+
* @returns {Promise<object>|null} The document or {@code null} if the document does not exist
|
|
138
|
+
*/
|
|
139
|
+
getDocumentFromPath(parentId:string, path:string, noRetry:boolean):Promise<object>;
|
|
140
|
+
}
|
package/src/GoogleClient.js
CHANGED
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
+
import LRU from 'lru-cache';
|
|
12
13
|
import { google } from 'googleapis';
|
|
13
14
|
import {
|
|
14
15
|
editDistance, sanitizeName, splitByExtension,
|
|
15
16
|
} from '@adobe/helix-onedrive-support/utils';
|
|
16
17
|
import { StatusCodeError } from '@adobe/helix-onedrive-support';
|
|
17
18
|
import { GoogleTokenCache } from './GoogleTokenCache.js';
|
|
18
|
-
|
|
19
|
+
|
|
20
|
+
let lru = new LRU({ max: 1000, ttl: 60000 });
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* @typedef DriveItemInfo {
|
|
@@ -39,6 +41,19 @@ function addLastModified(itemInfo, item) {
|
|
|
39
41
|
return itemInfo;
|
|
40
42
|
}
|
|
41
43
|
|
|
44
|
+
function createPathSegments(path) {
|
|
45
|
+
const pathSegments = path.split('/');
|
|
46
|
+
if (!pathSegments[0]) {
|
|
47
|
+
// if path starts with '/' the first segment is empty
|
|
48
|
+
pathSegments.shift();
|
|
49
|
+
}
|
|
50
|
+
return pathSegments;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getCacheKey(parentId, pathSegments) {
|
|
54
|
+
return `${parentId}:${pathSegments.join('/')}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
42
57
|
/**
|
|
43
58
|
* Google auth client
|
|
44
59
|
*/
|
|
@@ -50,7 +65,7 @@ export class GoogleClient {
|
|
|
50
65
|
* @param opts
|
|
51
66
|
*/
|
|
52
67
|
static setItemCacheOptions(opts) {
|
|
53
|
-
|
|
68
|
+
lru = new LRU(opts);
|
|
54
69
|
}
|
|
55
70
|
|
|
56
71
|
/**
|
|
@@ -95,13 +110,6 @@ export class GoogleClient {
|
|
|
95
110
|
version: 'v3',
|
|
96
111
|
auth: this.auth,
|
|
97
112
|
});
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Cached version of `getUncachedItemsFromSegments`
|
|
101
|
-
*/
|
|
102
|
-
this.getDriveItemsFromSegments = cache(this.getUncachedItemsFromSegments.bind(this), {
|
|
103
|
-
hash: (fn, segs, parentId) => `${parentId}:${segs.join('/')}`,
|
|
104
|
-
});
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
async init() {
|
|
@@ -142,12 +150,12 @@ export class GoogleClient {
|
|
|
142
150
|
}
|
|
143
151
|
|
|
144
152
|
/**
|
|
145
|
-
* @param {string} path
|
|
146
153
|
* @param {string} parentId
|
|
154
|
+
* @param {string[]} pathSegments
|
|
147
155
|
* @param {string} parentPath
|
|
148
|
-
* @returns {Promise<DriveItemInfo[]
|
|
156
|
+
* @returns {Promise<DriveItemInfo[]>|null}
|
|
149
157
|
*/
|
|
150
|
-
async getUncachedItemsFromSegments(
|
|
158
|
+
async getUncachedItemsFromSegments(parentId, pathSegments, parentPath) {
|
|
151
159
|
const { log, drive } = this;
|
|
152
160
|
const name = pathSegments.shift();
|
|
153
161
|
const [baseName, ext] = splitByExtension(name);
|
|
@@ -161,7 +169,7 @@ export class GoogleClient {
|
|
|
161
169
|
// folder if path continues, sheet otherwise
|
|
162
170
|
`and mimeType ${pathSegments.length ? '=' : '!='} 'application/vnd.google-apps.folder'`,
|
|
163
171
|
].join(' '),
|
|
164
|
-
fields: 'nextPageToken, files(id, name, modifiedTime)',
|
|
172
|
+
fields: 'nextPageToken, files(id, name, mimeType, modifiedTime)',
|
|
165
173
|
includeItemsFromAllDrives: true,
|
|
166
174
|
supportsAllDrives: true,
|
|
167
175
|
pageSize: 1000,
|
|
@@ -218,42 +226,72 @@ export class GoogleClient {
|
|
|
218
226
|
const itemPath = `${parentPath}/${sanitizedName}`;
|
|
219
227
|
const children = pathSegments.length
|
|
220
228
|
// eslint-disable-next-line no-use-before-define
|
|
221
|
-
? await this.getDriveItemsFromSegments(
|
|
229
|
+
? await this.getDriveItemsFromSegments(item.id, pathSegments, itemPath)
|
|
222
230
|
: [];
|
|
223
231
|
|
|
224
232
|
if (!children) {
|
|
225
233
|
return null;
|
|
226
234
|
}
|
|
227
|
-
|
|
228
235
|
const pathItem = addLastModified({
|
|
229
236
|
name,
|
|
230
237
|
path: itemPath,
|
|
231
238
|
id: item.id,
|
|
232
239
|
}, item);
|
|
233
240
|
|
|
241
|
+
if (children.length) {
|
|
242
|
+
// add parent references not-enumerable to avoid deep structures during serialization
|
|
243
|
+
Object.defineProperty(children[children.length - 1], 'parent', {
|
|
244
|
+
enumerable: false,
|
|
245
|
+
value: pathItem,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
234
249
|
return [...children, pathItem];
|
|
235
250
|
}
|
|
236
251
|
|
|
252
|
+
/**
|
|
253
|
+
* @param {string} parentId
|
|
254
|
+
* @param {string} pathSegments
|
|
255
|
+
* @param {string} parentPath
|
|
256
|
+
* @returns {Promise<DriveItemInfo[]>|null}
|
|
257
|
+
*/
|
|
258
|
+
async getDriveItemsFromSegments(parentId, pathSegments, parentPath) {
|
|
259
|
+
const key = getCacheKey(parentId, pathSegments);
|
|
260
|
+
let items = lru.get(key);
|
|
261
|
+
if (items) {
|
|
262
|
+
return items;
|
|
263
|
+
}
|
|
264
|
+
items = await this.getUncachedItemsFromSegments(parentId, pathSegments, parentPath);
|
|
265
|
+
if (items) {
|
|
266
|
+
lru.set(key, items);
|
|
267
|
+
// add invalidation function as not-enumerable to keep compatible objects
|
|
268
|
+
Object.defineProperty(items[items.length - 1], 'invalidate', {
|
|
269
|
+
enumerable: false,
|
|
270
|
+
value() {
|
|
271
|
+
lru.delete(key);
|
|
272
|
+
this.parent?.invalidate();
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
return items;
|
|
277
|
+
}
|
|
278
|
+
|
|
237
279
|
/**
|
|
238
280
|
* returns the items hierarchy for the given path and root id, starting with the given path.
|
|
239
|
-
* @param
|
|
240
|
-
* @param
|
|
281
|
+
* @param {string} parentId
|
|
282
|
+
* @param {string} path
|
|
241
283
|
* @return {DriveItemInfo[]}
|
|
242
284
|
*/
|
|
243
|
-
async getItemsFromPath(
|
|
244
|
-
const segs = path
|
|
245
|
-
|
|
246
|
-
// if path starts with '/' the first segment is empty
|
|
247
|
-
segs.shift();
|
|
248
|
-
}
|
|
249
|
-
const result = await this.getDriveItemsFromSegments(segs, rootId, '');
|
|
285
|
+
async getItemsFromPath(parentId, path) {
|
|
286
|
+
const segs = createPathSegments(path);
|
|
287
|
+
const result = await this.getDriveItemsFromSegments(parentId, segs, '');
|
|
250
288
|
if (!result) {
|
|
251
289
|
return [];
|
|
252
290
|
}
|
|
253
291
|
return [...result, {
|
|
254
292
|
name: '',
|
|
255
293
|
path: '/',
|
|
256
|
-
id:
|
|
294
|
+
id: parentId,
|
|
257
295
|
}];
|
|
258
296
|
}
|
|
259
297
|
|
|
@@ -261,6 +299,7 @@ export class GoogleClient {
|
|
|
261
299
|
* returns the items hierarchy for the given item, starting with the given id
|
|
262
300
|
* @param {string} fileId
|
|
263
301
|
* @param {object} roots
|
|
302
|
+
* @private
|
|
264
303
|
* @returns {Promise<DriveItemInfo[]>}
|
|
265
304
|
*/
|
|
266
305
|
async getItems(fileId, roots) {
|
|
@@ -325,6 +364,25 @@ export class GoogleClient {
|
|
|
325
364
|
}
|
|
326
365
|
|
|
327
366
|
/**
|
|
367
|
+
* Returns the (cached) item for the given path or {@code null} if the item cannot be found.
|
|
368
|
+
* The item will contains a `invalidate()` method which can be used to remove it from the cache.
|
|
369
|
+
*
|
|
370
|
+
* @param {string} parentId
|
|
371
|
+
* @param {string} path
|
|
372
|
+
* @returns {Promise<DriveItemInfo>}
|
|
373
|
+
*/
|
|
374
|
+
async getItemFromPath(parentId, path) {
|
|
375
|
+
const segs = createPathSegments(path);
|
|
376
|
+
const items = await this.getDriveItemsFromSegments(parentId, segs, '');
|
|
377
|
+
const item = items?.[0];
|
|
378
|
+
if (!item) {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
return item;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Returns an (uncached) file directly via the google api
|
|
328
386
|
* @param {string} fileId
|
|
329
387
|
* @returns {string} file data
|
|
330
388
|
*/
|
|
@@ -343,6 +401,42 @@ export class GoogleClient {
|
|
|
343
401
|
}
|
|
344
402
|
}
|
|
345
403
|
|
|
404
|
+
/**
|
|
405
|
+
* Fetches the file data from the give path. If the file with the internal id could not be
|
|
406
|
+
* fetched, the item cache is invalidated and the operation is retried. this is to support
|
|
407
|
+
* moved items.
|
|
408
|
+
* @param {string} parentId
|
|
409
|
+
* @param {string} path
|
|
410
|
+
* @param {boolean} noRetry {@code true} to avoid retry
|
|
411
|
+
* @returns {Promise<string>|null} The data of the file or {@code null} if the file does not exist
|
|
412
|
+
*/
|
|
413
|
+
async getFileFromPath(parentId, path, noRetry) {
|
|
414
|
+
const item = await this.getItemFromPath(parentId, path);
|
|
415
|
+
if (!item) {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
// noinspection ES6RedundantAwait (need to catch exception)
|
|
420
|
+
return await this.getFile(item.id);
|
|
421
|
+
} catch (e) {
|
|
422
|
+
if (e.statusCode === 404) {
|
|
423
|
+
if (noRetry) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
this.log.info(`file ${item.id} does not exist - invalidating cache and retry`);
|
|
427
|
+
item.invalidate();
|
|
428
|
+
return this.getFileFromPath(parentId, path, true);
|
|
429
|
+
} else {
|
|
430
|
+
throw e;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Returns an (uncached) document directly via the google api
|
|
437
|
+
* @param {string} documentId
|
|
438
|
+
* @returns {object} document
|
|
439
|
+
*/
|
|
346
440
|
async getDocument(documentId) {
|
|
347
441
|
const docs = google.docs({
|
|
348
442
|
version: 'v1',
|
|
@@ -358,4 +452,35 @@ export class GoogleClient {
|
|
|
358
452
|
throw e;
|
|
359
453
|
}
|
|
360
454
|
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Fetches the document from the give path. If the document with the internal id could not be
|
|
458
|
+
* fetched, the item cache is invalidated and the operation is retried. this is to support
|
|
459
|
+
* moved items.
|
|
460
|
+
* @param {string} parentId
|
|
461
|
+
* @param {string} path
|
|
462
|
+
* @param {boolean} noRetry {@code true} to avoid retry
|
|
463
|
+
* @returns {Promise<object>|null} The document or {@code null} if the document does not exist
|
|
464
|
+
*/
|
|
465
|
+
async getDocumentFromPath(parentId, path, noRetry) {
|
|
466
|
+
const item = await this.getItemFromPath(parentId, path);
|
|
467
|
+
if (!item) {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
try {
|
|
471
|
+
// noinspection ES6RedundantAwait (need to catch exception)
|
|
472
|
+
return await this.getDocument(item.id);
|
|
473
|
+
} catch (e) {
|
|
474
|
+
if (e.statusCode === 404) {
|
|
475
|
+
if (noRetry) {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
this.log.info(`document ${item.id} does not exist - invalidating cache and retry`);
|
|
479
|
+
item.invalidate();
|
|
480
|
+
return this.getDocumentFromPath(parentId, path, true);
|
|
481
|
+
} else {
|
|
482
|
+
throw e;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
361
486
|
}
|
package/src/cache.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2020 Adobe. All rights reserved.
|
|
3
|
-
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
-
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
*
|
|
7
|
-
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
-
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
-
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
-
* governing permissions and limitations under the License.
|
|
11
|
-
*/
|
|
12
|
-
import LRU from 'lru-cache';
|
|
13
|
-
|
|
14
|
-
let lru = new LRU({ max: 1000, ttl: 60000 });
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Returns a memoized version of the function `fn`.
|
|
18
|
-
* @param {function} fn a function to memoize
|
|
19
|
-
* @param {object} opts caching options
|
|
20
|
-
* @param {function} opts.hash a hash function to build a cache key.
|
|
21
|
-
* The hash function will be called with the `fn` and a list of
|
|
22
|
-
* it's arguments. A good hashing function will discard irrelevant
|
|
23
|
-
* arguments and join the resulting arguments
|
|
24
|
-
* @param {function} opts.cacheresult a predicate function that will be called
|
|
25
|
-
* with the result of the function execution. Only when this function returns
|
|
26
|
-
* `true` will the result be cached. The default is that all results are
|
|
27
|
-
* cached.
|
|
28
|
-
* @param {function} opts.cacheerror a predicate function that will be called
|
|
29
|
-
* with the error that the function execution throws. Only when this
|
|
30
|
-
* function returns `true` will the error be cached. The default is that
|
|
31
|
-
* errors are never cached, so that each new invocation will be uncached.
|
|
32
|
-
*/
|
|
33
|
-
export default function cache(fn, opts = {}) {
|
|
34
|
-
const {
|
|
35
|
-
hash = (...args) => args.join(),
|
|
36
|
-
cacheresult = () => true,
|
|
37
|
-
cacheerror = () => false,
|
|
38
|
-
} = opts;
|
|
39
|
-
return async function cached(...args) {
|
|
40
|
-
const key = hash(fn, ...args);
|
|
41
|
-
const entry = lru.get(key);
|
|
42
|
-
if (entry) {
|
|
43
|
-
if (entry.err) {
|
|
44
|
-
throw entry.err;
|
|
45
|
-
}
|
|
46
|
-
return entry.ok;
|
|
47
|
-
}
|
|
48
|
-
try {
|
|
49
|
-
// invoke the function
|
|
50
|
-
const result = await fn(...args);
|
|
51
|
-
if (cacheresult(result)) {
|
|
52
|
-
// store the result under ok if permitted
|
|
53
|
-
lru.set(key, { ok: result });
|
|
54
|
-
}
|
|
55
|
-
// and return the result
|
|
56
|
-
return result;
|
|
57
|
-
} catch (err) {
|
|
58
|
-
if (cacheerror(err)) {
|
|
59
|
-
// store the error under err if permitted
|
|
60
|
-
lru.set(key, { err });
|
|
61
|
-
}
|
|
62
|
-
// and throw the error
|
|
63
|
-
throw err;
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Resets the QuickLRU cache with new options. Existing cache entries
|
|
70
|
-
* will be cleared.
|
|
71
|
-
* @param {object} opts options
|
|
72
|
-
* @param {integer} opts.maxSize maximum size of the cache
|
|
73
|
-
*/
|
|
74
|
-
cache.options = (opts) => {
|
|
75
|
-
lru = new LRU(opts);
|
|
76
|
-
|
|
77
|
-
return cache;
|
|
78
|
-
};
|