This repository was archived by the owner on Oct 1, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathutils.js
150 lines (130 loc) · 3.55 KB
/
utils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
58
59
60
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
'use strict'
const {
Key,
Errors
} = require('interface-datastore')
/**
* @typedef {import('interface-datastore').Datastore} Datastore
*/
const CONFIG_KEY = new Key('/config')
const VERSION_KEY = new Key('/version')
/**
* Level dbs wrap level dbs that wrap level dbs. Find a level-js
* instance in the chain if one exists.
*
* @param {Datastore} store
* @returns {Datastore | undefined}
*/
function findLevelJs (store) {
let db = store
// @ts-ignore
while (db.db || db.child) {
// @ts-ignore
db = db.db || db.child
// `Level` is only present in the browser, in node it is LevelDOWN
// @ts-ignore
if (db.type === 'level-js' || db.constructor.name === 'Level') {
return db
}
}
}
/**
* @param {Key} key
* @param {function (Key): Promise<boolean>} has
* @param {Datastore} store
* @returns {Promise<boolean>}
*/
async function hasWithFallback (key, has, store) {
const result = await has(key)
if (result) {
return result
}
// Newer versions of level.js changed the key type from Uint8Array|string
// to Uint8Array so fall back to trying Uint8Arrays if we are using level.js
// and the string version of the key did not work
const levelJs = findLevelJs(store)
if (!levelJs) {
return false
}
return new Promise((resolve, reject) => {
// drop down to IndexDB API, otherwise level-js will monkey around with the keys/values
// @ts-ignore
const req = levelJs.store('readonly').get(key.toString())
req.transaction.onabort = () => {
reject(req.transaction.error)
}
req.transaction.oncomplete = () => {
resolve(Boolean(req.result))
}
})
}
/**
* @param {import('interface-datastore').Key} key
* @param {function (Key): Promise<Uint8Array>} get
* @param {function (Key): Promise<boolean>} has
* @param {import('interface-datastore').Datastore} store
* @returns {Promise<Uint8Array>}
*/
async function getWithFallback (key, get, has, store) {
if (await has(key)) {
return get(key)
}
// Newer versions of level.js changed the key type from Uint8Array|string
// to Uint8Array so fall back to trying Uint8Arrays if we are using level.js
// and the string version of the key did not work
const levelJs = findLevelJs(store)
if (!levelJs) {
throw Errors.notFoundError()
}
return new Promise((resolve, reject) => {
// drop down to IndexDB API, otherwise level-js will monkey around with the keys/values
// @ts-ignore
const req = levelJs.store('readonly').get(key.toString())
req.transaction.onabort = () => {
reject(req.transaction.error)
}
req.transaction.oncomplete = () => {
if (req.result) {
return resolve(req.result)
}
reject(Errors.notFoundError())
}
})
}
/**
* @param {Datastore} store
*/
function wrapStore (store) {
// necessary since level-js@5 cannot read keys from level-js@4 and earlier
const originalGet = store.get.bind(store)
const originalHas = store.has.bind(store)
/**
* @param {Key} key
*/
store.get = (key) => getWithFallback(key, originalGet, originalHas, store)
/**
* @param {Key} key
*/
store.has = (key) => hasWithFallback(key, originalHas, store)
return store
}
/**
* @param {import('./types').Backends} backends
*/
function wrapBackends (backends) {
return {
...backends,
root: wrapStore(backends.root),
datastore: wrapStore(backends.datastore),
pins: wrapStore(backends.pins),
keys: wrapStore(backends.keys)
}
}
module.exports = {
wrapBackends,
hasWithFallback,
getWithFallback,
findLevelJs,
CONFIG_KEY,
VERSION_KEY
}