@mblaney/holster 2.3.1 → 2.3.3
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/dist/holster.js +3 -3
- package/dist/holster.js.map +3 -3
- package/package.json +1 -1
- package/src/holster.js +24 -17
- package/ts/src/holster.ts +32 -24
- package/ts/src/user.ts +8 -3
package/package.json
CHANGED
package/src/holster.js
CHANGED
|
@@ -416,10 +416,10 @@ const Holster = opt => {
|
|
|
416
416
|
return
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
-
// lex
|
|
419
|
+
// lex isn't part of the chain below, so without a callback the
|
|
420
|
+
// result is returned as a promise instead.
|
|
420
421
|
if (lex && typeof cb !== "function") {
|
|
421
|
-
|
|
422
|
-
return
|
|
422
|
+
return new Promise(resolve => api(ctxid).get(key, lex, resolve, _opt))
|
|
423
423
|
}
|
|
424
424
|
|
|
425
425
|
// Top level keys are added to a root node so their values don't need
|
|
@@ -462,10 +462,12 @@ const Holster = opt => {
|
|
|
462
462
|
return
|
|
463
463
|
}
|
|
464
464
|
|
|
465
|
-
// lex
|
|
465
|
+
// lex isn't part of the chain below, so without a callback the
|
|
466
|
+
// result is returned as a promise instead.
|
|
466
467
|
if (lex && typeof cb !== "function") {
|
|
467
|
-
|
|
468
|
-
|
|
468
|
+
return new Promise(resolve =>
|
|
469
|
+
api(ctxid).next(key, lex, resolve, _opt),
|
|
470
|
+
)
|
|
469
471
|
}
|
|
470
472
|
|
|
471
473
|
const ctx = allctx.get(ctxid)
|
|
@@ -769,6 +771,9 @@ const Holster = opt => {
|
|
|
769
771
|
// same listener. Scoped to this one on() call's closure, so concurrent
|
|
770
772
|
// subscriptions (even on the same key) can each track their own.
|
|
771
773
|
let listenedSoul = soul
|
|
774
|
+
// Each update starts its own async read, and an earlier one can finish
|
|
775
|
+
// last - only the newest is delivered, so stale data can't follow it.
|
|
776
|
+
let latestRun = 0
|
|
772
777
|
|
|
773
778
|
map.set(cb, () => {
|
|
774
779
|
// Bail out if off() has already cleaned up this context. The mapped
|
|
@@ -781,6 +786,12 @@ const Holster = opt => {
|
|
|
781
786
|
// have an update and should not call cb twice.
|
|
782
787
|
clearTimeout(retryTimer)
|
|
783
788
|
retryTimer = null
|
|
789
|
+
const run = ++latestRun
|
|
790
|
+
const deliver = data => {
|
|
791
|
+
if (run !== latestRun) return
|
|
792
|
+
retryTimer = null
|
|
793
|
+
cb(data)
|
|
794
|
+
}
|
|
784
795
|
|
|
785
796
|
// Resolves {soul, item} to a genuine value, following a rel to its
|
|
786
797
|
// target if the property turns out to be one. This is checked on
|
|
@@ -796,6 +807,7 @@ const Holster = opt => {
|
|
|
796
807
|
// way the rel branch below already retries on a null target
|
|
797
808
|
// read.
|
|
798
809
|
const resolveValue = (retries, node, value) => {
|
|
810
|
+
if (run !== latestRun) return
|
|
799
811
|
const id = utils.rel.is(value)
|
|
800
812
|
if (id) {
|
|
801
813
|
if (listenedSoul !== id) {
|
|
@@ -803,21 +815,16 @@ const Holster = opt => {
|
|
|
803
815
|
wire.on({"#": id, ".": null}, map.get(cb), false, _opt)
|
|
804
816
|
listenedSoul = id
|
|
805
817
|
}
|
|
806
|
-
readRelTarget(id, ctx ? ctx.user : null, _opt).then(
|
|
807
|
-
retryTimer = null
|
|
808
|
-
cb(data)
|
|
809
|
-
})
|
|
818
|
+
readRelTarget(id, ctx ? ctx.user : null, _opt).then(deliver)
|
|
810
819
|
return
|
|
811
820
|
}
|
|
812
821
|
|
|
813
822
|
if (value !== undefined && value !== null) {
|
|
814
|
-
|
|
815
|
-
cb(value)
|
|
823
|
+
deliver(value)
|
|
816
824
|
return
|
|
817
825
|
}
|
|
818
826
|
if (retries >= maxRetries) {
|
|
819
|
-
|
|
820
|
-
cb(value !== undefined ? value : null)
|
|
827
|
+
deliver(value !== undefined ? value : null)
|
|
821
828
|
return
|
|
822
829
|
}
|
|
823
830
|
// Fast once the parent node already exists (a value is likely
|
|
@@ -977,10 +984,10 @@ const Holster = opt => {
|
|
|
977
984
|
return
|
|
978
985
|
}
|
|
979
986
|
|
|
980
|
-
// lex
|
|
987
|
+
// lex isn't part of the chain below, so without a callback the
|
|
988
|
+
// result is returned as a promise instead.
|
|
981
989
|
if (lex && !cb) {
|
|
982
|
-
|
|
983
|
-
return
|
|
990
|
+
return new Promise(resolve => user.get(keys, lex, resolve, _opt))
|
|
984
991
|
}
|
|
985
992
|
|
|
986
993
|
ctxid = utils.text.random()
|
package/ts/src/holster.ts
CHANGED
|
@@ -37,11 +37,8 @@ export interface HolsterAPI {
|
|
|
37
37
|
cb: (data: unknown) => void,
|
|
38
38
|
_opt?: WireOptions,
|
|
39
39
|
): HolsterAPI
|
|
40
|
-
(
|
|
41
|
-
|
|
42
|
-
lex?: LexWithDot,
|
|
43
|
-
_opt?: WireOptions,
|
|
44
|
-
): AwaitableHolsterAPI
|
|
40
|
+
(key: string | null, lex: LexWithDot, _opt?: WireOptions): Promise<unknown>
|
|
41
|
+
(key: string | null, lex?: null, _opt?: WireOptions): AwaitableHolsterAPI
|
|
45
42
|
}
|
|
46
43
|
next: {
|
|
47
44
|
(
|
|
@@ -55,11 +52,8 @@ export interface HolsterAPI {
|
|
|
55
52
|
cb: (data: unknown) => void,
|
|
56
53
|
_opt?: WireOptions,
|
|
57
54
|
): HolsterAPI
|
|
58
|
-
(
|
|
59
|
-
|
|
60
|
-
lex?: LexWithDot,
|
|
61
|
-
_opt?: WireOptions,
|
|
62
|
-
): AwaitableHolsterAPI
|
|
55
|
+
(key: string | null, lex: LexWithDot, _opt?: WireOptions): Promise<unknown>
|
|
56
|
+
(key: string | null, lex?: null, _opt?: WireOptions): AwaitableHolsterAPI
|
|
63
57
|
}
|
|
64
58
|
put: {
|
|
65
59
|
(
|
|
@@ -601,9 +595,12 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
|
|
|
601
595
|
return this
|
|
602
596
|
}
|
|
603
597
|
|
|
598
|
+
// lex isn't part of the chain below, so without a callback the
|
|
599
|
+
// result is returned as a promise instead.
|
|
604
600
|
if (lexFilter && typeof callback !== "function") {
|
|
605
|
-
|
|
606
|
-
|
|
601
|
+
return new Promise(resolve =>
|
|
602
|
+
api(ctxid).get(key, lexFilter, resolve, opts),
|
|
603
|
+
) as never
|
|
607
604
|
}
|
|
608
605
|
|
|
609
606
|
ctxid = utils.text.random()
|
|
@@ -662,9 +659,12 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
|
|
|
662
659
|
return this
|
|
663
660
|
}
|
|
664
661
|
|
|
662
|
+
// lex isn't part of the chain below, so without a callback the
|
|
663
|
+
// result is returned as a promise instead.
|
|
665
664
|
if (lexFilter && typeof callback !== "function") {
|
|
666
|
-
|
|
667
|
-
|
|
665
|
+
return new Promise(resolve =>
|
|
666
|
+
api(ctxid).next(key, lexFilter, resolve, opts),
|
|
667
|
+
) as never
|
|
668
668
|
}
|
|
669
669
|
|
|
670
670
|
const ctx = allctx.get(ctxid)
|
|
@@ -1020,6 +1020,9 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
|
|
|
1020
1020
|
// on() call's closure, so concurrent subscriptions (even on the
|
|
1021
1021
|
// same key) each track their own independently.
|
|
1022
1022
|
let listenedSoul = soul
|
|
1023
|
+
// Each update starts its own async read, and an earlier one can finish
|
|
1024
|
+
// last - only the newest is delivered, so stale data can't follow it.
|
|
1025
|
+
let latestRun = 0
|
|
1023
1026
|
|
|
1024
1027
|
map.set(callback, () => {
|
|
1025
1028
|
// Bail out if off() has already cleaned up this context — the mapped
|
|
@@ -1031,6 +1034,12 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
|
|
|
1031
1034
|
// have an update and should not call callback twice.
|
|
1032
1035
|
clearTimeout(retryTimer!)
|
|
1033
1036
|
retryTimer = null
|
|
1037
|
+
const run = ++latestRun
|
|
1038
|
+
const deliver = (data: unknown) => {
|
|
1039
|
+
if (run !== latestRun) return
|
|
1040
|
+
retryTimer = null
|
|
1041
|
+
callback(data)
|
|
1042
|
+
}
|
|
1034
1043
|
|
|
1035
1044
|
// Resolves {soul, item} to a genuine value, following a rel to its
|
|
1036
1045
|
// target if the property turns out to be one - checked fresh on
|
|
@@ -1051,6 +1060,7 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
|
|
|
1051
1060
|
node: Record<string, GraphValue> | null | undefined,
|
|
1052
1061
|
value: unknown,
|
|
1053
1062
|
): void => {
|
|
1063
|
+
if (run !== latestRun) return
|
|
1054
1064
|
const id = utils.rel.is(value as GraphValue)
|
|
1055
1065
|
if (id) {
|
|
1056
1066
|
if (listenedSoul !== id) {
|
|
@@ -1063,21 +1073,16 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
|
|
|
1063
1073
|
)
|
|
1064
1074
|
listenedSoul = id
|
|
1065
1075
|
}
|
|
1066
|
-
readRelTarget(id, ctx ? ctx.user : null, opts).then(
|
|
1067
|
-
retryTimer = null
|
|
1068
|
-
callback(data)
|
|
1069
|
-
})
|
|
1076
|
+
readRelTarget(id, ctx ? ctx.user : null, opts).then(deliver)
|
|
1070
1077
|
return
|
|
1071
1078
|
}
|
|
1072
1079
|
|
|
1073
1080
|
if (value !== undefined && value !== null) {
|
|
1074
|
-
|
|
1075
|
-
callback(value)
|
|
1081
|
+
deliver(value)
|
|
1076
1082
|
return
|
|
1077
1083
|
}
|
|
1078
1084
|
if (retries >= maxRetries) {
|
|
1079
|
-
|
|
1080
|
-
callback(value !== undefined ? value : null)
|
|
1085
|
+
deliver(value !== undefined ? value : null)
|
|
1081
1086
|
return
|
|
1082
1087
|
}
|
|
1083
1088
|
// Fast once the parent node already exists (a value is likely
|
|
@@ -1261,9 +1266,12 @@ const Holster = (opt?: HolsterOptions | string | string[]): HolsterAPI => {
|
|
|
1261
1266
|
return this
|
|
1262
1267
|
}
|
|
1263
1268
|
|
|
1269
|
+
// lex isn't part of the chain below, so without a callback the
|
|
1270
|
+
// result is returned as a promise instead.
|
|
1264
1271
|
if (lexFilter && !callback) {
|
|
1265
|
-
|
|
1266
|
-
|
|
1272
|
+
return new Promise(resolve =>
|
|
1273
|
+
user.get!(keys, lexFilter, resolve, opts),
|
|
1274
|
+
) as never
|
|
1267
1275
|
}
|
|
1268
1276
|
|
|
1269
1277
|
ctxid = utils.text.random()
|
package/ts/src/user.ts
CHANGED
|
@@ -9,7 +9,7 @@ import SEA from "./sea.ts"
|
|
|
9
9
|
import type {
|
|
10
10
|
UserIdentity,
|
|
11
11
|
HolsterOptions,
|
|
12
|
-
|
|
12
|
+
LexWithDot,
|
|
13
13
|
WireOptions,
|
|
14
14
|
} from "./schemas.ts"
|
|
15
15
|
import type {HolsterAPI, AwaitableHolsterAPI} from "./holster.ts"
|
|
@@ -45,7 +45,7 @@ export interface UserInterface {
|
|
|
45
45
|
get?: {
|
|
46
46
|
(
|
|
47
47
|
keys: string | string[],
|
|
48
|
-
lex:
|
|
48
|
+
lex: LexWithDot,
|
|
49
49
|
cb: (data: unknown) => void,
|
|
50
50
|
_opt?: WireOptions,
|
|
51
51
|
): HolsterAPI
|
|
@@ -56,7 +56,12 @@ export interface UserInterface {
|
|
|
56
56
|
): HolsterAPI
|
|
57
57
|
(
|
|
58
58
|
keys: string | string[],
|
|
59
|
-
lex
|
|
59
|
+
lex: LexWithDot,
|
|
60
|
+
_opt?: WireOptions,
|
|
61
|
+
): Promise<unknown>
|
|
62
|
+
(
|
|
63
|
+
keys: string | string[],
|
|
64
|
+
lex?: null,
|
|
60
65
|
_opt?: WireOptions,
|
|
61
66
|
): AwaitableHolsterAPI
|
|
62
67
|
}
|