@browserless.io/browserless 2.5.0 → 2.6.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/CHANGELOG.md +9 -1
- package/README.md +55 -36
- package/build/config.d.ts +2 -2
- package/build/config.js +3 -3
- package/build/data/classes.json +1 -1
- package/build/data/selectors.json +1 -1
- package/build/http.d.ts +1 -0
- package/build/http.js +1 -0
- package/build/routes/chrome/http/content.post.body.json +8 -8
- package/build/routes/chrome/http/pdf.post.body.json +8 -8
- package/build/routes/chrome/http/scrape.post.body.json +8 -8
- package/build/routes/chrome/http/screenshot.post.body.json +9 -9
- package/build/routes/chromium/http/content.post.body.json +8 -8
- package/build/routes/chromium/http/pdf.post.body.json +8 -8
- package/build/routes/chromium/http/scrape.post.body.json +8 -8
- package/build/routes/chromium/http/screenshot.post.body.json +9 -9
- package/build/routes/management/http/active.get.d.ts +16 -0
- package/build/routes/management/http/active.get.js +17 -0
- package/build/routes/management/tests/management.spec.js +7 -0
- package/build/server.js +1 -1
- package/build/types.d.ts +6 -4
- package/build/types.js +1 -0
- package/build/utils.d.ts +1 -1
- package/docker/base/Dockerfile +1 -1
- package/extensions/ublock/1p-filters.html +4 -3
- package/extensions/ublock/3p-filters.html +3 -3
- package/extensions/ublock/_locales/ar/messages.json +16 -4
- package/extensions/ublock/_locales/az/messages.json +16 -4
- package/extensions/ublock/_locales/be/messages.json +19 -7
- package/extensions/ublock/_locales/bg/messages.json +16 -4
- package/extensions/ublock/_locales/bn/messages.json +33 -21
- package/extensions/ublock/_locales/br_FR/messages.json +33 -21
- package/extensions/ublock/_locales/bs/messages.json +16 -4
- package/extensions/ublock/_locales/ca/messages.json +16 -4
- package/extensions/ublock/_locales/cs/messages.json +16 -4
- package/extensions/ublock/_locales/cv/messages.json +16 -4
- package/extensions/ublock/_locales/cy/messages.json +16 -4
- package/extensions/ublock/_locales/da/messages.json +21 -9
- package/extensions/ublock/_locales/de/messages.json +17 -5
- package/extensions/ublock/_locales/el/messages.json +16 -4
- package/extensions/ublock/_locales/en/messages.json +16 -4
- package/extensions/ublock/_locales/en_GB/messages.json +16 -4
- package/extensions/ublock/_locales/eo/messages.json +17 -5
- package/extensions/ublock/_locales/es/messages.json +16 -4
- package/extensions/ublock/_locales/et/messages.json +16 -4
- package/extensions/ublock/_locales/eu/messages.json +16 -4
- package/extensions/ublock/_locales/fa/messages.json +24 -12
- package/extensions/ublock/_locales/fi/messages.json +16 -4
- package/extensions/ublock/_locales/fil/messages.json +16 -4
- package/extensions/ublock/_locales/fr/messages.json +16 -4
- package/extensions/ublock/_locales/fy/messages.json +16 -4
- package/extensions/ublock/_locales/gl/messages.json +16 -4
- package/extensions/ublock/_locales/gu/messages.json +16 -4
- package/extensions/ublock/_locales/he/messages.json +25 -13
- package/extensions/ublock/_locales/hi/messages.json +31 -19
- package/extensions/ublock/_locales/hr/messages.json +16 -4
- package/extensions/ublock/_locales/hu/messages.json +16 -4
- package/extensions/ublock/_locales/hy/messages.json +17 -5
- package/extensions/ublock/_locales/id/messages.json +16 -4
- package/extensions/ublock/_locales/it/messages.json +17 -5
- package/extensions/ublock/_locales/ja/messages.json +16 -4
- package/extensions/ublock/_locales/ka/messages.json +16 -4
- package/extensions/ublock/_locales/kk/messages.json +16 -4
- package/extensions/ublock/_locales/kn/messages.json +74 -62
- package/extensions/ublock/_locales/ko/messages.json +16 -4
- package/extensions/ublock/_locales/lt/messages.json +23 -11
- package/extensions/ublock/_locales/lv/messages.json +16 -4
- package/extensions/ublock/_locales/mk/messages.json +16 -4
- package/extensions/ublock/_locales/ml/messages.json +19 -7
- package/extensions/ublock/_locales/mr/messages.json +16 -4
- package/extensions/ublock/_locales/ms/messages.json +16 -4
- package/extensions/ublock/_locales/nb/messages.json +16 -4
- package/extensions/ublock/_locales/nl/messages.json +16 -4
- package/extensions/ublock/_locales/no/messages.json +16 -4
- package/extensions/ublock/_locales/oc/messages.json +16 -4
- package/extensions/ublock/_locales/pa/messages.json +16 -4
- package/extensions/ublock/_locales/pl/messages.json +17 -5
- package/extensions/ublock/_locales/pt_BR/messages.json +16 -4
- package/extensions/ublock/_locales/pt_PT/messages.json +16 -4
- package/extensions/ublock/_locales/ro/messages.json +17 -5
- package/extensions/ublock/_locales/ru/messages.json +16 -4
- package/extensions/ublock/_locales/si/messages.json +16 -4
- package/extensions/ublock/_locales/sk/messages.json +16 -4
- package/extensions/ublock/_locales/sl/messages.json +16 -4
- package/extensions/ublock/_locales/so/messages.json +16 -4
- package/extensions/ublock/_locales/sq/messages.json +16 -4
- package/extensions/ublock/_locales/sr/messages.json +16 -4
- package/extensions/ublock/_locales/sv/messages.json +20 -8
- package/extensions/ublock/_locales/sw/messages.json +16 -4
- package/extensions/ublock/_locales/ta/messages.json +16 -4
- package/extensions/ublock/_locales/te/messages.json +16 -4
- package/extensions/ublock/_locales/th/messages.json +42 -30
- package/extensions/ublock/_locales/tr/messages.json +19 -7
- package/extensions/ublock/_locales/uk/messages.json +16 -4
- package/extensions/ublock/_locales/ur/messages.json +16 -4
- package/extensions/ublock/_locales/vi/messages.json +16 -4
- package/extensions/ublock/_locales/zh_CN/messages.json +16 -4
- package/extensions/ublock/_locales/zh_TW/messages.json +42 -30
- package/extensions/ublock/assets/assets.json +95 -78
- package/extensions/ublock/assets/resources/scriptlets.js +70 -24
- package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +6258 -3453
- package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +277 -40
- package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +8 -32
- package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +107 -12
- package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +1160 -954
- package/extensions/ublock/assets/ublock/badlists.txt +1 -2
- package/extensions/ublock/assets/ublock/badware.min.txt +395 -270
- package/extensions/ublock/assets/ublock/filters.min.txt +1176 -1238
- package/extensions/ublock/assets/ublock/privacy.min.txt +32 -31
- package/extensions/ublock/assets/ublock/quick-fixes.min.txt +120 -110
- package/extensions/ublock/assets/ublock/unbreak.min.txt +75 -36
- package/extensions/ublock/css/1p-filters.css +2 -1
- package/extensions/ublock/css/3p-filters.css +1 -16
- package/extensions/ublock/css/advanced-settings.css +1 -0
- package/extensions/ublock/css/asset-viewer.css +1 -0
- package/extensions/ublock/css/code-viewer.css +1 -0
- package/extensions/ublock/css/codemirror.css +37 -10
- package/extensions/ublock/css/common.css +36 -2
- package/extensions/ublock/css/dashboard.css +9 -3
- package/extensions/ublock/css/devtools.css +1 -0
- package/extensions/ublock/css/document-blocked.css +3 -3
- package/extensions/ublock/css/dom-inspector.css +1 -0
- package/extensions/ublock/css/dyna-rules.css +1 -0
- package/extensions/ublock/css/epicker-ui.css +76 -66
- package/extensions/ublock/css/fa-icons.css +1 -0
- package/extensions/ublock/css/logger-ui.css +2 -0
- package/extensions/ublock/css/popup-fenix.css +1 -0
- package/extensions/ublock/css/whitelist.css +1 -0
- package/extensions/ublock/dashboard.html +20 -13
- package/extensions/ublock/devtools.html +2 -0
- package/extensions/ublock/dyna-rules.html +2 -2
- package/extensions/ublock/img/flags-of-the-world/np.png +0 -0
- package/extensions/ublock/img/fontawesome/fontawesome-defs.svg +1 -0
- package/extensions/ublock/js/1p-filters.js +72 -23
- package/extensions/ublock/js/3p-filters.js +71 -25
- package/extensions/ublock/js/asset-viewer.js +1 -0
- package/extensions/ublock/js/assets.js +83 -89
- package/extensions/ublock/js/background.js +20 -27
- package/extensions/ublock/js/base64-custom.js +1 -102
- package/extensions/ublock/js/benchmarks.js +36 -21
- package/extensions/ublock/js/biditrie.js +8 -23
- package/extensions/ublock/js/broadcast.js +2 -4
- package/extensions/ublock/js/cachestorage.js +594 -396
- package/extensions/ublock/js/codemirror/search.js +49 -37
- package/extensions/ublock/js/codemirror/ubo-static-filtering.js +233 -215
- package/extensions/ublock/js/contentscript-extra.js +31 -1
- package/extensions/ublock/js/cosmetic-filtering.js +35 -33
- package/extensions/ublock/js/dashboard.js +11 -7
- package/extensions/ublock/js/devtools.js +22 -0
- package/extensions/ublock/js/dom.js +2 -2
- package/extensions/ublock/js/dyna-rules.js +17 -16
- package/extensions/ublock/js/epicker-ui.js +41 -16
- package/extensions/ublock/js/fa-icons.js +1 -0
- package/extensions/ublock/js/hntrie.js +10 -25
- package/extensions/ublock/js/i18n.js +15 -15
- package/extensions/ublock/js/logger-ui.js +9 -6
- package/extensions/ublock/js/messaging.js +51 -26
- package/extensions/ublock/js/pagestore.js +21 -23
- package/extensions/ublock/js/popup-fenix.js +35 -22
- package/extensions/ublock/js/redirect-engine.js +15 -30
- package/extensions/ublock/js/reverselookup.js +1 -1
- package/extensions/ublock/js/s14e-serializer.js +1405 -0
- package/extensions/ublock/js/scriptlet-filtering-core.js +1 -1
- package/extensions/ublock/js/scriptlets/epicker.js +27 -18
- package/extensions/ublock/js/settings.js +32 -21
- package/extensions/ublock/js/start.js +121 -62
- package/extensions/ublock/js/static-ext-filtering-db.js +6 -6
- package/extensions/ublock/js/static-ext-filtering.js +17 -28
- package/extensions/ublock/js/static-filtering-parser.js +26 -4
- package/extensions/ublock/js/static-net-filtering.js +69 -168
- package/extensions/ublock/js/storage.js +178 -155
- package/extensions/ublock/js/traffic.js +11 -7
- package/extensions/ublock/js/vapi-background.js +49 -62
- package/extensions/ublock/js/vapi-client.js +13 -16
- package/extensions/ublock/js/webext.js +10 -2
- package/extensions/ublock/js/whitelist.js +27 -25
- package/extensions/ublock/lib/publicsuffixlist/publicsuffixlist.js +3 -7
- package/extensions/ublock/manifest.json +2 -1
- package/extensions/ublock/web_accessible_resources/epicker-ui.html +5 -8
- package/extensions/ublock/whitelist.html +3 -4
- package/package.json +12 -12
- package/src/config.ts +3 -4
- package/src/http.ts +1 -0
- package/src/routes/management/http/active.get.ts +30 -0
- package/src/routes/management/tests/management.spec.ts +13 -0
- package/src/server.ts +1 -1
- package/src/types.ts +2 -1
- package/static/docs/swagger.json +57 -11
- package/static/docs/swagger.min.json +56 -10
- package/static/function/client.js +4155 -3350
- package/extensions/ublock/_locales/ku/messages.json +0 -1294
|
@@ -19,191 +19,440 @@
|
|
|
19
19
|
Home: https://github.com/gorhill/uBlock
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
/* global browser, IDBDatabase, indexedDB */
|
|
23
|
-
|
|
24
|
-
'use strict';
|
|
25
|
-
|
|
26
22
|
/******************************************************************************/
|
|
27
23
|
|
|
24
|
+
import * as s14e from './s14e-serializer.js';
|
|
25
|
+
|
|
28
26
|
import lz4Codec from './lz4.js';
|
|
29
|
-
import
|
|
27
|
+
import { ubolog } from './console.js';
|
|
30
28
|
import webext from './webext.js';
|
|
29
|
+
import µb from './background.js';
|
|
31
30
|
|
|
32
31
|
/******************************************************************************/
|
|
33
32
|
|
|
34
|
-
// The code below has been originally manually imported from:
|
|
35
|
-
// Commit: https://github.com/nikrolls/uBlock-Edge/commit/d1538ea9bea89d507219d3219592382eee306134
|
|
36
|
-
// Commit date: 29 October 2016
|
|
37
|
-
// Commit author: https://github.com/nikrolls
|
|
38
|
-
// Commit message: "Implement cacheStorage using IndexedDB"
|
|
39
|
-
|
|
40
|
-
// The original imported code has been subsequently modified as it was not
|
|
41
|
-
// compatible with Firefox.
|
|
42
|
-
// (a Promise thing, see https://github.com/dfahlander/Dexie.js/issues/317)
|
|
43
|
-
// Furthermore, code to migrate from browser.storage.local to vAPI.storage
|
|
44
|
-
// has been added, for seamless migration of cache-related entries into
|
|
45
|
-
// indexedDB.
|
|
46
|
-
|
|
47
|
-
// https://bugzilla.mozilla.org/show_bug.cgi?id=1371255
|
|
48
|
-
// Firefox-specific: we use indexedDB because browser.storage.local() has
|
|
49
|
-
// poor performance in Firefox.
|
|
50
|
-
// https://github.com/uBlockOrigin/uBlock-issues/issues/328
|
|
51
|
-
// Use IndexedDB for Chromium as well, to take advantage of LZ4
|
|
52
|
-
// compression.
|
|
53
|
-
// https://github.com/uBlockOrigin/uBlock-issues/issues/399
|
|
54
|
-
// Revert Chromium support of IndexedDB, use advanced setting to force
|
|
55
|
-
// IndexedDB.
|
|
56
|
-
// https://github.com/uBlockOrigin/uBlock-issues/issues/409
|
|
57
|
-
// Allow forcing the use of webext storage on Firefox.
|
|
58
|
-
|
|
59
33
|
const STORAGE_NAME = 'uBlock0CacheStorage';
|
|
34
|
+
const extensionStorage = webext.storage.local;
|
|
35
|
+
|
|
36
|
+
const keysFromGetArg = arg => {
|
|
37
|
+
if ( arg === null || arg === undefined ) { return []; }
|
|
38
|
+
const type = typeof arg;
|
|
39
|
+
if ( type === 'string' ) { return [ arg ]; }
|
|
40
|
+
if ( Array.isArray(arg) ) { return arg; }
|
|
41
|
+
if ( type !== 'object' ) { return; }
|
|
42
|
+
return Object.keys(arg);
|
|
43
|
+
};
|
|
60
44
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
45
|
+
let fastCache = 'indexedDB';
|
|
46
|
+
|
|
47
|
+
// https://eslint.org/docs/latest/rules/no-prototype-builtins
|
|
48
|
+
const hasOwnProperty = (o, p) =>
|
|
49
|
+
Object.prototype.hasOwnProperty.call(o, p);
|
|
50
|
+
|
|
51
|
+
/*******************************************************************************
|
|
52
|
+
*
|
|
53
|
+
* Extension storage
|
|
54
|
+
*
|
|
55
|
+
* Always available.
|
|
56
|
+
*
|
|
57
|
+
* */
|
|
58
|
+
|
|
59
|
+
const cacheStorage = (( ) => {
|
|
60
|
+
|
|
61
|
+
const exGet = (api, wanted, outbin) => {
|
|
62
|
+
return api.get(wanted).then(inbin => {
|
|
63
|
+
inbin = inbin || {};
|
|
64
|
+
const found = Object.keys(inbin);
|
|
65
|
+
Object.assign(outbin, inbin);
|
|
66
|
+
if ( found.length === wanted.length ) { return; }
|
|
67
|
+
const missing = [];
|
|
68
|
+
for ( const key of wanted ) {
|
|
69
|
+
if ( hasOwnProperty(outbin, key) ) { continue; }
|
|
70
|
+
missing.push(key);
|
|
71
|
+
}
|
|
72
|
+
return missing;
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const compress = async (bin, key, data) => {
|
|
77
|
+
const µbhs = µb.hiddenSettings;
|
|
78
|
+
const after = await s14e.serializeAsync(data, {
|
|
79
|
+
compress: µbhs.cacheStorageCompression,
|
|
80
|
+
compressThreshold: µbhs.cacheStorageCompressionThreshold,
|
|
81
|
+
multithreaded: µbhs.cacheStorageMultithread,
|
|
82
|
+
});
|
|
83
|
+
bin[key] = after;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const decompress = async (bin, key) => {
|
|
87
|
+
const data = bin[key];
|
|
88
|
+
if ( s14e.isSerialized(data) === false ) { return; }
|
|
89
|
+
const µbhs = µb.hiddenSettings;
|
|
90
|
+
const isLarge = data.length >= µbhs.cacheStorageCompressionThreshold;
|
|
91
|
+
bin[key] = await s14e.deserializeAsync(data, {
|
|
92
|
+
multithreaded: isLarge && µbhs.cacheStorageMultithread || 1,
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const api = {
|
|
97
|
+
get(argbin) {
|
|
98
|
+
const outbin = {};
|
|
99
|
+
return exGet(
|
|
100
|
+
cacheAPIs[fastCache],
|
|
101
|
+
keysFromGetArg(argbin),
|
|
102
|
+
outbin
|
|
103
|
+
).then(wanted => {
|
|
104
|
+
if ( wanted === undefined ) { return; }
|
|
105
|
+
return exGet(extensionStorage, wanted, outbin);
|
|
106
|
+
}).then(wanted => {
|
|
107
|
+
if ( wanted === undefined ) { return; }
|
|
108
|
+
if ( argbin instanceof Object === false ) { return; }
|
|
109
|
+
if ( Array.isArray(argbin) ) { return; }
|
|
110
|
+
for ( const key of wanted ) {
|
|
111
|
+
if ( hasOwnProperty(argbin, key) === false ) { continue; }
|
|
112
|
+
outbin[key] = argbin[key];
|
|
112
113
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
}).then(( ) => {
|
|
115
|
+
const promises = [];
|
|
116
|
+
for ( const key of Object.keys(outbin) ) {
|
|
117
|
+
promises.push(decompress(outbin, key));
|
|
118
|
+
}
|
|
119
|
+
return Promise.all(promises).then(( ) => outbin);
|
|
120
|
+
}).catch(reason => {
|
|
121
|
+
ubolog(reason);
|
|
116
122
|
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
async keys(regex) {
|
|
126
|
+
const results = await Promise.all([
|
|
127
|
+
cacheAPIs[fastCache].keys(regex),
|
|
128
|
+
extensionStorage.get(null).catch(( ) => {}),
|
|
129
|
+
]);
|
|
130
|
+
const keys = new Set(results[0]);
|
|
131
|
+
const bin = results[1] || {};
|
|
132
|
+
for ( const key of Object.keys(bin) ) {
|
|
133
|
+
if ( regex && regex.test(key) === false ) { continue; }
|
|
134
|
+
keys.add(key);
|
|
135
|
+
}
|
|
136
|
+
return keys;
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
async set(rawbin) {
|
|
140
|
+
const keys = Object.keys(rawbin);
|
|
141
|
+
if ( keys.length === 0 ) { return; }
|
|
142
|
+
const serializedbin = {};
|
|
143
|
+
const promises = [];
|
|
144
|
+
for ( const key of keys ) {
|
|
145
|
+
promises.push(compress(serializedbin, key, rawbin[key]));
|
|
146
|
+
}
|
|
147
|
+
await Promise.all(promises);
|
|
148
|
+
cacheAPIs[fastCache].set(rawbin, serializedbin);
|
|
149
|
+
return extensionStorage.set(serializedbin).catch(reason => {
|
|
150
|
+
ubolog(reason);
|
|
151
|
+
});
|
|
152
|
+
},
|
|
127
153
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
154
|
+
remove(...args) {
|
|
155
|
+
cacheAPIs[fastCache].remove(...args);
|
|
156
|
+
return extensionStorage.remove(...args).catch(reason => {
|
|
157
|
+
ubolog(reason);
|
|
158
|
+
});
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
clear(...args) {
|
|
162
|
+
cacheAPIs[fastCache].clear(...args);
|
|
163
|
+
return extensionStorage.clear(...args).catch(reason => {
|
|
164
|
+
ubolog(reason);
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
select(api) {
|
|
169
|
+
if ( hasOwnProperty(cacheAPIs, api) === false ) { return fastCache; }
|
|
170
|
+
fastCache = api;
|
|
171
|
+
for ( const k of Object.keys(cacheAPIs) ) {
|
|
172
|
+
if ( k === api ) { continue; }
|
|
173
|
+
cacheAPIs[k]['clear']();
|
|
174
|
+
}
|
|
175
|
+
return fastCache;
|
|
176
|
+
},
|
|
134
177
|
};
|
|
135
|
-
}
|
|
136
178
|
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
179
|
+
// Not all platforms support getBytesInUse
|
|
180
|
+
if ( extensionStorage.getBytesInUse instanceof Function ) {
|
|
181
|
+
api.getBytesInUse = function(...args) {
|
|
182
|
+
return extensionStorage.getBytesInUse(...args).catch(reason => {
|
|
183
|
+
ubolog(reason);
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
}
|
|
141
187
|
|
|
142
|
-
|
|
188
|
+
return api;
|
|
189
|
+
})();
|
|
190
|
+
|
|
191
|
+
/*******************************************************************************
|
|
192
|
+
*
|
|
193
|
+
* Cache API
|
|
194
|
+
*
|
|
195
|
+
* Purpose is to mirror cache-related items from extension storage, as its
|
|
196
|
+
* read/write operations are faster. May not be available/populated in
|
|
197
|
+
* private/incognito mode.
|
|
198
|
+
*
|
|
199
|
+
* */
|
|
200
|
+
|
|
201
|
+
const cacheAPI = (( ) => {
|
|
202
|
+
const caches = globalThis.caches;
|
|
203
|
+
let cacheStoragePromise;
|
|
204
|
+
|
|
205
|
+
const getAPI = ( ) => {
|
|
206
|
+
if ( cacheStoragePromise !== undefined ) { return cacheStoragePromise; }
|
|
207
|
+
cacheStoragePromise = new Promise(resolve => {
|
|
208
|
+
if ( typeof caches !== 'object' || caches === null ) {
|
|
209
|
+
ubolog('CacheStorage API not available');
|
|
210
|
+
resolve(null);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
resolve(caches.open(STORAGE_NAME));
|
|
214
|
+
}).catch(reason => {
|
|
215
|
+
ubolog(reason);
|
|
216
|
+
return null;
|
|
217
|
+
});
|
|
218
|
+
return cacheStoragePromise;
|
|
143
219
|
};
|
|
144
220
|
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
221
|
+
const urlPrefix = 'https://ublock0.invalid/';
|
|
222
|
+
|
|
223
|
+
const keyToURL = key =>
|
|
224
|
+
`${urlPrefix}${encodeURIComponent(key)}`;
|
|
225
|
+
|
|
226
|
+
const urlToKey = url =>
|
|
227
|
+
decodeURIComponent(url.slice(urlPrefix.length));
|
|
228
|
+
|
|
229
|
+
// Cache API is subject to quota so we will use it only for what is key
|
|
230
|
+
// performance-wise
|
|
231
|
+
const shouldCache = bin => {
|
|
232
|
+
const out = {};
|
|
233
|
+
for ( const key of Object.keys(bin) ) {
|
|
234
|
+
if ( key.startsWith('cache/' ) ) {
|
|
235
|
+
if ( /^cache\/(compiled|selfie)\//.test(key) === false ) { continue; }
|
|
236
|
+
}
|
|
237
|
+
out[key] = bin[key];
|
|
150
238
|
}
|
|
239
|
+
if ( Object.keys(out).length !== 0 ) { return out; }
|
|
151
240
|
};
|
|
152
241
|
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
242
|
+
const getOne = async key => {
|
|
243
|
+
const cache = await getAPI();
|
|
244
|
+
if ( cache === null ) { return; }
|
|
245
|
+
return cache.match(keyToURL(key)).then(response => {
|
|
246
|
+
if ( response === undefined ) { return; }
|
|
247
|
+
return response.text();
|
|
248
|
+
}).then(text => {
|
|
249
|
+
if ( text === undefined ) { return; }
|
|
250
|
+
return { key, text };
|
|
251
|
+
}).catch(reason => {
|
|
252
|
+
ubolog(reason);
|
|
253
|
+
});
|
|
254
|
+
};
|
|
156
255
|
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
256
|
+
const getAll = async ( ) => {
|
|
257
|
+
const cache = await getAPI();
|
|
258
|
+
if ( cache === null ) { return; }
|
|
259
|
+
return cache.keys().then(requests => {
|
|
260
|
+
const promises = [];
|
|
261
|
+
for ( const request of requests ) {
|
|
262
|
+
promises.push(getOne(urlToKey(request.url)));
|
|
263
|
+
}
|
|
264
|
+
return Promise.all(promises);
|
|
265
|
+
}).then(responses => {
|
|
266
|
+
const bin = {};
|
|
267
|
+
for ( const response of responses ) {
|
|
268
|
+
if ( response === undefined ) { continue; }
|
|
269
|
+
bin[response.key] = response.text;
|
|
270
|
+
}
|
|
271
|
+
return bin;
|
|
272
|
+
}).catch(reason => {
|
|
273
|
+
ubolog(reason);
|
|
274
|
+
});
|
|
162
275
|
};
|
|
163
276
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
277
|
+
const setOne = async (key, text) => {
|
|
278
|
+
if ( text === undefined ) { return removeOne(key); }
|
|
279
|
+
const blob = new Blob([ text ], { type: 'text/plain;charset=utf-8'});
|
|
280
|
+
const cache = await getAPI();
|
|
281
|
+
if ( cache === null ) { return; }
|
|
282
|
+
return cache
|
|
283
|
+
.put(keyToURL(key), new Response(blob))
|
|
284
|
+
.catch(reason => {
|
|
285
|
+
ubolog(reason);
|
|
286
|
+
});
|
|
287
|
+
};
|
|
173
288
|
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
289
|
+
const removeOne = async key => {
|
|
290
|
+
const cache = await getAPI();
|
|
291
|
+
if ( cache === null ) { return; }
|
|
292
|
+
return cache.delete(keyToURL(key)).catch(reason => {
|
|
293
|
+
ubolog(reason);
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
async get(arg) {
|
|
299
|
+
const keys = keysFromGetArg(arg);
|
|
300
|
+
if ( keys === undefined ) { return; }
|
|
301
|
+
if ( keys.length === 0 ) {
|
|
302
|
+
return getAll();
|
|
303
|
+
}
|
|
304
|
+
const bin = {};
|
|
305
|
+
const toFetch = keys.slice();
|
|
306
|
+
const hasDefault = typeof arg === 'object' && Array.isArray(arg) === false;
|
|
307
|
+
for ( let i = 0; i < toFetch.length; i++ ) {
|
|
308
|
+
const key = toFetch[i];
|
|
309
|
+
if ( hasDefault && arg[key] !== undefined ) {
|
|
310
|
+
bin[key] = arg[key];
|
|
189
311
|
}
|
|
190
|
-
|
|
312
|
+
toFetch[i] = getOne(key);
|
|
191
313
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
314
|
+
const responses = await Promise.all(toFetch);
|
|
315
|
+
for ( const response of responses ) {
|
|
316
|
+
if ( response === undefined ) { continue; }
|
|
317
|
+
const { key, text } = response;
|
|
318
|
+
if ( typeof key !== 'string' ) { continue; }
|
|
319
|
+
if ( typeof text !== 'string' ) { continue; }
|
|
320
|
+
bin[key] = text;
|
|
196
321
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
322
|
+
if ( Object.keys(bin).length === 0 ) { return; }
|
|
323
|
+
return bin;
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
async keys(regex) {
|
|
327
|
+
const cache = await getAPI();
|
|
328
|
+
if ( cache === null ) { return []; }
|
|
329
|
+
return cache.keys().then(requests =>
|
|
330
|
+
requests.map(r => urlToKey(r.url))
|
|
331
|
+
.filter(k => regex === undefined || regex.test(k))
|
|
332
|
+
).catch(( ) => []);
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
async set(rawbin, serializedbin) {
|
|
336
|
+
const bin = shouldCache(serializedbin);
|
|
337
|
+
if ( bin === undefined ) { return; }
|
|
338
|
+
const keys = Object.keys(bin);
|
|
339
|
+
const promises = [];
|
|
340
|
+
for ( const key of keys ) {
|
|
341
|
+
promises.push(setOne(key, bin[key]));
|
|
342
|
+
}
|
|
343
|
+
return Promise.all(promises);
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
remove(keys) {
|
|
347
|
+
const toRemove = [];
|
|
348
|
+
if ( typeof keys === 'string' ) {
|
|
349
|
+
toRemove.push(removeOne(keys));
|
|
350
|
+
} else if ( Array.isArray(keys) ) {
|
|
351
|
+
for ( const key of keys ) {
|
|
352
|
+
toRemove.push(removeOne(key));
|
|
206
353
|
}
|
|
354
|
+
}
|
|
355
|
+
return Promise.all(toRemove);
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
async clear() {
|
|
359
|
+
if ( typeof caches !== 'object' || caches === null ) { return; }
|
|
360
|
+
return globalThis.caches.delete(STORAGE_NAME).catch(reason => {
|
|
361
|
+
ubolog(reason);
|
|
362
|
+
});
|
|
363
|
+
},
|
|
364
|
+
|
|
365
|
+
shutdown() {
|
|
366
|
+
cacheStoragePromise = undefined;
|
|
367
|
+
return this.clear();
|
|
368
|
+
},
|
|
369
|
+
};
|
|
370
|
+
})();
|
|
371
|
+
|
|
372
|
+
/*******************************************************************************
|
|
373
|
+
*
|
|
374
|
+
* In-memory storage
|
|
375
|
+
*
|
|
376
|
+
* */
|
|
377
|
+
|
|
378
|
+
const memoryStorage = (( ) => {
|
|
379
|
+
|
|
380
|
+
const sessionStorage = vAPI.sessionStorage;
|
|
381
|
+
|
|
382
|
+
// This should help speed up loading from suspended state in Firefox for
|
|
383
|
+
// Android.
|
|
384
|
+
// 20240228 Observation: Slows down loading from suspended state in
|
|
385
|
+
// Firefox desktop. Could be different in Firefox for Android.
|
|
386
|
+
const shouldCache = bin => {
|
|
387
|
+
const out = {};
|
|
388
|
+
for ( const key of Object.keys(bin) ) {
|
|
389
|
+
if ( key.startsWith('cache/compiled/') ) { continue; }
|
|
390
|
+
out[key] = bin[key];
|
|
391
|
+
}
|
|
392
|
+
if ( Object.keys(out).length !== 0 ) { return out; }
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
get(...args) {
|
|
397
|
+
return sessionStorage.get(...args).then(bin => {
|
|
398
|
+
return bin;
|
|
399
|
+
}).catch(reason => {
|
|
400
|
+
ubolog(reason);
|
|
401
|
+
});
|
|
402
|
+
},
|
|
403
|
+
|
|
404
|
+
async keys(regex) {
|
|
405
|
+
const bin = await this.get(null);
|
|
406
|
+
const keys = [];
|
|
407
|
+
for ( const key of Object.keys(bin || {}) ) {
|
|
408
|
+
if ( regex && regex.test(key) === false ) { continue; }
|
|
409
|
+
keys.push(key);
|
|
410
|
+
}
|
|
411
|
+
return keys;
|
|
412
|
+
},
|
|
413
|
+
|
|
414
|
+
async set(rawbin, serializedbin) {
|
|
415
|
+
const bin = shouldCache(serializedbin);
|
|
416
|
+
if ( bin === undefined ) { return; }
|
|
417
|
+
return sessionStorage.set(bin).catch(reason => {
|
|
418
|
+
ubolog(reason);
|
|
419
|
+
});
|
|
420
|
+
},
|
|
421
|
+
|
|
422
|
+
remove(...args) {
|
|
423
|
+
return sessionStorage.remove(...args).catch(reason => {
|
|
424
|
+
ubolog(reason);
|
|
425
|
+
});
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
clear(...args) {
|
|
429
|
+
return sessionStorage.clear(...args).catch(reason => {
|
|
430
|
+
ubolog(reason);
|
|
431
|
+
});
|
|
432
|
+
},
|
|
433
|
+
|
|
434
|
+
shutdown() {
|
|
435
|
+
return this.clear();
|
|
436
|
+
},
|
|
437
|
+
};
|
|
438
|
+
})();
|
|
439
|
+
|
|
440
|
+
/*******************************************************************************
|
|
441
|
+
*
|
|
442
|
+
* IndexedDB
|
|
443
|
+
*
|
|
444
|
+
* Deprecated, exists only for the purpose of migrating from older versions.
|
|
445
|
+
*
|
|
446
|
+
* */
|
|
447
|
+
|
|
448
|
+
const idbStorage = (( ) => {
|
|
449
|
+
let dbPromise;
|
|
450
|
+
|
|
451
|
+
const getDb = function() {
|
|
452
|
+
if ( dbPromise !== undefined ) { return dbPromise; }
|
|
453
|
+
dbPromise = new Promise(resolve => {
|
|
454
|
+
const req = indexedDB.open(STORAGE_NAME, 1);
|
|
455
|
+
req.onupgradeneeded = ev => {
|
|
207
456
|
if ( ev.oldVersion === 1 ) { return; }
|
|
208
457
|
try {
|
|
209
458
|
const db = ev.target.result;
|
|
@@ -212,35 +461,37 @@ const selectIDB = async function() {
|
|
|
212
461
|
req.onerror();
|
|
213
462
|
}
|
|
214
463
|
};
|
|
215
|
-
req.onsuccess =
|
|
464
|
+
req.onsuccess = ev => {
|
|
216
465
|
if ( resolve === undefined ) { return; }
|
|
217
|
-
|
|
218
|
-
db = ev.target.result;
|
|
219
|
-
dbPromise = undefined;
|
|
220
|
-
resolve(db);
|
|
466
|
+
resolve(ev.target.result || null);
|
|
221
467
|
resolve = undefined;
|
|
222
468
|
};
|
|
223
|
-
req.onerror = req.onblocked =
|
|
469
|
+
req.onerror = req.onblocked = ( ) => {
|
|
224
470
|
if ( resolve === undefined ) { return; }
|
|
225
|
-
req
|
|
226
|
-
console.log(this.error);
|
|
227
|
-
db = null;
|
|
228
|
-
dbPromise = undefined;
|
|
471
|
+
ubolog(req.error);
|
|
229
472
|
resolve(null);
|
|
230
473
|
resolve = undefined;
|
|
231
474
|
};
|
|
232
|
-
vAPI.defer.once(
|
|
475
|
+
vAPI.defer.once(10000).then(( ) => {
|
|
233
476
|
if ( resolve === undefined ) { return; }
|
|
234
|
-
db = null;
|
|
235
|
-
dbPromise = undefined;
|
|
236
477
|
resolve(null);
|
|
237
478
|
resolve = undefined;
|
|
238
479
|
});
|
|
480
|
+
}).catch(reason => {
|
|
481
|
+
ubolog(`idbStorage() / getDb() failed: ${reason}`);
|
|
482
|
+
return null;
|
|
239
483
|
});
|
|
240
484
|
return dbPromise;
|
|
241
485
|
};
|
|
242
486
|
|
|
243
|
-
|
|
487
|
+
// Cache API is subject to quota so we will use it only for what is key
|
|
488
|
+
// performance-wise
|
|
489
|
+
const shouldCache = key => {
|
|
490
|
+
if ( key.startsWith('cache/') === false ) { return true; }
|
|
491
|
+
return /^cache\/(compiled|selfie)\//.test(key);
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
const fromBlob = data => {
|
|
244
495
|
if ( data instanceof Blob === false ) {
|
|
245
496
|
return Promise.resolve(data);
|
|
246
497
|
}
|
|
@@ -253,277 +504,224 @@ const selectIDB = async function() {
|
|
|
253
504
|
});
|
|
254
505
|
};
|
|
255
506
|
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
return Promise.resolve(value);
|
|
507
|
+
const decompress = (key, value) => {
|
|
508
|
+
return lz4Codec.decode(value, fromBlob).then(value => {
|
|
509
|
+
return { key, value };
|
|
510
|
+
});
|
|
261
511
|
};
|
|
262
512
|
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
513
|
+
const getAllEntries = async function() {
|
|
514
|
+
const db = await getDb();
|
|
515
|
+
if ( db === null ) { return []; }
|
|
516
|
+
return new Promise(resolve => {
|
|
517
|
+
const entries = [];
|
|
518
|
+
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
|
519
|
+
transaction.oncomplete =
|
|
520
|
+
transaction.onerror =
|
|
521
|
+
transaction.onabort = ( ) => {
|
|
522
|
+
resolve(Promise.all(entries));
|
|
523
|
+
};
|
|
524
|
+
const table = transaction.objectStore(STORAGE_NAME);
|
|
525
|
+
const req = table.openCursor();
|
|
526
|
+
req.onsuccess = ev => {
|
|
527
|
+
const cursor = ev.target && ev.target.result;
|
|
528
|
+
if ( !cursor ) { return; }
|
|
529
|
+
const { key, value } = cursor.value;
|
|
530
|
+
if ( value instanceof Blob ) {
|
|
531
|
+
entries.push(decompress(key, value));
|
|
532
|
+
} else {
|
|
533
|
+
entries.push({ key, value });
|
|
534
|
+
}
|
|
535
|
+
cursor.continue();
|
|
536
|
+
};
|
|
537
|
+
}).catch(reason => {
|
|
538
|
+
ubolog(`idbStorage() / getAllEntries() failed: ${reason}`);
|
|
539
|
+
return [];
|
|
266
540
|
});
|
|
267
541
|
};
|
|
268
542
|
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
543
|
+
const getAllKeys = async function(regex) {
|
|
544
|
+
const db = await getDb();
|
|
545
|
+
if ( db === null ) { return []; }
|
|
546
|
+
return new Promise(resolve => {
|
|
547
|
+
const keys = [];
|
|
548
|
+
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
|
549
|
+
transaction.oncomplete =
|
|
550
|
+
transaction.onerror =
|
|
551
|
+
transaction.onabort = ( ) => {
|
|
552
|
+
resolve(keys);
|
|
553
|
+
};
|
|
554
|
+
const table = transaction.objectStore(STORAGE_NAME);
|
|
555
|
+
const req = table.openCursor();
|
|
556
|
+
req.onsuccess = ev => {
|
|
557
|
+
const cursor = ev.target && ev.target.result;
|
|
558
|
+
if ( !cursor ) { return; }
|
|
559
|
+
if ( regex && regex.test(cursor.key) === false ) { return; }
|
|
560
|
+
keys.push(cursor.key);
|
|
561
|
+
cursor.continue();
|
|
562
|
+
};
|
|
563
|
+
}).catch(reason => {
|
|
564
|
+
ubolog(`idbStorage() / getAllKeys() failed: ${reason}`);
|
|
565
|
+
return [];
|
|
272
566
|
});
|
|
273
567
|
};
|
|
274
568
|
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
if (
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
569
|
+
const getEntries = async function(keys) {
|
|
570
|
+
const db = await getDb();
|
|
571
|
+
if ( db === null ) { return []; }
|
|
572
|
+
return new Promise(resolve => {
|
|
573
|
+
const entries = [];
|
|
574
|
+
const gotOne = ev => {
|
|
575
|
+
const { result } = ev.target;
|
|
576
|
+
if ( typeof result !== 'object' ) { return; }
|
|
577
|
+
if ( result === null ) { return; }
|
|
578
|
+
const { key, value } = result;
|
|
579
|
+
if ( value instanceof Blob ) {
|
|
580
|
+
entries.push(decompress(key, value));
|
|
581
|
+
} else {
|
|
582
|
+
entries.push({ key, value });
|
|
583
|
+
}
|
|
584
|
+
};
|
|
289
585
|
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
|
290
586
|
transaction.oncomplete =
|
|
291
587
|
transaction.onerror =
|
|
292
588
|
transaction.onabort = ( ) => {
|
|
293
|
-
Promise.all(
|
|
294
|
-
callback(keyvalStore);
|
|
295
|
-
});
|
|
589
|
+
resolve(Promise.all(entries));
|
|
296
590
|
};
|
|
297
591
|
const table = transaction.objectStore(STORAGE_NAME);
|
|
298
592
|
for ( const key of keys ) {
|
|
299
593
|
const req = table.get(key);
|
|
300
594
|
req.onsuccess = gotOne;
|
|
301
|
-
req.onerror =
|
|
595
|
+
req.onerror = ( ) => { };
|
|
302
596
|
}
|
|
303
|
-
}
|
|
304
|
-
catch(reason) {
|
|
305
|
-
console.info(`cacheStorage.getFromDb() failed: ${reason}`);
|
|
306
|
-
callback();
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
const visitAllFromDb = async function(visitFn) {
|
|
311
|
-
const db = await getDb();
|
|
312
|
-
if ( !db ) { return visitFn(); }
|
|
313
|
-
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
|
314
|
-
transaction.oncomplete =
|
|
315
|
-
transaction.onerror =
|
|
316
|
-
transaction.onabort = ( ) => visitFn();
|
|
317
|
-
const table = transaction.objectStore(STORAGE_NAME);
|
|
318
|
-
const req = table.openCursor();
|
|
319
|
-
req.onsuccess = function(ev) {
|
|
320
|
-
let cursor = ev.target && ev.target.result;
|
|
321
|
-
if ( !cursor ) { return; }
|
|
322
|
-
let entry = cursor.value;
|
|
323
|
-
visitFn(entry);
|
|
324
|
-
cursor.continue();
|
|
325
|
-
};
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
const getAllFromDb = function(callback) {
|
|
329
|
-
if ( typeof callback !== 'function' ) { return; }
|
|
330
|
-
const promises = [];
|
|
331
|
-
const keyvalStore = {};
|
|
332
|
-
visitAllFromDb(entry => {
|
|
333
|
-
if ( entry === undefined ) {
|
|
334
|
-
Promise.all(promises).then(( ) => {
|
|
335
|
-
callback(keyvalStore);
|
|
336
|
-
});
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
const { key, value } = entry;
|
|
340
|
-
keyvalStore[key] = value;
|
|
341
|
-
if ( entry.value instanceof Blob === false ) { return; }
|
|
342
|
-
promises.push(decompress(keyvalStore, key, value));
|
|
343
597
|
}).catch(reason => {
|
|
344
|
-
|
|
345
|
-
|
|
598
|
+
ubolog(`idbStorage() / getEntries() failed: ${reason}`);
|
|
599
|
+
return [];
|
|
346
600
|
});
|
|
347
601
|
};
|
|
348
602
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const putToDb = async function(keyvalStore, callback) {
|
|
356
|
-
if ( typeof callback !== 'function' ) {
|
|
357
|
-
callback = noopfn;
|
|
603
|
+
const getAll = async ( ) => {
|
|
604
|
+
const entries = await getAllEntries();
|
|
605
|
+
const outbin = {};
|
|
606
|
+
for ( const { key, value } of entries ) {
|
|
607
|
+
outbin[key] = value;
|
|
358
608
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
609
|
+
return outbin;
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
const setEntries = async inbin => {
|
|
613
|
+
const keys = Object.keys(inbin);
|
|
614
|
+
if ( keys.length === 0 ) { return; }
|
|
615
|
+
const db = await getDb();
|
|
616
|
+
if ( db === null ) { return; }
|
|
617
|
+
return new Promise(resolve => {
|
|
618
|
+
const entries = [];
|
|
619
|
+
for ( const key of keys ) {
|
|
620
|
+
entries.push({ key, value: inbin[key] });
|
|
371
621
|
}
|
|
372
|
-
|
|
373
|
-
}
|
|
374
|
-
const finish = ( ) => {
|
|
375
|
-
if ( callback === undefined ) { return; }
|
|
376
|
-
let cb = callback;
|
|
377
|
-
callback = undefined;
|
|
378
|
-
cb();
|
|
379
|
-
};
|
|
380
|
-
try {
|
|
381
|
-
const results = await Promise.all(promises);
|
|
382
|
-
const db = results[0];
|
|
383
|
-
if ( !db ) { return callback(); }
|
|
384
|
-
const transaction = db.transaction(
|
|
385
|
-
STORAGE_NAME,
|
|
386
|
-
'readwrite'
|
|
387
|
-
);
|
|
622
|
+
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
|
388
623
|
transaction.oncomplete =
|
|
389
624
|
transaction.onerror =
|
|
390
|
-
transaction.onabort =
|
|
625
|
+
transaction.onabort = ( ) => {
|
|
626
|
+
resolve();
|
|
627
|
+
};
|
|
391
628
|
const table = transaction.objectStore(STORAGE_NAME);
|
|
392
629
|
for ( const entry of entries ) {
|
|
393
630
|
table.put(entry);
|
|
394
631
|
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
}
|
|
632
|
+
}).catch(reason => {
|
|
633
|
+
ubolog(`idbStorage() / setEntries() failed: ${reason}`);
|
|
634
|
+
});
|
|
398
635
|
};
|
|
399
636
|
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
const finish = ( ) => {
|
|
407
|
-
if ( callback === undefined ) { return; }
|
|
408
|
-
let cb = callback;
|
|
409
|
-
callback = undefined;
|
|
410
|
-
cb();
|
|
411
|
-
};
|
|
412
|
-
try {
|
|
413
|
-
const db = await getDb();
|
|
414
|
-
if ( !db ) { return callback(); }
|
|
637
|
+
const deleteEntries = async arg => {
|
|
638
|
+
const keys = Array.isArray(arg) ? arg.slice() : [ arg ];
|
|
639
|
+
if ( keys.length === 0 ) { return; }
|
|
640
|
+
const db = await getDb();
|
|
641
|
+
if ( db === null ) { return; }
|
|
642
|
+
return new Promise(resolve => {
|
|
415
643
|
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
|
416
644
|
transaction.oncomplete =
|
|
417
645
|
transaction.onerror =
|
|
418
|
-
transaction.onabort =
|
|
646
|
+
transaction.onabort = ( ) => {
|
|
647
|
+
resolve();
|
|
648
|
+
};
|
|
419
649
|
const table = transaction.objectStore(STORAGE_NAME);
|
|
420
650
|
for ( const key of keys ) {
|
|
421
651
|
table.delete(key);
|
|
422
652
|
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
const clearDb = async function(callback) {
|
|
429
|
-
if ( typeof callback !== 'function' ) {
|
|
430
|
-
callback = noopfn;
|
|
431
|
-
}
|
|
432
|
-
try {
|
|
433
|
-
const db = await getDb();
|
|
434
|
-
if ( !db ) { return callback(); }
|
|
435
|
-
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
|
436
|
-
transaction.oncomplete =
|
|
437
|
-
transaction.onerror =
|
|
438
|
-
transaction.onabort = ( ) => {
|
|
439
|
-
callback();
|
|
440
|
-
};
|
|
441
|
-
transaction.objectStore(STORAGE_NAME).clear();
|
|
442
|
-
}
|
|
443
|
-
catch(reason) {
|
|
444
|
-
console.info(`cacheStorage.clearDb() failed: ${reason}`);
|
|
445
|
-
callback();
|
|
446
|
-
}
|
|
653
|
+
}).catch(reason => {
|
|
654
|
+
ubolog(`idbStorage() / deleteEntries() failed: ${reason}`);
|
|
655
|
+
});
|
|
447
656
|
};
|
|
448
657
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
658
|
+
return {
|
|
659
|
+
async get(argbin) {
|
|
660
|
+
const keys = keysFromGetArg(argbin);
|
|
661
|
+
if ( keys === undefined ) { return; }
|
|
662
|
+
if ( keys.length === 0 ) { return getAll(); }
|
|
663
|
+
const entries = await getEntries(keys);
|
|
664
|
+
const outbin = {};
|
|
665
|
+
const toRemove = [];
|
|
666
|
+
for ( const { key, value } of entries ) {
|
|
667
|
+
if ( shouldCache(key) === false ) {
|
|
668
|
+
toRemove.push(key);
|
|
669
|
+
continue;
|
|
458
670
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
toRead = Object.keys(keys);
|
|
466
|
-
output = keys;
|
|
671
|
+
outbin[key] = value;
|
|
672
|
+
}
|
|
673
|
+
if ( argbin instanceof Object && Array.isArray(argbin) === false ) {
|
|
674
|
+
for ( const key of keys ) {
|
|
675
|
+
if ( hasOwnProperty(outbin, key) ) { continue; }
|
|
676
|
+
outbin[key] = argbin[key];
|
|
467
677
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
)
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
678
|
+
}
|
|
679
|
+
if ( toRemove.length !== 0 ) {
|
|
680
|
+
deleteEntries(toRemove);
|
|
681
|
+
}
|
|
682
|
+
return outbin;
|
|
683
|
+
},
|
|
684
|
+
|
|
685
|
+
async set(rawbin) {
|
|
686
|
+
const bin = {};
|
|
687
|
+
for ( const key of Object.keys(rawbin) ) {
|
|
688
|
+
if ( shouldCache(key) === false ) { continue; }
|
|
689
|
+
bin[key] = rawbin[key];
|
|
690
|
+
}
|
|
691
|
+
return setEntries(bin);
|
|
692
|
+
},
|
|
693
|
+
|
|
694
|
+
keys(...args) {
|
|
695
|
+
return getAllKeys(...args);
|
|
696
|
+
},
|
|
697
|
+
|
|
698
|
+
remove(...args) {
|
|
699
|
+
return deleteEntries(...args);
|
|
700
|
+
},
|
|
701
|
+
|
|
702
|
+
clear() {
|
|
703
|
+
return getDb().then(db => {
|
|
704
|
+
if ( db === null ) { return; }
|
|
705
|
+
db.close();
|
|
706
|
+
indexedDB.deleteDatabase(STORAGE_NAME);
|
|
707
|
+
}).catch(reason => {
|
|
708
|
+
ubolog(`idbStorage.clear() failed: ${reason}`);
|
|
709
|
+
});
|
|
710
|
+
},
|
|
711
|
+
|
|
712
|
+
async shutdown() {
|
|
713
|
+
await this.clear();
|
|
714
|
+
dbPromise = undefined;
|
|
715
|
+
},
|
|
495
716
|
};
|
|
496
|
-
|
|
497
|
-
};
|
|
717
|
+
})();
|
|
498
718
|
|
|
499
|
-
|
|
500
|
-
// Delete cache-related entries from webext storage.
|
|
501
|
-
const clearWebext = async function() {
|
|
502
|
-
let bin;
|
|
503
|
-
try {
|
|
504
|
-
bin = await webext.storage.local.get('assetCacheRegistry');
|
|
505
|
-
} catch(ex) {
|
|
506
|
-
console.error(ex);
|
|
507
|
-
}
|
|
508
|
-
if ( bin instanceof Object === false ) { return; }
|
|
509
|
-
if ( bin.assetCacheRegistry instanceof Object === false ) { return; }
|
|
510
|
-
const toRemove = [
|
|
511
|
-
'assetCacheRegistry',
|
|
512
|
-
'assetSourceRegistry',
|
|
513
|
-
];
|
|
514
|
-
for ( const key in bin.assetCacheRegistry ) {
|
|
515
|
-
if ( bin.assetCacheRegistry.hasOwnProperty(key) ) {
|
|
516
|
-
toRemove.push('cache/' + key);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
webext.storage.local.remove(toRemove);
|
|
520
|
-
};
|
|
719
|
+
/******************************************************************************/
|
|
521
720
|
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
}
|
|
721
|
+
const cacheAPIs = {
|
|
722
|
+
'indexedDB': idbStorage,
|
|
723
|
+
'cacheAPI': cacheAPI,
|
|
724
|
+
'browser.storage.session': memoryStorage,
|
|
527
725
|
};
|
|
528
726
|
|
|
529
727
|
/******************************************************************************/
|