@fireproof/vendor 2.0.2 → 3.0.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/package.json +6 -60
- package/src/p-limit/index.d.ts +81 -0
- package/src/p-limit/index.js +104 -0
- package/src/p-limit/license +9 -0
- package/src/p-limit/readme.md +129 -0
- package/src/@web3-storage/pail/LICENSE.md +0 -232
- package/src/@web3-storage/pail/README.md +0 -84
- package/src/@web3-storage/pail/cli.js +0 -218
- package/src/@web3-storage/pail/dist/src/api.d.ts +0 -61
- package/src/@web3-storage/pail/dist/src/api.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/api.js +0 -1
- package/src/@web3-storage/pail/dist/src/batch/api.d.ts +0 -31
- package/src/@web3-storage/pail/dist/src/batch/api.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/batch/api.js +0 -1
- package/src/@web3-storage/pail/dist/src/batch/index.d.ts +0 -23
- package/src/@web3-storage/pail/dist/src/batch/index.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/batch/index.js +0 -241
- package/src/@web3-storage/pail/dist/src/batch/shard.d.ts +0 -3
- package/src/@web3-storage/pail/dist/src/batch/shard.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/batch/shard.js +0 -12
- package/src/@web3-storage/pail/dist/src/block.d.ts +0 -35
- package/src/@web3-storage/pail/dist/src/block.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/block.js +0 -66
- package/src/@web3-storage/pail/dist/src/clock/api.d.ts +0 -10
- package/src/@web3-storage/pail/dist/src/clock/api.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/clock/api.js +0 -1
- package/src/@web3-storage/pail/dist/src/clock/index.d.ts +0 -48
- package/src/@web3-storage/pail/dist/src/clock/index.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/clock/index.js +0 -178
- package/src/@web3-storage/pail/dist/src/crdt/api.d.ts +0 -26
- package/src/@web3-storage/pail/dist/src/crdt/api.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/crdt/api.js +0 -1
- package/src/@web3-storage/pail/dist/src/crdt/batch/api.d.ts +0 -11
- package/src/@web3-storage/pail/dist/src/crdt/batch/api.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/crdt/batch/api.js +0 -1
- package/src/@web3-storage/pail/dist/src/crdt/batch/index.d.ts +0 -5
- package/src/@web3-storage/pail/dist/src/crdt/batch/index.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/crdt/batch/index.js +0 -140
- package/src/@web3-storage/pail/dist/src/crdt/index.d.ts +0 -9
- package/src/@web3-storage/pail/dist/src/crdt/index.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/crdt/index.js +0 -344
- package/src/@web3-storage/pail/dist/src/diff.d.ts +0 -13
- package/src/@web3-storage/pail/dist/src/diff.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/diff.js +0 -151
- package/src/@web3-storage/pail/dist/src/index.d.ts +0 -10
- package/src/@web3-storage/pail/dist/src/index.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/index.js +0 -356
- package/src/@web3-storage/pail/dist/src/merge.d.ts +0 -5
- package/src/@web3-storage/pail/dist/src/merge.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/merge.js +0 -42
- package/src/@web3-storage/pail/dist/src/shard.d.ts +0 -43
- package/src/@web3-storage/pail/dist/src/shard.d.ts.map +0 -1
- package/src/@web3-storage/pail/dist/src/shard.js +0 -166
- package/src/@web3-storage/pail/dist/tsconfig.tsbuildinfo +0 -1
- package/src/@web3-storage/pail/src/api.ts +0 -92
- package/src/@web3-storage/pail/src/batch/api.js +0 -1
- package/src/@web3-storage/pail/src/batch/api.ts +0 -59
- package/src/@web3-storage/pail/src/batch/index.js +0 -258
- package/src/@web3-storage/pail/src/batch/shard.js +0 -13
- package/src/@web3-storage/pail/src/block.js +0 -75
- package/src/@web3-storage/pail/src/clock/api.js +0 -1
- package/src/@web3-storage/pail/src/clock/api.ts +0 -12
- package/src/@web3-storage/pail/src/clock/index.js +0 -182
- package/src/@web3-storage/pail/src/crdt/api.js +0 -1
- package/src/@web3-storage/pail/src/crdt/api.ts +0 -33
- package/src/@web3-storage/pail/src/crdt/batch/api.js +0 -1
- package/src/@web3-storage/pail/src/crdt/batch/api.ts +0 -30
- package/src/@web3-storage/pail/src/crdt/batch/index.js +0 -155
- package/src/@web3-storage/pail/src/crdt/index.js +0 -354
- package/src/@web3-storage/pail/src/diff.js +0 -151
- package/src/@web3-storage/pail/src/index.js +0 -406
- package/src/@web3-storage/pail/src/merge.js +0 -43
- package/src/@web3-storage/pail/src/shard.js +0 -180
|
@@ -1,406 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line no-unused-vars
|
|
2
|
-
import * as API from './api.js'
|
|
3
|
-
import { ShardFetcher, isPrintableASCII } from './shard.js'
|
|
4
|
-
import * as Shard from './shard.js'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Put a value (a CID) for the given key. If the key exists it's value is
|
|
8
|
-
* overwritten.
|
|
9
|
-
*
|
|
10
|
-
* @param {API.BlockFetcher} blocks Bucket block storage.
|
|
11
|
-
* @param {API.ShardLink} root CID of the root node of the bucket.
|
|
12
|
-
* @param {string} key The key of the value to put.
|
|
13
|
-
* @param {API.UnknownLink} value The value to put.
|
|
14
|
-
* @returns {Promise<{ root: API.ShardLink } & API.ShardDiff>}
|
|
15
|
-
*/
|
|
16
|
-
export const put = async (blocks, root, key, value) => {
|
|
17
|
-
const shards = new ShardFetcher(blocks)
|
|
18
|
-
const rshard = await shards.get(root)
|
|
19
|
-
|
|
20
|
-
if (rshard.value.keyChars !== Shard.KeyCharsASCII) {
|
|
21
|
-
throw new Error(`unsupported key character set: ${rshard.value.keyChars}`)
|
|
22
|
-
}
|
|
23
|
-
if (!isPrintableASCII(key)) {
|
|
24
|
-
throw new Error('key contains non-ASCII characters')
|
|
25
|
-
}
|
|
26
|
-
// ensure utf8 encoded key is smaller than max
|
|
27
|
-
if (new TextEncoder().encode(key).length > rshard.value.maxKeySize) {
|
|
28
|
-
throw new Error(`UTF-8 encoded key exceeds max size of ${rshard.value.maxKeySize} bytes`)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const path = await traverse(shards, rshard, key)
|
|
32
|
-
const target = path[path.length - 1]
|
|
33
|
-
const skey = key.slice(target.value.prefix.length) // key within the shard
|
|
34
|
-
|
|
35
|
-
/** @type {API.ShardEntry} */
|
|
36
|
-
let entry = [skey, value]
|
|
37
|
-
let targetEntries = [...target.value.entries]
|
|
38
|
-
|
|
39
|
-
/** @type {API.ShardBlockView[]} */
|
|
40
|
-
const additions = []
|
|
41
|
-
|
|
42
|
-
for (const [i, e] of targetEntries.entries()) {
|
|
43
|
-
const [k, v] = e
|
|
44
|
-
|
|
45
|
-
// is this just a replace?
|
|
46
|
-
if (k === skey) break
|
|
47
|
-
|
|
48
|
-
// do we need to shard this entry?
|
|
49
|
-
const shortest = k.length < skey.length ? k : skey
|
|
50
|
-
const other = shortest === k ? skey : k
|
|
51
|
-
let common = ''
|
|
52
|
-
for (const char of shortest) {
|
|
53
|
-
const next = common + char
|
|
54
|
-
if (!other.startsWith(next)) break
|
|
55
|
-
common = next
|
|
56
|
-
}
|
|
57
|
-
if (common.length) {
|
|
58
|
-
/** @type {API.ShardEntry[]} */
|
|
59
|
-
let entries = []
|
|
60
|
-
|
|
61
|
-
// if the existing entry key or new key is equal to the common prefix,
|
|
62
|
-
// then the existing value / new value needs to persist in the parent
|
|
63
|
-
// shard. Otherwise they persist in this new shard.
|
|
64
|
-
if (common !== skey) {
|
|
65
|
-
entries = Shard.putEntry(entries, [skey.slice(common.length), value])
|
|
66
|
-
}
|
|
67
|
-
if (common !== k) {
|
|
68
|
-
entries = Shard.putEntry(entries, [k.slice(common.length), v])
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
let child = await Shard.encodeBlock(
|
|
72
|
-
Shard.withEntries(entries, { ...target.value, prefix: target.value.prefix + common })
|
|
73
|
-
)
|
|
74
|
-
additions.push(child)
|
|
75
|
-
|
|
76
|
-
// need to spread as access by index does not consider utf-16 surrogates
|
|
77
|
-
const commonChars = [...common]
|
|
78
|
-
|
|
79
|
-
// create parent shards for each character of the common prefix
|
|
80
|
-
for (let i = commonChars.length - 1; i > 0; i--) {
|
|
81
|
-
const parentConfig = { ...target.value, prefix: target.value.prefix + commonChars.slice(0, i).join('') }
|
|
82
|
-
/** @type {API.ShardEntryLinkValue | API.ShardEntryValueValue | API.ShardEntryLinkAndValueValue} */
|
|
83
|
-
let parentValue
|
|
84
|
-
// if the first iteration and the existing entry key is equal to the
|
|
85
|
-
// common prefix, then existing value needs to persist in this parent
|
|
86
|
-
if (i === commonChars.length - 1 && common === k) {
|
|
87
|
-
if (Array.isArray(v)) throw new Error('found a shard link when expecting a value')
|
|
88
|
-
parentValue = [child.cid, v]
|
|
89
|
-
} else if (i === commonChars.length - 1 && common === skey) {
|
|
90
|
-
parentValue = [child.cid, value]
|
|
91
|
-
} else {
|
|
92
|
-
parentValue = [child.cid]
|
|
93
|
-
}
|
|
94
|
-
const parent = await Shard.encodeBlock(Shard.withEntries([[commonChars[i], parentValue]], parentConfig))
|
|
95
|
-
additions.push(parent)
|
|
96
|
-
child = parent
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// remove the sharded entry
|
|
100
|
-
targetEntries.splice(i, 1)
|
|
101
|
-
|
|
102
|
-
// create the entry that will be added to target
|
|
103
|
-
if (commonChars.length === 1 && common === k) {
|
|
104
|
-
if (Array.isArray(v)) throw new Error('found a shard link when expecting a value')
|
|
105
|
-
entry = [commonChars[0], [child.cid, v]]
|
|
106
|
-
} else if (commonChars.length === 1 && common === skey) {
|
|
107
|
-
entry = [commonChars[0], [child.cid, value]]
|
|
108
|
-
} else {
|
|
109
|
-
entry = [commonChars[0], [child.cid]]
|
|
110
|
-
}
|
|
111
|
-
break
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const shard = Shard.withEntries(Shard.putEntry(targetEntries, entry), target.value)
|
|
116
|
-
let child = await Shard.encodeBlock(shard)
|
|
117
|
-
|
|
118
|
-
// if no change in the target then we're done
|
|
119
|
-
if (child.cid.toString() === target.cid.toString()) {
|
|
120
|
-
return { root, additions: [], removals: [] }
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
additions.push(child)
|
|
124
|
-
|
|
125
|
-
// path is root -> target, so work backwards, propagating the new shard CID
|
|
126
|
-
for (let i = path.length - 2; i >= 0; i--) {
|
|
127
|
-
const parent = path[i]
|
|
128
|
-
const key = child.value.prefix.slice(parent.value.prefix.length)
|
|
129
|
-
const value = Shard.withEntries(
|
|
130
|
-
parent.value.entries.map((entry) => {
|
|
131
|
-
const [k, v] = entry
|
|
132
|
-
if (k !== key) return entry
|
|
133
|
-
if (!Array.isArray(v)) throw new Error(`"${key}" is not a shard link in: ${parent.cid}`)
|
|
134
|
-
return /** @type {API.ShardEntry} */(v[1] == null ? [k, [child.cid]] : [k, [child.cid, v[1]]])
|
|
135
|
-
}),
|
|
136
|
-
parent.value
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
child = await Shard.encodeBlock(value)
|
|
140
|
-
additions.push(child)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return { root: additions[additions.length - 1].cid, additions, removals: path }
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get the stored value for the given key from the bucket. If the key is not
|
|
148
|
-
* found, `undefined` is returned.
|
|
149
|
-
*
|
|
150
|
-
* @param {API.BlockFetcher} blocks Bucket block storage.
|
|
151
|
-
* @param {API.ShardLink} root CID of the root node of the bucket.
|
|
152
|
-
* @param {string} key The key of the value to get.
|
|
153
|
-
* @returns {Promise<API.UnknownLink | undefined>}
|
|
154
|
-
*/
|
|
155
|
-
export const get = async (blocks, root, key) => {
|
|
156
|
-
const shards = new ShardFetcher(blocks)
|
|
157
|
-
const rshard = await shards.get(root)
|
|
158
|
-
const path = await traverse(shards, rshard, key)
|
|
159
|
-
const target = path[path.length - 1]
|
|
160
|
-
const skey = key.slice(target.value.prefix.length) // key within the shard
|
|
161
|
-
const entry = target.value.entries.find(([k]) => k === skey)
|
|
162
|
-
if (!entry) return
|
|
163
|
-
return Array.isArray(entry[1]) ? entry[1][1] : entry[1]
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Delete the value for the given key from the bucket. If the key is not found
|
|
168
|
-
* no operation occurs.
|
|
169
|
-
*
|
|
170
|
-
* @param {API.BlockFetcher} blocks Bucket block storage.
|
|
171
|
-
* @param {API.ShardLink} root CID of the root node of the bucket.
|
|
172
|
-
* @param {string} key The key of the value to delete.
|
|
173
|
-
* @returns {Promise<{ root: API.ShardLink } & API.ShardDiff>}
|
|
174
|
-
*/
|
|
175
|
-
export const del = async (blocks, root, key) => {
|
|
176
|
-
const shards = new ShardFetcher(blocks)
|
|
177
|
-
const rshard = await shards.get(root)
|
|
178
|
-
const path = await traverse(shards, rshard, key)
|
|
179
|
-
const target = path[path.length - 1]
|
|
180
|
-
const skey = key.slice(target.value.prefix.length) // key within the shard
|
|
181
|
-
|
|
182
|
-
const entryidx = target.value.entries.findIndex(([k]) => k === skey)
|
|
183
|
-
if (entryidx === -1) return { root, additions: [], removals: [] }
|
|
184
|
-
|
|
185
|
-
const entry = target.value.entries[entryidx]
|
|
186
|
-
// cannot delete a shard (without data)
|
|
187
|
-
if (Array.isArray(entry[1]) && entry[1][1] == null) {
|
|
188
|
-
return { root, additions: [], removals: [] }
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** @type {API.ShardBlockView[]} */
|
|
192
|
-
const additions = []
|
|
193
|
-
/** @type {API.ShardBlockView[]} */
|
|
194
|
-
const removals = [...path]
|
|
195
|
-
|
|
196
|
-
let shard = Shard.withEntries([...target.value.entries], target.value)
|
|
197
|
-
|
|
198
|
-
if (Array.isArray(entry[1])) {
|
|
199
|
-
// remove the value from this link+value
|
|
200
|
-
shard.entries[entryidx] = [entry[0], [entry[1][0]]]
|
|
201
|
-
} else {
|
|
202
|
-
shard.entries.splice(entryidx, 1)
|
|
203
|
-
// if now empty, remove from parent
|
|
204
|
-
while (!shard.entries.length) {
|
|
205
|
-
const child = path[path.length - 1]
|
|
206
|
-
const parent = path[path.length - 2]
|
|
207
|
-
if (!parent) break
|
|
208
|
-
path.pop()
|
|
209
|
-
shard = Shard.withEntries(
|
|
210
|
-
parent.value.entries.filter(e => {
|
|
211
|
-
if (!Array.isArray(e[1])) return true
|
|
212
|
-
return e[1][0].toString() !== child.cid.toString()
|
|
213
|
-
}),
|
|
214
|
-
parent.value
|
|
215
|
-
)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
let child = await Shard.encodeBlock(shard)
|
|
220
|
-
additions.push(child)
|
|
221
|
-
|
|
222
|
-
// path is root -> shard, so work backwards, propagating the new shard CID
|
|
223
|
-
for (let i = path.length - 2; i >= 0; i--) {
|
|
224
|
-
const parent = path[i]
|
|
225
|
-
const key = child.value.prefix.slice(parent.value.prefix.length)
|
|
226
|
-
const value = Shard.withEntries(
|
|
227
|
-
parent.value.entries.map((entry) => {
|
|
228
|
-
const [k, v] = entry
|
|
229
|
-
if (k !== key) return entry
|
|
230
|
-
if (!Array.isArray(v)) throw new Error(`"${key}" is not a shard link in: ${parent.cid}`)
|
|
231
|
-
return /** @type {API.ShardEntry} */(v[1] == null ? [k, [child.cid]] : [k, [child.cid, v[1]]])
|
|
232
|
-
}),
|
|
233
|
-
parent.value
|
|
234
|
-
)
|
|
235
|
-
|
|
236
|
-
child = await Shard.encodeBlock(value)
|
|
237
|
-
additions.push(child)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return { root: additions[additions.length - 1].cid, additions, removals }
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* @param {API.EntriesOptions} [options]
|
|
245
|
-
* @returns {options is API.KeyPrefixOption}
|
|
246
|
-
*/
|
|
247
|
-
const isKeyPrefixOption = options => {
|
|
248
|
-
const opts = options ?? {}
|
|
249
|
-
return 'prefix' in opts && Boolean(opts.prefix)
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* @param {API.EntriesOptions} [options]
|
|
254
|
-
* @returns {options is API.KeyRangeOption}
|
|
255
|
-
*/
|
|
256
|
-
const isKeyRangeOption = options => {
|
|
257
|
-
const opts = options ?? {}
|
|
258
|
-
return ('gt' in opts && Boolean(opts.gt)) || ('gte' in opts && Boolean(opts.gte)) || ('lt' in opts && Boolean(opts.lt)) || ('lte' in opts && Boolean(opts.lte))
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* @param {API.KeyRangeOption} options
|
|
263
|
-
* @returns {options is API.KeyLowerBoundRangeOption}
|
|
264
|
-
*/
|
|
265
|
-
const isKeyLowerBoundRangeOption = options => ('gt' in options && Boolean(options.gt)) || ('gte' in options && Boolean(options.gte))
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* @param {API.KeyLowerBoundRangeOption} options
|
|
269
|
-
* @returns {options is API.KeyLowerBoundRangeInclusiveOption}
|
|
270
|
-
*/
|
|
271
|
-
const isKeyLowerBoundRangeInclusiveOption = options => 'gte' in options && Boolean(options.gte)
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* @param {API.KeyLowerBoundRangeOption} options
|
|
275
|
-
* @returns {options is API.KeyLowerBoundRangeExclusiveOption}
|
|
276
|
-
*/
|
|
277
|
-
const isKeyLowerBoundRangeExclusiveOption = options => 'gt' in options && Boolean(options.gt)
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* @param {API.KeyRangeOption} options
|
|
281
|
-
* @returns {options is API.KeyUpperBoundRangeOption}
|
|
282
|
-
*/
|
|
283
|
-
const isKeyUpperBoundRangeOption = options => ('lt' in options && Boolean(options.lt)) || ('lte' in options && Boolean(options.lte))
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* @param {API.KeyUpperBoundRangeOption} options
|
|
287
|
-
* @returns {options is API.KeyUpperBoundRangeInclusiveOption}
|
|
288
|
-
*/
|
|
289
|
-
const isKeyUpperBoundRangeInclusiveOption = options => 'lte' in options && Boolean(options.lte)
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* @param {API.KeyUpperBoundRangeOption} options
|
|
293
|
-
* @returns {options is API.KeyUpperBoundRangeExclusiveOption}
|
|
294
|
-
*/
|
|
295
|
-
const isKeyUpperBoundRangeExclusiveOption = options => 'lt' in options && Boolean(options.lt)
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* List entries in the bucket.
|
|
299
|
-
*
|
|
300
|
-
* @param {API.BlockFetcher} blocks Bucket block storage.
|
|
301
|
-
* @param {API.ShardLink} root CID of the root node of the bucket.
|
|
302
|
-
* @param {API.EntriesOptions} [options]
|
|
303
|
-
* @returns {AsyncIterableIterator<API.ShardValueEntry>}
|
|
304
|
-
*/
|
|
305
|
-
export const entries = async function * (blocks, root, options) {
|
|
306
|
-
const hasKeyPrefix = isKeyPrefixOption(options)
|
|
307
|
-
const hasKeyRange = isKeyRangeOption(options)
|
|
308
|
-
const hasKeyLowerBoundRange = hasKeyRange && isKeyLowerBoundRangeOption(options)
|
|
309
|
-
const hasKeyLowerBoundRangeInclusive = hasKeyLowerBoundRange && isKeyLowerBoundRangeInclusiveOption(options)
|
|
310
|
-
const hasKeyLowerBoundRangeExclusive = hasKeyLowerBoundRange && isKeyLowerBoundRangeExclusiveOption(options)
|
|
311
|
-
const hasKeyUpperBoundRange = hasKeyRange && isKeyUpperBoundRangeOption(options)
|
|
312
|
-
const hasKeyUpperBoundRangeInclusive = hasKeyUpperBoundRange && isKeyUpperBoundRangeInclusiveOption(options)
|
|
313
|
-
const hasKeyUpperBoundRangeExclusive = hasKeyUpperBoundRange && isKeyUpperBoundRangeExclusiveOption(options)
|
|
314
|
-
const hasKeyUpperAndLowerBoundRange = hasKeyLowerBoundRange && hasKeyUpperBoundRange
|
|
315
|
-
|
|
316
|
-
const shards = new ShardFetcher(blocks)
|
|
317
|
-
const rshard = await shards.get(root)
|
|
318
|
-
|
|
319
|
-
yield * (
|
|
320
|
-
/** @returns {AsyncIterableIterator<API.ShardValueEntry>} */
|
|
321
|
-
(async function* ents(shard) {
|
|
322
|
-
for (const entry of shard.value.entries) {
|
|
323
|
-
const key = shard.value.prefix + entry[0]
|
|
324
|
-
|
|
325
|
-
// if array, this is a link to a shard
|
|
326
|
-
if (Array.isArray(entry[1])) {
|
|
327
|
-
if (entry[1][1]) {
|
|
328
|
-
if (
|
|
329
|
-
(hasKeyPrefix && key.startsWith(options.prefix)) ||
|
|
330
|
-
(hasKeyUpperAndLowerBoundRange && (
|
|
331
|
-
((hasKeyLowerBoundRangeExclusive && key > options.gt) || (hasKeyLowerBoundRangeInclusive && key >= options.gte)) &&
|
|
332
|
-
((hasKeyUpperBoundRangeExclusive && key < options.lt) || (hasKeyUpperBoundRangeInclusive && key <= options.lte))
|
|
333
|
-
)) ||
|
|
334
|
-
(hasKeyLowerBoundRangeExclusive && key > options.gt) ||
|
|
335
|
-
(hasKeyLowerBoundRangeInclusive && key >= options.gte) ||
|
|
336
|
-
(hasKeyUpperBoundRangeExclusive && key < options.lt) ||
|
|
337
|
-
(hasKeyUpperBoundRangeInclusive && key <= options.lte) ||
|
|
338
|
-
(!hasKeyPrefix && !hasKeyRange)
|
|
339
|
-
) {
|
|
340
|
-
yield [key, entry[1][1]]
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
if (hasKeyPrefix) {
|
|
345
|
-
if (options.prefix.length <= key.length && !key.startsWith(options.prefix)) {
|
|
346
|
-
continue
|
|
347
|
-
}
|
|
348
|
-
if (options.prefix.length > key.length && !options.prefix.startsWith(key)) {
|
|
349
|
-
continue
|
|
350
|
-
}
|
|
351
|
-
} else if (
|
|
352
|
-
(hasKeyLowerBoundRangeExclusive && (trunc(key, Math.min(key.length, options.gt.length)) < trunc(options.gt, Math.min(key.length, options.gt.length)))) ||
|
|
353
|
-
(hasKeyLowerBoundRangeInclusive && (trunc(key, Math.min(key.length, options.gte.length)) < trunc(options.gte, Math.min(key.length, options.gte.length)))) ||
|
|
354
|
-
(hasKeyUpperBoundRangeExclusive && (trunc(key, Math.min(key.length, options.lt.length)) > trunc(options.lt, Math.min(key.length, options.lt.length)))) ||
|
|
355
|
-
(hasKeyUpperBoundRangeInclusive && (trunc(key, Math.min(key.length, options.lte.length)) > trunc(options.lte, Math.min(key.length, options.lte.length))))
|
|
356
|
-
) {
|
|
357
|
-
continue
|
|
358
|
-
}
|
|
359
|
-
yield * ents(await shards.get(entry[1][0]))
|
|
360
|
-
} else {
|
|
361
|
-
if (
|
|
362
|
-
(hasKeyPrefix && key.startsWith(options.prefix)) ||
|
|
363
|
-
(hasKeyRange && hasKeyUpperAndLowerBoundRange && (
|
|
364
|
-
((hasKeyLowerBoundRangeExclusive && key > options.gt) || (hasKeyLowerBoundRangeInclusive && key >= options.gte)) &&
|
|
365
|
-
((hasKeyUpperBoundRangeExclusive && key < options.lt) || (hasKeyUpperBoundRangeInclusive && key <= options.lte))
|
|
366
|
-
)) ||
|
|
367
|
-
(hasKeyRange && !hasKeyUpperAndLowerBoundRange && (
|
|
368
|
-
(hasKeyLowerBoundRangeExclusive && key > options.gt) || (hasKeyLowerBoundRangeInclusive && key >= options.gte) ||
|
|
369
|
-
(hasKeyUpperBoundRangeExclusive && key < options.lt) || (hasKeyUpperBoundRangeInclusive && key <= options.lte)
|
|
370
|
-
)) ||
|
|
371
|
-
(!hasKeyPrefix && !hasKeyRange)
|
|
372
|
-
) {
|
|
373
|
-
yield [key, entry[1]]
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
})
|
|
378
|
-
)(rshard)
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* @param {string} str
|
|
383
|
-
* @param {number} len
|
|
384
|
-
*/
|
|
385
|
-
const trunc = (str, len) => str.length <= len ? str : str.slice(0, len)
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Traverse from the passed shard block to the target shard block using the
|
|
389
|
-
* passed key. All traversed shards are returned, starting with the passed
|
|
390
|
-
* shard and ending with the target.
|
|
391
|
-
*
|
|
392
|
-
* @param {ShardFetcher} shards
|
|
393
|
-
* @param {API.ShardBlockView} shard
|
|
394
|
-
* @param {string} key
|
|
395
|
-
* @returns {Promise<[API.ShardBlockView, ...Array<API.ShardBlockView>]>}
|
|
396
|
-
*/
|
|
397
|
-
const traverse = async (shards, shard, key) => {
|
|
398
|
-
for (const [k, v] of shard.value.entries) {
|
|
399
|
-
if (key === k) return [shard]
|
|
400
|
-
if (key.startsWith(k) && Array.isArray(v)) {
|
|
401
|
-
const path = await traverse(shards, await shards.get(v[0]), key.slice(k.length))
|
|
402
|
-
return [shard, ...path]
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return [shard]
|
|
406
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line no-unused-vars
|
|
2
|
-
import * as API from './api.js'
|
|
3
|
-
import { difference } from './diff.js'
|
|
4
|
-
import { put, del } from './index.js'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @param {API.BlockFetcher} blocks Bucket block storage.
|
|
8
|
-
* @param {API.ShardLink} base Merge base. Common parent of target DAGs.
|
|
9
|
-
* @param {API.ShardLink[]} targets Target DAGs to merge.
|
|
10
|
-
* @returns {Promise<{ root: API.ShardLink } & API.ShardDiff>}
|
|
11
|
-
*/
|
|
12
|
-
export const merge = async (blocks, base, targets) => {
|
|
13
|
-
const diffs = await Promise.all(targets.map(t => difference(blocks, base, t)))
|
|
14
|
-
const additions = new Map()
|
|
15
|
-
const removals = new Map()
|
|
16
|
-
/** @type {API.BlockFetcher} */
|
|
17
|
-
const fetcher = { get: cid => additions.get(cid.toString()) ?? blocks.get(cid) }
|
|
18
|
-
|
|
19
|
-
let root = base
|
|
20
|
-
for (const { keys } of diffs) {
|
|
21
|
-
for (const [k, v] of keys) {
|
|
22
|
-
let res
|
|
23
|
-
if (v[1] == null) {
|
|
24
|
-
res = await del(fetcher, root, k)
|
|
25
|
-
} else {
|
|
26
|
-
res = await put(fetcher, root, k, v[1])
|
|
27
|
-
}
|
|
28
|
-
for (const blk of res.removals) {
|
|
29
|
-
if (additions.has(blk.cid.toString())) {
|
|
30
|
-
additions.delete(blk.cid.toString())
|
|
31
|
-
} else {
|
|
32
|
-
removals.set(blk.cid.toString(), blk)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
for (const blk of res.additions) {
|
|
36
|
-
additions.set(blk.cid.toString(), blk)
|
|
37
|
-
}
|
|
38
|
-
root = res.root
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return { root, additions: [...additions.values()], removals: [...removals.values()] }
|
|
43
|
-
}
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import * as Link from 'multiformats/link'
|
|
2
|
-
import { Block, encode, decode } from 'multiformats/block'
|
|
3
|
-
import { sha256 } from 'multiformats/hashes/sha2'
|
|
4
|
-
import * as dagCBOR from '@ipld/dag-cbor'
|
|
5
|
-
// eslint-disable-next-line no-unused-vars
|
|
6
|
-
import * as API from './api.js'
|
|
7
|
-
|
|
8
|
-
export const KeyCharsASCII = 'ascii'
|
|
9
|
-
export const MaxKeySize = 4096
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @extends {Block<API.Shard, typeof dagCBOR.code, typeof sha256.code, 1>}
|
|
13
|
-
* @implements {API.ShardBlockView}
|
|
14
|
-
*/
|
|
15
|
-
export class ShardBlock extends Block {
|
|
16
|
-
/**
|
|
17
|
-
* @param {object} config
|
|
18
|
-
* @param {API.ShardLink} config.cid
|
|
19
|
-
* @param {API.Shard} config.value
|
|
20
|
-
* @param {Uint8Array} config.bytes
|
|
21
|
-
*/
|
|
22
|
-
constructor ({ cid, value, bytes }) {
|
|
23
|
-
// @ts-expect-error
|
|
24
|
-
super({ cid, value, bytes })
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** @param {API.ShardOptions} [options] */
|
|
28
|
-
static create (options) {
|
|
29
|
-
return encodeBlock(create(options))
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @param {API.ShardOptions} [options]
|
|
35
|
-
* @returns {API.Shard}
|
|
36
|
-
*/
|
|
37
|
-
export const create = (options) => ({ entries: [], ...configure(options) })
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @param {API.ShardOptions} [options]
|
|
41
|
-
* @returns {API.ShardConfig}
|
|
42
|
-
*/
|
|
43
|
-
export const configure = (options) => ({
|
|
44
|
-
version: 1,
|
|
45
|
-
keyChars: options?.keyChars ?? KeyCharsASCII,
|
|
46
|
-
maxKeySize: options?.maxKeySize ?? MaxKeySize,
|
|
47
|
-
prefix: options?.prefix ?? ''
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* @param {API.ShardEntry[]} entries
|
|
52
|
-
* @param {API.ShardOptions} [options]
|
|
53
|
-
* @returns {API.Shard}
|
|
54
|
-
*/
|
|
55
|
-
export const withEntries = (entries, options) => ({ ...create(options), entries })
|
|
56
|
-
|
|
57
|
-
/** @type {WeakMap<Uint8Array, API.ShardBlockView>} */
|
|
58
|
-
const decodeCache = new WeakMap()
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @param {API.Shard} value
|
|
62
|
-
* @returns {Promise<API.ShardBlockView>}
|
|
63
|
-
*/
|
|
64
|
-
export const encodeBlock = async value => {
|
|
65
|
-
const { cid, bytes } = await encode({ value, codec: dagCBOR, hasher: sha256 })
|
|
66
|
-
const block = new ShardBlock({ cid, value, bytes })
|
|
67
|
-
decodeCache.set(block.bytes, block)
|
|
68
|
-
return block
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* @param {Uint8Array} bytes
|
|
73
|
-
* @returns {Promise<API.ShardBlockView>}
|
|
74
|
-
*/
|
|
75
|
-
export const decodeBlock = async bytes => {
|
|
76
|
-
const block = decodeCache.get(bytes)
|
|
77
|
-
if (block) return block
|
|
78
|
-
const { cid, value } = await decode({ bytes, codec: dagCBOR, hasher: sha256 })
|
|
79
|
-
if (!isShard(value)) throw new Error(`invalid shard: ${cid}`)
|
|
80
|
-
return new ShardBlock({ cid, value, bytes })
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* @param {any} value
|
|
85
|
-
* @returns {value is API.Shard}
|
|
86
|
-
*/
|
|
87
|
-
export const isShard = value =>
|
|
88
|
-
value != null &&
|
|
89
|
-
typeof value === 'object' &&
|
|
90
|
-
Array.isArray(value.entries) &&
|
|
91
|
-
value.version === 1 &&
|
|
92
|
-
typeof value.maxKeySize === 'number' &&
|
|
93
|
-
typeof value.keyChars === 'string' &&
|
|
94
|
-
typeof value.prefix === 'string'
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* @param {any} value
|
|
98
|
-
* @returns {value is API.ShardLink}
|
|
99
|
-
*/
|
|
100
|
-
export const isShardLink = (value) =>
|
|
101
|
-
Link.isLink(value) &&
|
|
102
|
-
value.code === dagCBOR.code
|
|
103
|
-
|
|
104
|
-
export class ShardFetcher {
|
|
105
|
-
/** @param {API.BlockFetcher} blocks */
|
|
106
|
-
constructor (blocks) {
|
|
107
|
-
this._blocks = blocks
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* @param {API.ShardLink} link
|
|
112
|
-
* @returns {Promise<API.ShardBlockView>}
|
|
113
|
-
*/
|
|
114
|
-
async get (link) {
|
|
115
|
-
const block = await this._blocks.get(link)
|
|
116
|
-
if (!block) throw new Error(`missing block: ${link}`)
|
|
117
|
-
return decodeBlock(block.bytes)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* @param {API.ShardEntry[]} target Entries to insert into.
|
|
123
|
-
* @param {API.ShardEntry} newEntry
|
|
124
|
-
* @returns {API.ShardEntry[]}
|
|
125
|
-
*/
|
|
126
|
-
export const putEntry = (target, newEntry) => {
|
|
127
|
-
/** @type {API.ShardEntry[]} */
|
|
128
|
-
const entries = []
|
|
129
|
-
|
|
130
|
-
for (const [i, entry] of target.entries()) {
|
|
131
|
-
const [k, v] = entry
|
|
132
|
-
if (newEntry[0] === k) {
|
|
133
|
-
// if new value is link to shard...
|
|
134
|
-
if (Array.isArray(newEntry[1])) {
|
|
135
|
-
// and old value is link to shard
|
|
136
|
-
// and old value is _also_ link to data
|
|
137
|
-
// and new value does not have link to data
|
|
138
|
-
// then preserve old data
|
|
139
|
-
if (Array.isArray(v) && v[1] != null && newEntry[1][1] == null) {
|
|
140
|
-
entries.push([k, [newEntry[1][0], v[1]]])
|
|
141
|
-
} else {
|
|
142
|
-
entries.push(newEntry)
|
|
143
|
-
}
|
|
144
|
-
} else {
|
|
145
|
-
// shard as well as value?
|
|
146
|
-
if (Array.isArray(v)) {
|
|
147
|
-
entries.push([k, [v[0], newEntry[1]]])
|
|
148
|
-
} else {
|
|
149
|
-
entries.push(newEntry)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
for (let j = i + 1; j < target.length; j++) {
|
|
153
|
-
entries.push(target[j])
|
|
154
|
-
}
|
|
155
|
-
return entries
|
|
156
|
-
}
|
|
157
|
-
if (i === 0 && newEntry[0] < k) {
|
|
158
|
-
entries.push(newEntry)
|
|
159
|
-
for (let j = i; j < target.length; j++) {
|
|
160
|
-
entries.push(target[j])
|
|
161
|
-
}
|
|
162
|
-
return entries
|
|
163
|
-
}
|
|
164
|
-
if (i > 0 && newEntry[0] > target[i - 1][0] && newEntry[0] < k) {
|
|
165
|
-
entries.push(newEntry)
|
|
166
|
-
for (let j = i; j < target.length; j++) {
|
|
167
|
-
entries.push(target[j])
|
|
168
|
-
}
|
|
169
|
-
return entries
|
|
170
|
-
}
|
|
171
|
-
entries.push(entry)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
entries.push(newEntry)
|
|
175
|
-
|
|
176
|
-
return entries
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/** @param {string} s */
|
|
180
|
-
export const isPrintableASCII = s => /^[\x20-\x7E]*$/.test(s)
|