@mblaney/holster 1.0.26 → 1.0.28
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/build/holster.js +3 -3
- package/build/holster.js.map +3 -3
- package/package.json +1 -1
- package/src/get.js +3 -2
- package/src/holster.js +151 -129
- package/src/radisk.js +22 -7
- package/src/sea.js +0 -1
- package/src/store.js +6 -3
- package/src/wire.js +28 -24
package/package.json
CHANGED
package/src/get.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {match} from "./utils.js"
|
|
1
|
+
import {match, userPublicKey} from "./utils.js"
|
|
2
2
|
|
|
3
3
|
const Get = (lex, graph) => {
|
|
4
4
|
if (!lex || typeof lex !== "object") {
|
|
@@ -34,7 +34,8 @@ const Get = (lex, graph) => {
|
|
|
34
34
|
}
|
|
35
35
|
} else {
|
|
36
36
|
for (const key of Object.keys(graph[soul])) {
|
|
37
|
-
|
|
37
|
+
// Always include userPublicKey for verification, regardless of filter
|
|
38
|
+
if (key === userPublicKey || match(lex["."], key)) {
|
|
38
39
|
node[key] = graph[soul][key]
|
|
39
40
|
node._[">"][key] = graph[soul]._[">"][key]
|
|
40
41
|
const state = graph[soul]._[">"][key]
|
package/src/holster.js
CHANGED
|
@@ -67,12 +67,15 @@ const Holster = opt => {
|
|
|
67
67
|
for (const key of Object.keys(msg.put[soul])) {
|
|
68
68
|
const id = utils.rel.is(msg.put[soul][key])
|
|
69
69
|
if (id) {
|
|
70
|
-
// Due to message queuing, the related node might not be available yet
|
|
71
70
|
// Retry with delays if we get null
|
|
72
71
|
const attemptRead = async (retries = 0) => {
|
|
73
72
|
const data = await new Promise(res => {
|
|
74
73
|
const _ctxid = utils.text.random()
|
|
75
|
-
allctx.
|
|
74
|
+
const ctx = allctx.get(ctxid)
|
|
75
|
+
allctx.set(_ctxid, {
|
|
76
|
+
chain: [{item: null, soul: id}],
|
|
77
|
+
user: ctx ? ctx.user : null,
|
|
78
|
+
})
|
|
76
79
|
api(_ctxid).next(null, res, _opt)
|
|
77
80
|
})
|
|
78
81
|
if (data !== null || retries >= 5) {
|
|
@@ -157,11 +160,7 @@ const Holster = opt => {
|
|
|
157
160
|
{"#": soul, ".": item},
|
|
158
161
|
async msg => {
|
|
159
162
|
if (msg.err) {
|
|
160
|
-
|
|
161
|
-
console.log(`error getting ${soul}: ${msg.err}`)
|
|
162
|
-
} else {
|
|
163
|
-
console.log(`error getting ${item} on ${soul}: ${msg.err}`)
|
|
164
|
-
}
|
|
163
|
+
console.log(`error getting ${item} on ${soul}: ${msg.err}`)
|
|
165
164
|
if (cb) cb(null)
|
|
166
165
|
return
|
|
167
166
|
}
|
|
@@ -230,7 +229,7 @@ const Holster = opt => {
|
|
|
230
229
|
if (cb) cb(null)
|
|
231
230
|
}
|
|
232
231
|
},
|
|
233
|
-
request._opt,
|
|
232
|
+
{...request._opt, secure: ctx.user || opt.secure},
|
|
234
233
|
)
|
|
235
234
|
// Callback has been passed to next soul lookup or called above, so
|
|
236
235
|
// return false as the calling code should not continue.
|
|
@@ -382,66 +381,70 @@ const Holster = opt => {
|
|
|
382
381
|
// When result is true data is a property to put on the current soul.
|
|
383
382
|
// Need to check if item is a rel and also set the node to null. (This
|
|
384
383
|
// applies for any update from a rel to a property, not just null.)
|
|
385
|
-
wire.get(
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
return
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
let node = msg.put && msg.put[soul]
|
|
392
|
-
const current = node && node[item]
|
|
393
|
-
const id = utils.rel.is(current)
|
|
394
|
-
if (!id) {
|
|
395
|
-
// Not a rel, can just put the data.
|
|
396
|
-
if (!node) node = {}
|
|
397
|
-
node[item] = data
|
|
398
|
-
const g = await graph(soul, node, ctx.user, _ack)
|
|
399
|
-
if (g === null) return
|
|
400
|
-
|
|
401
|
-
wire.put(g, _ack)
|
|
402
|
-
return
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
wire.get({"#": id}, async msg => {
|
|
384
|
+
wire.get(
|
|
385
|
+
{"#": soul, ".": item},
|
|
386
|
+
async msg => {
|
|
406
387
|
if (msg.err) {
|
|
407
|
-
_ack(`error getting ${
|
|
388
|
+
_ack(`error getting ${soul}: ${msg.err}`)
|
|
408
389
|
return
|
|
409
390
|
}
|
|
410
391
|
|
|
411
|
-
|
|
412
|
-
|
|
392
|
+
let node = msg.put && msg.put[soul]
|
|
393
|
+
const current = node && node[item]
|
|
394
|
+
const id = utils.rel.is(current)
|
|
395
|
+
if (!id) {
|
|
396
|
+
// Not a rel, can just put the data.
|
|
397
|
+
if (!node) node = {}
|
|
398
|
+
node[item] = data
|
|
399
|
+
const g = await graph(soul, node, ctx.user, _ack)
|
|
400
|
+
if (g === null) return
|
|
401
|
+
|
|
402
|
+
wire.put(g, _ack)
|
|
413
403
|
return
|
|
414
404
|
}
|
|
415
405
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
key === utils.userPublicKey ||
|
|
421
|
-
key === utils.userSignature
|
|
422
|
-
) {
|
|
423
|
-
continue
|
|
406
|
+
wire.get({"#": id}, async msg => {
|
|
407
|
+
if (msg.err) {
|
|
408
|
+
_ack(`error getting ${id}: ${msg.err}`)
|
|
409
|
+
return
|
|
424
410
|
}
|
|
425
411
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const chain = [{item: key, soul: id}]
|
|
429
|
-
allctx.set(_ctxid, {chain: chain, user: ctx.user})
|
|
430
|
-
api(_ctxid).put(null, res)
|
|
431
|
-
})
|
|
432
|
-
if (err) {
|
|
433
|
-
_ack(err)
|
|
412
|
+
if (!msg.put || !msg.put[id]) {
|
|
413
|
+
_ack(`error ${id} not found`)
|
|
434
414
|
return
|
|
435
415
|
}
|
|
436
|
-
}
|
|
437
|
-
if (!node) node = {}
|
|
438
|
-
node[item] = data
|
|
439
|
-
const g = await graph(soul, node, ctx.user, _ack)
|
|
440
|
-
if (g === null) return
|
|
441
416
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
417
|
+
// null each of the properties on the node before putting data.
|
|
418
|
+
for (const key of Object.keys(msg.put[id])) {
|
|
419
|
+
if (
|
|
420
|
+
key === "_" ||
|
|
421
|
+
key === utils.userPublicKey ||
|
|
422
|
+
key === utils.userSignature
|
|
423
|
+
) {
|
|
424
|
+
continue
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const err = await new Promise(res => {
|
|
428
|
+
const _ctxid = utils.text.random()
|
|
429
|
+
const chain = [{item: key, soul: id}]
|
|
430
|
+
allctx.set(_ctxid, {chain: chain, user: ctx.user})
|
|
431
|
+
api(_ctxid).put(null, res)
|
|
432
|
+
})
|
|
433
|
+
if (err) {
|
|
434
|
+
_ack(err)
|
|
435
|
+
return
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (!node) node = {}
|
|
439
|
+
node[item] = data
|
|
440
|
+
const g = await graph(soul, node, ctx.user, _ack)
|
|
441
|
+
if (g === null) return
|
|
442
|
+
|
|
443
|
+
wire.put(g, _ack)
|
|
444
|
+
})
|
|
445
|
+
},
|
|
446
|
+
{secure: ctx.user || opt.secure},
|
|
447
|
+
)
|
|
445
448
|
return
|
|
446
449
|
}
|
|
447
450
|
|
|
@@ -449,88 +452,97 @@ const Holster = opt => {
|
|
|
449
452
|
// Need to check if a rel has already been added on the current node.
|
|
450
453
|
// Use attemptRead to retry if data hasn't propagated yet.
|
|
451
454
|
const attemptRead = (retries = 0) => {
|
|
452
|
-
wire.get(
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
455
|
+
wire.get(
|
|
456
|
+
{"#": soul, ".": item},
|
|
457
|
+
async msg => {
|
|
458
|
+
if (msg.err) {
|
|
459
|
+
_ack(`error getting ${soul}.${item}: ${msg.err}`)
|
|
460
|
+
return
|
|
461
|
+
}
|
|
457
462
|
|
|
458
|
-
|
|
459
|
-
|
|
463
|
+
let node = msg.put && msg.put[soul]
|
|
464
|
+
const current = node && node[item]
|
|
460
465
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
+
// If we didn't find the item but still have retries, retry
|
|
467
|
+
if (!current && retries < 5) {
|
|
468
|
+
await new Promise(r => setTimeout(r, 50))
|
|
469
|
+
return attemptRead(retries + 1)
|
|
470
|
+
}
|
|
466
471
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
472
|
+
const id = utils.rel.is(current)
|
|
473
|
+
if (!id) {
|
|
474
|
+
// The current rel doesn't exist, so add it first.
|
|
475
|
+
if (!node) node = {}
|
|
476
|
+
node[item] = utils.rel.ify(utils.text.random())
|
|
477
|
+
const g = await graph(soul, node, ctx.user, _ack)
|
|
478
|
+
if (g === null) return
|
|
474
479
|
|
|
475
|
-
|
|
480
|
+
wire.put(g, err => {
|
|
481
|
+
if (err) {
|
|
482
|
+
_ack(`error putting ${item} on ${soul}: ${err}`)
|
|
483
|
+
} else {
|
|
484
|
+
const _ctxid = utils.text.random()
|
|
485
|
+
const chain = [{item: item, soul: soul}]
|
|
486
|
+
// Pass on the previous context's callback and user flag here.
|
|
487
|
+
allctx.set(_ctxid, {
|
|
488
|
+
chain: chain,
|
|
489
|
+
user: ctx.user,
|
|
490
|
+
cb: ctx.cb,
|
|
491
|
+
})
|
|
492
|
+
api(_ctxid).put(data)
|
|
493
|
+
}
|
|
494
|
+
})
|
|
495
|
+
return
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const update = []
|
|
499
|
+
for (const key of result) {
|
|
500
|
+
const err = await new Promise(res => {
|
|
501
|
+
if (utils.obj.is(data[key]) && !utils.rel.is(data[key])) {
|
|
502
|
+
// Use the current rel as the context for nested objects.
|
|
503
|
+
const _ctxid = utils.text.random()
|
|
504
|
+
const chain = [{item: key, soul: id}]
|
|
505
|
+
allctx.set(_ctxid, {chain: chain, user: ctx.user})
|
|
506
|
+
api(_ctxid).put(data[key], res)
|
|
507
|
+
} else {
|
|
508
|
+
// Group the rest of the updates for put below.
|
|
509
|
+
update.push(key)
|
|
510
|
+
res(null)
|
|
511
|
+
}
|
|
512
|
+
})
|
|
476
513
|
if (err) {
|
|
477
|
-
_ack(
|
|
478
|
-
|
|
479
|
-
const _ctxid = utils.text.random()
|
|
480
|
-
const chain = [{item: item, soul: soul}]
|
|
481
|
-
// Pass on the previous context's callback and user flag here.
|
|
482
|
-
allctx.set(_ctxid, {chain: chain, user: ctx.user, cb: ctx.cb})
|
|
483
|
-
api(_ctxid).put(data)
|
|
514
|
+
_ack(err, ctxid)
|
|
515
|
+
return
|
|
484
516
|
}
|
|
485
|
-
}
|
|
486
|
-
return
|
|
487
|
-
}
|
|
517
|
+
}
|
|
488
518
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const err = await new Promise(res => {
|
|
492
|
-
if (utils.obj.is(data[key]) && !utils.rel.is(data[key])) {
|
|
493
|
-
// Use the current rel as the context for nested objects.
|
|
494
|
-
const _ctxid = utils.text.random()
|
|
495
|
-
const chain = [{item: key, soul: id}]
|
|
496
|
-
allctx.set(_ctxid, {chain: chain, user: ctx.user})
|
|
497
|
-
api(_ctxid).put(data[key], res)
|
|
498
|
-
} else {
|
|
499
|
-
// Group the rest of the updates for put below.
|
|
500
|
-
update.push(key)
|
|
501
|
-
res(null)
|
|
502
|
-
}
|
|
503
|
-
})
|
|
504
|
-
if (err) {
|
|
505
|
-
_ack(err, ctxid)
|
|
519
|
+
if (update.length === 0) {
|
|
520
|
+
_ack(null)
|
|
506
521
|
return
|
|
507
522
|
}
|
|
508
|
-
}
|
|
509
523
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
524
|
+
// The nested objects created above will also have rels on the
|
|
525
|
+
// parent object, so fetch the node so that the rest of the updates
|
|
526
|
+
// can be added.
|
|
527
|
+
wire.get({"#": id}, async msg => {
|
|
528
|
+
if (msg.err) {
|
|
529
|
+
_ack(`error getting ${id}: ${msg.err}`)
|
|
530
|
+
return
|
|
531
|
+
}
|
|
514
532
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
533
|
+
let node = msg.put && msg.put[id]
|
|
534
|
+
if (!node) node = {}
|
|
535
|
+
update.forEach(key => {
|
|
536
|
+
node[key] = data[key]
|
|
537
|
+
})
|
|
538
|
+
const g = await graph(id, node, ctx.user, _ack)
|
|
539
|
+
if (g === null) return
|
|
522
540
|
|
|
523
|
-
|
|
524
|
-
if (!node) node = {}
|
|
525
|
-
update.forEach(key => {
|
|
526
|
-
node[key] = data[key]
|
|
541
|
+
wire.put(g, _ack)
|
|
527
542
|
})
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
wire.put(g, _ack)
|
|
532
|
-
})
|
|
533
|
-
})
|
|
543
|
+
},
|
|
544
|
+
{secure: ctx.user || opt.secure},
|
|
545
|
+
)
|
|
534
546
|
}
|
|
535
547
|
attemptRead()
|
|
536
548
|
},
|
|
@@ -556,8 +568,15 @@ const Holster = opt => {
|
|
|
556
568
|
const {item, soul} = resolve({on: lex, _get: _get, _opt: _opt}, cb)
|
|
557
569
|
if (!soul) return
|
|
558
570
|
|
|
571
|
+
// Get the context to check if it has user info
|
|
572
|
+
const ctx = allctx.get(ctxid)
|
|
573
|
+
|
|
559
574
|
// Flag that this context is set from on and shouldn't be removed.
|
|
560
|
-
allctx.set(ctxid, {
|
|
575
|
+
allctx.set(ctxid, {
|
|
576
|
+
chain: [{item: item, soul: soul}],
|
|
577
|
+
on: true,
|
|
578
|
+
user: ctx ? ctx.user : null,
|
|
579
|
+
})
|
|
561
580
|
// Map the user's callback because it can also be passed to off,
|
|
562
581
|
// so need a reference to it to compare them.
|
|
563
582
|
// Create a new context for each listener invocation to avoid mutation
|
|
@@ -574,7 +593,10 @@ const Holster = opt => {
|
|
|
574
593
|
const attemptRead = async (retries = 0) => {
|
|
575
594
|
const data = await new Promise(res => {
|
|
576
595
|
const _ctxid = utils.text.random()
|
|
577
|
-
allctx.set(_ctxid, {
|
|
596
|
+
allctx.set(_ctxid, {
|
|
597
|
+
chain: [{item: null, soul: id}],
|
|
598
|
+
user: ctx ? ctx.user : null,
|
|
599
|
+
})
|
|
578
600
|
api(_ctxid).next(null, res, _opt)
|
|
579
601
|
})
|
|
580
602
|
if (data !== null || retries >= 5) {
|
|
@@ -591,7 +613,7 @@ const Holster = opt => {
|
|
|
591
613
|
cb(current !== undefined ? current : null)
|
|
592
614
|
}
|
|
593
615
|
},
|
|
594
|
-
_opt,
|
|
616
|
+
{..._opt, secure: ctx.user || opt.secure},
|
|
595
617
|
)
|
|
596
618
|
})
|
|
597
619
|
|
|
@@ -637,7 +659,7 @@ const Holster = opt => {
|
|
|
637
659
|
map.get(cb)()
|
|
638
660
|
}
|
|
639
661
|
},
|
|
640
|
-
_opt,
|
|
662
|
+
{..._opt, secure: ctx.user || opt.secure},
|
|
641
663
|
)
|
|
642
664
|
},
|
|
643
665
|
off: cb => {
|
package/src/radisk.js
CHANGED
|
@@ -34,6 +34,7 @@ const Radisk = opt => {
|
|
|
34
34
|
if (!opt.write) opt.write = 1 // Wait time before write in milliseconds
|
|
35
35
|
if (!opt.size) opt.size = 1024 * 1024 // File size on disk, default 1MB
|
|
36
36
|
if (!opt.memoryLimit) opt.memoryLimit = 500 // Memory limit in MB
|
|
37
|
+
if (!opt.readTimeout) opt.readTimeout = 1000 // Read timeout in milliseconds
|
|
37
38
|
if (typeof opt.cache === "undefined") opt.cache = true
|
|
38
39
|
|
|
39
40
|
if (!opt.store) {
|
|
@@ -126,20 +127,34 @@ const Radisk = opt => {
|
|
|
126
127
|
// Check if there's already a pending read for this key
|
|
127
128
|
if (pendingReads.has(key)) {
|
|
128
129
|
// Add callback to existing pending read
|
|
129
|
-
pendingReads.get(key).push(cb)
|
|
130
|
+
pendingReads.get(key).callbacks.push(cb)
|
|
130
131
|
return
|
|
131
132
|
}
|
|
132
133
|
|
|
133
|
-
// Start new read and create callback queue
|
|
134
|
-
|
|
134
|
+
// Start new read and create callback queue with fired flag
|
|
135
|
+
const pending = {callbacks: [cb], fired: false, timeoutId: null}
|
|
136
|
+
pendingReads.set(key, pending)
|
|
137
|
+
|
|
138
|
+
// Set a timeout to fire callbacks if read takes too long
|
|
139
|
+
pending.timeoutId = setTimeout(() => {
|
|
140
|
+
if (!pending.fired) {
|
|
141
|
+
pending.fired = true
|
|
142
|
+
pendingReads.delete(key)
|
|
143
|
+
const err = new Error("radisk read timeout")
|
|
144
|
+
pending.callbacks.forEach(callback => callback(err, undefined))
|
|
145
|
+
}
|
|
146
|
+
}, opt.readTimeout)
|
|
135
147
|
|
|
136
148
|
const readStart = Date.now()
|
|
137
149
|
return radisk.read(key, (err, result) => {
|
|
150
|
+
clearTimeout(pending.timeoutId)
|
|
138
151
|
perfLog("read", readStart, key)
|
|
139
|
-
// Execute all pending callbacks for this key
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
152
|
+
// Execute all pending callbacks for this key if timeout hasn't fired
|
|
153
|
+
if (!pending.fired) {
|
|
154
|
+
pending.fired = true
|
|
155
|
+
pendingReads.delete(key)
|
|
156
|
+
pending.callbacks.forEach(callback => callback(err, result))
|
|
157
|
+
}
|
|
143
158
|
})
|
|
144
159
|
}
|
|
145
160
|
|
package/src/sea.js
CHANGED
package/src/store.js
CHANGED
|
@@ -211,7 +211,7 @@ const Store = opt => {
|
|
|
211
211
|
const radisk = Radisk(opt)
|
|
212
212
|
|
|
213
213
|
return {
|
|
214
|
-
get: (lex, cb) => {
|
|
214
|
+
get: (lex, cb, _opt) => {
|
|
215
215
|
if (!lex || !utils.obj.is(lex)) {
|
|
216
216
|
cb("lex required")
|
|
217
217
|
return
|
|
@@ -221,12 +221,15 @@ const Store = opt => {
|
|
|
221
221
|
return
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
if (!_opt) _opt = {}
|
|
225
|
+
|
|
224
226
|
var soul = lex["#"]
|
|
225
|
-
var key = typeof lex["."] === "string" ? lex["."] : ""
|
|
227
|
+
var key = !_opt.secure && typeof lex["."] === "string" ? lex["."] : ""
|
|
226
228
|
var node
|
|
227
229
|
var signatures = {}
|
|
228
230
|
const each = (value, key) => {
|
|
229
|
-
|
|
231
|
+
// Always include userPublicKey for verification, regardless of filter
|
|
232
|
+
if (key !== utils.userPublicKey && !utils.match(lex["."], key)) return
|
|
230
233
|
|
|
231
234
|
if (!node) node = {_: {"#": soul, ">": {}}}
|
|
232
235
|
node[key] = value[0]
|
package/src/wire.js
CHANGED
|
@@ -318,36 +318,40 @@ const Wire = opt => {
|
|
|
318
318
|
return
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
store.get(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
321
|
+
store.get(
|
|
322
|
+
lex,
|
|
323
|
+
(err, ack) => {
|
|
324
|
+
if (ack) {
|
|
325
|
+
// Also send request on the wire to check for updates.
|
|
326
|
+
const sendResult = send(request)
|
|
327
|
+
if (sendResult && sendResult.err) {
|
|
328
|
+
cb({err: sendResult.err})
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
cb({put: ack, err: err})
|
|
327
332
|
return
|
|
328
333
|
}
|
|
329
|
-
cb({put: ack, err: err})
|
|
330
|
-
return
|
|
331
|
-
}
|
|
332
334
|
|
|
333
|
-
|
|
335
|
+
if (err) console.log(err)
|
|
334
336
|
|
|
335
|
-
|
|
337
|
+
queue[track] = cb
|
|
336
338
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
339
|
+
// Store timeout config to start after message is sent from queue
|
|
340
|
+
pendingTimeouts.set(track, {
|
|
341
|
+
lex: lex,
|
|
342
|
+
wait: _opt.wait || 100,
|
|
343
|
+
})
|
|
342
344
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
345
|
+
const sendResult = send(request)
|
|
346
|
+
if (sendResult && sendResult.err) {
|
|
347
|
+
cb({err: sendResult.err})
|
|
348
|
+
delete queue[track]
|
|
349
|
+
pendingTimeouts.delete(track)
|
|
350
|
+
return
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
_opt,
|
|
354
|
+
)
|
|
351
355
|
}
|
|
352
356
|
|
|
353
357
|
const api = send => {
|