@fireproof/core 0.3.10 → 0.3.11

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fireproof/core",
3
- "version": "0.3.10",
3
+ "version": "0.3.11",
4
4
  "description": "Realtime database for IPFS",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/src/blockstore.js CHANGED
@@ -29,12 +29,12 @@ const husher = (id, workFn) => {
29
29
  */
30
30
  export default class TransactionBlockstore {
31
31
  /** @type {Map<string, Uint8Array>} */
32
- committedBlocks = new Map()
32
+ #committedBlocks = new Map()
33
33
 
34
34
  valet = null
35
35
 
36
- instanceId = 'blkz.' + Math.random().toString(36).substring(2, 4)
37
- inflightTransactions = new Set()
36
+ #instanceId = 'blkz.' + Math.random().toString(36).substring(2, 4)
37
+ #inflightTransactions = new Set()
38
38
 
39
39
  constructor (name, encryptionKey) {
40
40
  this.valet = new Valet(name, encryptionKey)
@@ -49,7 +49,7 @@ export default class TransactionBlockstore {
49
49
  async get (cid) {
50
50
  const key = cid.toString()
51
51
  // it is safe to read from the in-flight transactions becauase they are immutable
52
- const bytes = await Promise.any([this.transactionsGet(key), this.committedGet(key)]).catch(e => {
52
+ const bytes = await Promise.any([this.#transactionsGet(key), this.committedGet(key)]).catch(e => {
53
53
  // console.log('networkGet', cid.toString(), e)
54
54
  return this.networkGet(key)
55
55
  })
@@ -59,8 +59,8 @@ export default class TransactionBlockstore {
59
59
 
60
60
  // this iterates over the in-flight transactions
61
61
  // and returns the first matching block it finds
62
- async transactionsGet (key) {
63
- for (const transaction of this.inflightTransactions) {
62
+ async #transactionsGet (key) {
63
+ for (const transaction of this.#inflightTransactions) {
64
64
  const got = await transaction.get(key)
65
65
  if (got && got.bytes) return got.bytes
66
66
  }
@@ -68,16 +68,16 @@ export default class TransactionBlockstore {
68
68
  }
69
69
 
70
70
  async committedGet (key) {
71
- const old = this.committedBlocks.get(key)
71
+ const old = this.#committedBlocks.get(key)
72
72
  if (old) return old
73
73
  const got = await this.valet.getBlock(key)
74
74
  // console.log('committedGet: ' + key)
75
- this.committedBlocks.set(key, got)
75
+ this.#committedBlocks.set(key, got)
76
76
  return got
77
77
  }
78
78
 
79
79
  async clearCommittedCache () {
80
- this.committedBlocks.clear()
80
+ this.#committedBlocks.clear()
81
81
  }
82
82
 
83
83
  async networkGet (key) {
@@ -118,10 +118,10 @@ export default class TransactionBlockstore {
118
118
  */
119
119
  // * entries () {
120
120
  // // needs transaction blocks?
121
- // // for (const [str, bytes] of this.blocks) {
121
+ // // for (const [str, bytes] of this.#blocks) {
122
122
  // // yield { cid: parse(str), bytes }
123
123
  // // }
124
- // for (const [str, bytes] of this.committedBlocks) {
124
+ // for (const [str, bytes] of this.#committedBlocks) {
125
125
  // yield { cid: parse(str), bytes }
126
126
  // }
127
127
  // }
@@ -134,7 +134,7 @@ export default class TransactionBlockstore {
134
134
  */
135
135
  begin (label = '') {
136
136
  const innerTransactionBlockstore = new InnerBlockstore(label, this)
137
- this.inflightTransactions.add(innerTransactionBlockstore)
137
+ this.#inflightTransactions.add(innerTransactionBlockstore)
138
138
  return innerTransactionBlockstore
139
139
  }
140
140
 
@@ -144,7 +144,7 @@ export default class TransactionBlockstore {
144
144
  * @memberof TransactionBlockstore
145
145
  */
146
146
  async commit (innerBlockstore) {
147
- await this.doCommit(innerBlockstore)
147
+ await this.#doCommit(innerBlockstore)
148
148
  }
149
149
 
150
150
  // first get the transaction blockstore from the map of transaction blockstores
@@ -152,14 +152,14 @@ export default class TransactionBlockstore {
152
152
  // then write the transaction blockstore to a car
153
153
  // then write the car to the valet
154
154
  // then remove the transaction blockstore from the map of transaction blockstores
155
- doCommit = async innerBlockstore => {
155
+ #doCommit = async innerBlockstore => {
156
156
  const cids = new Set()
157
157
  for (const { cid, bytes } of innerBlockstore.entries()) {
158
158
  const stringCid = cid.toString() // unnecessary string conversion, can we fix upstream?
159
- if (this.committedBlocks.has(stringCid)) {
159
+ if (this.#committedBlocks.has(stringCid)) {
160
160
  // console.log('Duplicate block: ' + stringCid) // todo some of this can be avoided, cost is extra size on car files
161
161
  } else {
162
- this.committedBlocks.set(stringCid, bytes)
162
+ this.#committedBlocks.set(stringCid, bytes)
163
163
  cids.add(stringCid)
164
164
  }
165
165
  }
@@ -175,7 +175,7 @@ export default class TransactionBlockstore {
175
175
  * @memberof TransactionBlockstore
176
176
  */
177
177
  retire (innerBlockstore) {
178
- this.inflightTransactions.delete(innerBlockstore)
178
+ this.#inflightTransactions.delete(innerBlockstore)
179
179
  }
180
180
  }
181
181
 
@@ -206,7 +206,7 @@ export const doTransaction = async (label, blockstore, doFun) => {
206
206
  /** @implements {BlockFetcher} */
207
207
  export class InnerBlockstore {
208
208
  /** @type {Map<string, Uint8Array>} */
209
- blocks = new Map()
209
+ #blocks = new Map()
210
210
  lastCid = null
211
211
  label = ''
212
212
  parentBlockstore = null
@@ -222,7 +222,7 @@ export class InnerBlockstore {
222
222
  */
223
223
  async get (cid) {
224
224
  const key = cid.toString()
225
- let bytes = this.blocks.get(key)
225
+ let bytes = this.#blocks.get(key)
226
226
  if (bytes) {
227
227
  return { cid, bytes }
228
228
  }
@@ -238,12 +238,12 @@ export class InnerBlockstore {
238
238
  */
239
239
  put (cid, bytes) {
240
240
  // console.log('put', cid)
241
- this.blocks.set(cid.toString(), bytes)
241
+ this.#blocks.set(cid.toString(), bytes)
242
242
  this.lastCid = cid
243
243
  }
244
244
 
245
245
  * entries () {
246
- for (const [str, bytes] of this.blocks) {
246
+ for (const [str, bytes] of this.#blocks) {
247
247
  yield { cid: parse(str), bytes }
248
248
  }
249
249
  }
package/src/db-index.js CHANGED
@@ -179,9 +179,9 @@ export default class DbIndex {
179
179
  async query (query, update = true) {
180
180
  // const callId = Math.random().toString(36).substring(2, 7)
181
181
  // todo pass a root to query a snapshot
182
- // console.time(callId + '.updateIndex')
183
- update && await this.updateIndex(this.database.indexBlocks)
184
- // console.timeEnd(callId + '.updateIndex')
182
+ // console.time(callId + '.#updateIndex')
183
+ update && await this.#updateIndex(this.database.indexBlocks)
184
+ // console.timeEnd(callId + '.#updateIndex')
185
185
  // console.time(callId + '.doIndexQuery')
186
186
  // console.log('query', query)
187
187
  const response = await doIndexQuery(this.database.indexBlocks, this.indexByKey, query)
@@ -200,18 +200,18 @@ export default class DbIndex {
200
200
  * @returns {Promise<void>}
201
201
  */
202
202
 
203
- async updateIndex (blocks) {
203
+ async #updateIndex (blocks) {
204
204
  // todo this could enqueue the request and give fresh ones to all second comers -- right now it gives out stale promises while working
205
205
  // what would it do in a world where all indexes provide a database snapshot to query?
206
206
  if (this.updateIndexPromise) return this.updateIndexPromise
207
- this.updateIndexPromise = this.innerUpdateIndex(blocks)
207
+ this.updateIndexPromise = this.#innerUpdateIndex(blocks)
208
208
  this.updateIndexPromise.finally(() => { this.updateIndexPromise = null })
209
209
  return this.updateIndexPromise
210
210
  }
211
211
 
212
- async innerUpdateIndex (inBlocks) {
212
+ async #innerUpdateIndex (inBlocks) {
213
213
  // const callTag = Math.random().toString(36).substring(4)
214
- // console.log(`updateIndex ${callTag} >`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
214
+ // console.log(`#updateIndex ${callTag} >`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
215
215
  // todo remove this hack
216
216
  if (ALWAYS_REBUILD) {
217
217
  this.indexById = { root: null, cid: null }
@@ -224,15 +224,15 @@ export default class DbIndex {
224
224
  // console.timeEnd(callTag + '.changesSince')
225
225
  // console.log('result.rows.length', result.rows.length)
226
226
 
227
- // console.time(callTag + '.doTransactionupdateIndex')
228
- // console.log('updateIndex changes length', result.rows.length)
227
+ // console.time(callTag + '.doTransaction#updateIndex')
228
+ // console.log('#updateIndex changes length', result.rows.length)
229
229
 
230
230
  if (result.rows.length === 0) {
231
- // console.log('updateIndex < no changes', result.clock)
231
+ // console.log('#updateIndex < no changes', result.clock)
232
232
  this.dbHead = result.clock
233
233
  return
234
234
  }
235
- await doTransaction('updateIndex', inBlocks, async (blocks) => {
235
+ await doTransaction('#updateIndex', inBlocks, async (blocks) => {
236
236
  let oldIndexEntries = []
237
237
  let removeByIdIndexEntries = []
238
238
  await loadIndex(blocks, this.indexById, idIndexOpts)
@@ -252,8 +252,8 @@ export default class DbIndex {
252
252
  this.dbHead = result.clock
253
253
  })
254
254
  this.database.notifyExternal('dbIndex')
255
- // console.timeEnd(callTag + '.doTransactionupdateIndex')
256
- // console.log(`updateIndex ${callTag} <`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
255
+ // console.timeEnd(callTag + '.doTransaction#updateIndex')
256
+ // console.log(`#updateIndex ${callTag} <`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
257
257
  }
258
258
  }
259
259
 
package/src/fireproof.js CHANGED
@@ -18,7 +18,7 @@ import charwise from 'charwise'
18
18
  *
19
19
  */
20
20
  export default class Fireproof {
21
- listeners = new Set()
21
+ #listeners = new Set()
22
22
 
23
23
  /**
24
24
  * @function storage
@@ -82,12 +82,12 @@ export default class Fireproof {
82
82
  * @instance
83
83
  */
84
84
  async notifyReset () {
85
- await this.notifyListeners({ _reset: true, _clock: this.clockToJSON() })
85
+ await this.#notifyListeners({ _reset: true, _clock: this.clockToJSON() })
86
86
  }
87
87
 
88
88
  // used be indexes etc to notify database listeners of new availability
89
89
  async notifyExternal (source = 'unknown') {
90
- await this.notifyListeners({ _external: source, _clock: this.clockToJSON() })
90
+ await this.#notifyListeners({ _external: source, _clock: this.clockToJSON() })
91
91
  }
92
92
 
93
93
  /**
@@ -147,7 +147,7 @@ export default class Fireproof {
147
147
  * @memberof Fireproof
148
148
  * @instance
149
149
  */
150
- async runValidation (doc) {
150
+ async #runValidation (doc) {
151
151
  if (this.config && this.config.validateChange) {
152
152
  const oldDoc = await this.get(doc._id)
153
153
  .then((doc) => doc)
@@ -197,8 +197,8 @@ export default class Fireproof {
197
197
  */
198
198
  async put ({ _id, _proof, ...doc }) {
199
199
  const id = _id || 'f' + Math.random().toString(36).slice(2)
200
- await this.runValidation({ _id: id, ...doc })
201
- return await this.putToProllyTree({ key: id, value: doc }, doc._clock)
200
+ await this.#runValidation({ _id: id, ...doc })
201
+ return await this.#putToProllyTree({ key: id, value: doc }, doc._clock)
202
202
  }
203
203
 
204
204
  /**
@@ -217,10 +217,10 @@ export default class Fireproof {
217
217
  } else {
218
218
  id = docOrId
219
219
  }
220
- await this.runValidation({ _id: id, _deleted: true })
221
- return await this.putToProllyTree({ key: id, del: true }, clock) // not working at prolly tree layer?
220
+ await this.#runValidation({ _id: id, _deleted: true })
221
+ return await this.#putToProllyTree({ key: id, del: true }, clock) // not working at prolly tree layer?
222
222
  // this tombstone is temporary until we can get the prolly tree to delete
223
- // return await this.putToProllyTree({ key: id, value: null }, clock)
223
+ // return await this.#putToProllyTree({ key: id, value: null }, clock)
224
224
  }
225
225
 
226
226
  /**
@@ -229,7 +229,7 @@ export default class Fireproof {
229
229
  * @param {Object<{key : string, value: any}>} event - the event to add
230
230
  * @returns {Object<{ id: string, clock: CID[] }>} - The result of adding the event to storage
231
231
  */
232
- async putToProllyTree (decodedEvent, clock = null) {
232
+ async #putToProllyTree (decodedEvent, clock = null) {
233
233
  const event = encodeEvent(decodedEvent)
234
234
  if (clock && JSON.stringify(clock) !== JSON.stringify(this.clockToJSON())) {
235
235
  // we need to check and see what version of the document exists at the clock specified
@@ -241,7 +241,7 @@ export default class Fireproof {
241
241
  }
242
242
  }
243
243
  const result = await doTransaction(
244
- 'putToProllyTree',
244
+ '#putToProllyTree',
245
245
  this.blocks,
246
246
  async (blocks) => await put(blocks, this.clock, event)
247
247
  )
@@ -251,7 +251,7 @@ export default class Fireproof {
251
251
  }
252
252
  // console.log('new clock head', this.instanceId, result.head.toString())
253
253
  this.clock = result.head // do we want to do this as a finally block
254
- await this.notifyListeners([decodedEvent]) // this type is odd
254
+ await this.#notifyListeners([decodedEvent]) // this type is odd
255
255
  return {
256
256
  id: decodedEvent.key,
257
257
  clock: this.clockToJSON(),
@@ -290,15 +290,15 @@ export default class Fireproof {
290
290
  * @memberof Fireproof
291
291
  */
292
292
  registerListener (listener) {
293
- this.listeners.add(listener)
293
+ this.#listeners.add(listener)
294
294
  return () => {
295
- this.listeners.delete(listener)
295
+ this.#listeners.delete(listener)
296
296
  }
297
297
  }
298
298
 
299
- async notifyListeners (changes) {
299
+ async #notifyListeners (changes) {
300
300
  // await sleep(10)
301
- for (const listener of this.listeners) {
301
+ for (const listener of this.#listeners) {
302
302
  await listener(changes)
303
303
  }
304
304
  }
package/src/listener.js CHANGED
@@ -10,8 +10,8 @@
10
10
  // import { ChangeEvent } from './db-index'
11
11
 
12
12
  export default class Listener {
13
- subcribers = new Map()
14
- doStopListening = null
13
+ #subcribers = new Map()
14
+ #doStopListening = null
15
15
 
16
16
  constructor (database, routingFn) {
17
17
  /** routingFn
@@ -19,7 +19,7 @@ export default class Listener {
19
19
  * @type {Fireproof}
20
20
  */
21
21
  this.database = database
22
- this.doStopListening = database.registerListener(changes => this.onChanges(changes))
22
+ this.#doStopListening = database.registerListener(changes => this.#onChanges(changes))
23
23
  /**
24
24
  * The map function to apply to each entry in the database.
25
25
  * @type {Function}
@@ -41,7 +41,7 @@ export default class Listener {
41
41
  * @instance
42
42
  */
43
43
  on (topic, subscriber, since) {
44
- const listOfTopicSubscribers = getTopicList(this.subcribers, topic)
44
+ const listOfTopicSubscribers = getTopicList(this.#subcribers, topic)
45
45
  listOfTopicSubscribers.push(subscriber)
46
46
  if (typeof since !== 'undefined') {
47
47
  this.database.changesSince(since).then(({ rows: changes }) => {
@@ -55,16 +55,16 @@ export default class Listener {
55
55
  }
56
56
  }
57
57
 
58
- onChanges (changes) {
58
+ #onChanges (changes) {
59
59
  if (Array.isArray(changes)) {
60
60
  const seenTopics = topicsForChanges(changes, this.routingFn)
61
61
  for (const [topic, keys] of seenTopics) {
62
- const listOfTopicSubscribers = getTopicList(this.subcribers, topic)
62
+ const listOfTopicSubscribers = getTopicList(this.#subcribers, topic)
63
63
  listOfTopicSubscribers.forEach(subscriber => keys.forEach(key => subscriber(key)))
64
64
  }
65
65
  } else {
66
66
  // non-arrays go to all subscribers
67
- for (const [, listOfTopicSubscribers] of this.subcribers) {
67
+ for (const [, listOfTopicSubscribers] of this.#subcribers) {
68
68
  listOfTopicSubscribers.forEach(subscriber => subscriber(changes))
69
69
  }
70
70
  }
package/src/valet.js CHANGED
@@ -21,9 +21,9 @@ const NO_ENCRYPT =
21
21
  export default class Valet {
22
22
  idb = null
23
23
  name = null
24
- uploadQueue = null
25
- alreadyEnqueued = new Set()
26
- keyMaterial = null
24
+ #uploadQueue = null
25
+ #alreadyEnqueued = new Set()
26
+ #keyMaterial = null
27
27
  keyId = 'null'
28
28
 
29
29
  /**
@@ -35,7 +35,7 @@ export default class Valet {
35
35
  constructor (name = 'default', keyMaterial) {
36
36
  this.name = name
37
37
  this.setKeyMaterial(keyMaterial)
38
- this.uploadQueue = cargoQueue(async (tasks, callback) => {
38
+ this.#uploadQueue = cargoQueue(async (tasks, callback) => {
39
39
  console.log(
40
40
  'queue worker',
41
41
  tasks.length,
@@ -56,7 +56,7 @@ export default class Valet {
56
56
  callback()
57
57
  })
58
58
 
59
- this.uploadQueue.drain(async () => {
59
+ this.#uploadQueue.drain(async () => {
60
60
  return await this.withDB(async db => {
61
61
  const carKeys = (await db.getAllFromIndex('cidToCar', 'pending')).map(c => c.car)
62
62
  for (const carKey of carKeys) {
@@ -70,17 +70,17 @@ export default class Valet {
70
70
  }
71
71
 
72
72
  getKeyMaterial () {
73
- return this.keyMaterial
73
+ return this.#keyMaterial
74
74
  }
75
75
 
76
76
  setKeyMaterial (km) {
77
77
  if (km && !NO_ENCRYPT) {
78
78
  const hex = Uint8Array.from(Buffer.from(km, 'hex'))
79
- this.keyMaterial = km
79
+ this.#keyMaterial = km
80
80
  const hash = sha1sync(hex)
81
81
  this.keyId = Buffer.from(hash).toString('hex')
82
82
  } else {
83
- this.keyMaterial = null
83
+ this.#keyMaterial = null
84
84
  this.keyId = 'null'
85
85
  }
86
86
  // console.trace('keyId', this.name, this.keyId)
@@ -95,9 +95,9 @@ export default class Valet {
95
95
  */
96
96
  async writeTransaction (innerBlockstore, cids) {
97
97
  if (innerBlockstore.lastCid) {
98
- if (this.keyMaterial) {
98
+ if (this.#keyMaterial) {
99
99
  // console.log('encrypting car', innerBlockstore.label)
100
- const newCar = await blocksToEncryptedCarBlock(innerBlockstore.lastCid, innerBlockstore, this.keyMaterial)
100
+ const newCar = await blocksToEncryptedCarBlock(innerBlockstore.lastCid, innerBlockstore, this.#keyMaterial)
101
101
  await this.parkCar(newCar.cid.toString(), newCar.bytes, cids)
102
102
  } else {
103
103
  const newCar = await blocksToCarBlock(innerBlockstore.lastCid, innerBlockstore)
@@ -140,14 +140,14 @@ export default class Valet {
140
140
 
141
141
  // upload to web3.storage if we have credentials
142
142
  if (this.uploadFunction) {
143
- if (this.alreadyEnqueued.has(carCid)) {
143
+ if (this.#alreadyEnqueued.has(carCid)) {
144
144
  // console.log('already enqueued', carCid)
145
145
  return
146
146
  }
147
147
  // don't await this, it will be done in the queue
148
148
  // console.log('add to queue', carCid, value.length)
149
- this.uploadQueue.push({ carCid, value })
150
- this.alreadyEnqueued.add(carCid)
149
+ this.#uploadQueue.push({ carCid, value })
150
+ this.#alreadyEnqueued.add(carCid)
151
151
  } else {
152
152
  // console.log('no upload function', carCid, value.length, this.uploadFunction)
153
153
  }
@@ -165,7 +165,7 @@ export default class Valet {
165
165
  }
166
166
  const carBytes = await tx.objectStore('cars').get(carCid)
167
167
  const reader = await CarReader.fromBytes(carBytes)
168
- if (this.keyMaterial) {
168
+ if (this.#keyMaterial) {
169
169
  const roots = await reader.getRoots()
170
170
  const readerGetWithCodec = async cid => {
171
171
  const got = await reader.get(cid)
@@ -182,7 +182,7 @@ export default class Valet {
182
182
  // console.log('decoded', decoded.value)
183
183
  return decoded
184
184
  }
185
- const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.keyMaterial)
185
+ const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.#keyMaterial)
186
186
  const block = blocks.find(b => b.cid.toString() === dataCID)
187
187
  if (block) {
188
188
  return block.bytes
package/test/block.js CHANGED
@@ -8,14 +8,14 @@ import { parse } from 'multiformats/link'
8
8
  /** @implements {BlockFetcher} */
9
9
  export class MemoryBlockstore {
10
10
  /** @type {Map<string, Uint8Array>} */
11
- blocks = new Map()
11
+ #blocks = new Map()
12
12
 
13
13
  /**
14
14
  * @param {import('../src/link').AnyLink} cid
15
15
  * @returns {Promise<AnyBlock | undefined>}
16
16
  */
17
17
  async get (cid) {
18
- const bytes = this.blocks.get(cid.toString())
18
+ const bytes = this.#blocks.get(cid.toString())
19
19
  if (!bytes) return
20
20
  return { cid, bytes }
21
21
  }
@@ -26,7 +26,7 @@ export class MemoryBlockstore {
26
26
  */
27
27
  async put (cid, bytes) {
28
28
  // console.log('put', cid)
29
- this.blocks.set(cid.toString(), bytes)
29
+ this.#blocks.set(cid.toString(), bytes)
30
30
  }
31
31
 
32
32
  /**
@@ -34,11 +34,11 @@ export class MemoryBlockstore {
34
34
  * @param {Uint8Array} bytes
35
35
  */
36
36
  putSync (cid, bytes) {
37
- this.blocks.set(cid.toString(), bytes)
37
+ this.#blocks.set(cid.toString(), bytes)
38
38
  }
39
39
 
40
40
  * entries () {
41
- for (const [str, bytes] of this.blocks) {
41
+ for (const [str, bytes] of this.#blocks) {
42
42
  yield { cid: parse(str), bytes }
43
43
  }
44
44
  }
@@ -46,16 +46,16 @@ export class MemoryBlockstore {
46
46
 
47
47
  export class MultiBlockFetcher {
48
48
  /** @type {BlockFetcher[]} */
49
- fetchers
49
+ #fetchers
50
50
 
51
51
  /** @param {BlockFetcher[]} fetchers */
52
52
  constructor (...fetchers) {
53
- this.fetchers = fetchers
53
+ this.#fetchers = fetchers
54
54
  }
55
55
 
56
56
  /** @param {import('../src/link').AnyLink} link */
57
57
  async get (link) {
58
- for (const f of this.fetchers) {
58
+ for (const f of this.#fetchers) {
59
59
  const v = await f.get(link)
60
60
  if (v) {
61
61
  return v