@mblaney/holster 0.3.0 → 1.0.1
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/examples/user.js +3 -3
- package/package.json +1 -1
- package/src/get.js +17 -10
- package/src/ham.js +19 -22
- package/src/holster.js +256 -112
- package/src/sea.js +16 -4
- package/src/user.js +21 -22
- package/src/utils.js +13 -6
- package/src/wire.js +21 -15
- package/test/holster.get.test.js +36 -2
- package/test/holster.on.test.js +46 -5
- package/test/holster.put.test.js +23 -2
- package/test/holster.secure.test.js +1 -9
- package/test/holster.user.get.test.js +31 -4
- package/test/holster.user.lex.test.js +2 -2
- package/test/holster.user.on.test.js +62 -4
- package/test/holster.user.put.test.js +125 -59
- package/test/wire.test.js +7 -8
package/src/user.js
CHANGED
|
@@ -48,20 +48,23 @@ const User = (opt, wire) => {
|
|
|
48
48
|
priv: dec.priv,
|
|
49
49
|
epriv: dec.epriv,
|
|
50
50
|
}
|
|
51
|
-
// Holster API uses ctx to set the root node for user data.
|
|
52
|
-
user.ctx = "~" + data.pub
|
|
53
|
-
|
|
54
51
|
if (newPassword !== "") {
|
|
55
52
|
// Encrypt private key using new password and a new salt.
|
|
56
53
|
const salt = utils.text.random(64)
|
|
57
54
|
const work = await SEA.work(newPassword, salt)
|
|
58
55
|
const enc = await SEA.encrypt(dec, work)
|
|
59
|
-
|
|
60
|
-
const
|
|
56
|
+
// Put all fields so that verification applies to the whole node.
|
|
57
|
+
const update = {
|
|
58
|
+
username: username,
|
|
59
|
+
pub: data.pub,
|
|
60
|
+
epub: data.epub,
|
|
61
|
+
auth: JSON.stringify({enc: enc, salt: salt}),
|
|
62
|
+
}
|
|
63
|
+
const signed = await SEA.sign(update, user.is)
|
|
61
64
|
const graph = utils.graph(pub, signed.m, signed.s, data.pub)
|
|
62
65
|
wire.put(graph, err => {
|
|
63
66
|
if (err) {
|
|
64
|
-
done(`error putting ${
|
|
67
|
+
done(`error putting ${update} on ${pub}: ${err}`)
|
|
65
68
|
} else {
|
|
66
69
|
done(null)
|
|
67
70
|
}
|
|
@@ -236,40 +239,37 @@ const User = (opt, wire) => {
|
|
|
236
239
|
if (typeof globalThis.localStorage !== "undefined") {
|
|
237
240
|
globalThis.localStorage.setItem("user.is", JSON.stringify(user.is))
|
|
238
241
|
}
|
|
242
|
+
if (typeof globalThis.sessionStorage !== "undefined") {
|
|
243
|
+
globalThis.sessionStorage.removeItem("user.is")
|
|
244
|
+
}
|
|
239
245
|
return
|
|
240
246
|
}
|
|
241
247
|
|
|
242
248
|
if (typeof globalThis.sessionStorage !== "undefined") {
|
|
243
249
|
globalThis.sessionStorage.setItem("user.is", JSON.stringify(user.is))
|
|
244
250
|
}
|
|
251
|
+
if (typeof globalThis.localStorage !== "undefined") {
|
|
252
|
+
globalThis.localStorage.removeItem("user.is")
|
|
253
|
+
}
|
|
245
254
|
},
|
|
246
|
-
recall:
|
|
247
|
-
if (localStorage) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
user.ctx = "~" + user.is.pub
|
|
253
|
-
} else {
|
|
254
|
-
console.log("User credentials not stored in local storage")
|
|
255
|
-
}
|
|
255
|
+
recall: () => {
|
|
256
|
+
if (typeof globalThis.localStorage !== "undefined") {
|
|
257
|
+
const is = globalThis.localStorage.getItem("user.is")
|
|
258
|
+
if (is) {
|
|
259
|
+
user.is = JSON.parse(is)
|
|
260
|
+
return
|
|
256
261
|
}
|
|
257
|
-
return
|
|
258
262
|
}
|
|
259
263
|
|
|
260
264
|
if (typeof globalThis.sessionStorage !== "undefined") {
|
|
261
265
|
const is = globalThis.sessionStorage.getItem("user.is")
|
|
262
266
|
if (is) {
|
|
263
267
|
user.is = JSON.parse(is)
|
|
264
|
-
user.ctx = "~" + user.is.pub
|
|
265
|
-
} else {
|
|
266
|
-
console.log("User credentials not stored in session storage")
|
|
267
268
|
}
|
|
268
269
|
}
|
|
269
270
|
},
|
|
270
271
|
leave: () => {
|
|
271
272
|
user.is = null
|
|
272
|
-
user.ctx = null
|
|
273
273
|
if (typeof globalThis.localStorage !== "undefined") {
|
|
274
274
|
globalThis.localStorage.removeItem("user.is")
|
|
275
275
|
}
|
|
@@ -316,7 +316,6 @@ const User = (opt, wire) => {
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
user.is = null
|
|
319
|
-
user.ctx = null
|
|
320
319
|
// Return null on success. Note currently not updating ~@username,
|
|
321
320
|
// not sure if allowing username re-user is a good idea anyway?
|
|
322
321
|
if (cb) cb(null)
|
package/src/utils.js
CHANGED
|
@@ -68,19 +68,26 @@ export const rel = {
|
|
|
68
68
|
ify: soul => obj.put({}, "#", soul),
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
export const userSignature = "_holster_user_signature"
|
|
71
72
|
export const userPublicKey = "_holster_user_public_key"
|
|
72
73
|
|
|
73
74
|
// graph converts objects to graph format with updated states,
|
|
74
75
|
// with optional meta data to verify signed data.
|
|
75
76
|
export const graph = (soul, data, sig, pub) => {
|
|
76
|
-
const g = {[soul]: {_: {"#": soul, ">": {}
|
|
77
|
+
const g = {[soul]: {_: {"#": soul, ">": {}}}}
|
|
77
78
|
for (const [key, value] of Object.entries(data)) {
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
if (key !== "_" && key != userPublicKey && key != userSignature) {
|
|
80
|
+
g[soul][key] = value
|
|
81
|
+
g[soul]._[">"][key] = Date.now()
|
|
82
|
+
}
|
|
80
83
|
}
|
|
81
|
-
// If a public key
|
|
82
|
-
// ensure that future updates are only possible with the same
|
|
83
|
-
|
|
84
|
+
// If a signature and public key are provided they also need to be stored on
|
|
85
|
+
// the node to ensure that future updates are only possible with the same
|
|
86
|
+
// public key. The signature is requried because later get requests will
|
|
87
|
+
// broadcast the data as a put, which other devices will need to verify.
|
|
88
|
+
if (sig && pub) {
|
|
89
|
+
g[soul][userSignature] = sig
|
|
90
|
+
g[soul]._[">"][userSignature] = Date.now()
|
|
84
91
|
g[soul][userPublicKey] = pub
|
|
85
92
|
g[soul]._[">"][userPublicKey] = Date.now()
|
|
86
93
|
}
|
package/src/wire.js
CHANGED
|
@@ -37,13 +37,12 @@ const Wire = opt => {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
const node = data[soul]
|
|
40
|
-
const pub = node._ ? node._.p : undefined
|
|
41
40
|
const key = utils.userPublicKey
|
|
42
41
|
// If there is no current node then the data is ok to write without
|
|
43
42
|
// matching public keys, as the provided soul also needs a rel on the
|
|
44
43
|
// parent node which then also requires checking. Otherwise publc keys
|
|
45
44
|
// need to match for existing data.
|
|
46
|
-
if (!msg.put || !msg.put[soul] || msg.put[soul][key] ===
|
|
45
|
+
if (!msg.put || !msg.put[soul] || msg.put[soul][key] === node[key]) {
|
|
47
46
|
continue
|
|
48
47
|
}
|
|
49
48
|
|
|
@@ -107,32 +106,38 @@ const Wire = opt => {
|
|
|
107
106
|
}
|
|
108
107
|
}
|
|
109
108
|
|
|
110
|
-
const getWithCallback = (lex, cb, send,
|
|
109
|
+
const getWithCallback = (lex, cb, send, _opt) => {
|
|
111
110
|
if (!cb) return
|
|
112
111
|
|
|
113
|
-
if (!utils.obj.is(
|
|
112
|
+
if (!utils.obj.is(_opt)) _opt = {}
|
|
113
|
+
|
|
114
114
|
const ack = Get(lex, graph)
|
|
115
|
+
const track = utils.text.random(9)
|
|
116
|
+
// Request the whole node in secure mode for verification.
|
|
117
|
+
const request = JSON.stringify({
|
|
118
|
+
"#": dup.track(track),
|
|
119
|
+
get: opt.secure ? {"#": lex["#"]} : lex,
|
|
120
|
+
})
|
|
121
|
+
|
|
115
122
|
if (ack) {
|
|
123
|
+
// Also send request on the wire to check for updates.
|
|
124
|
+
send(request)
|
|
116
125
|
cb({put: ack})
|
|
117
126
|
return
|
|
118
127
|
}
|
|
119
128
|
|
|
120
129
|
store.get(lex, (err, ack) => {
|
|
121
130
|
if (ack) {
|
|
131
|
+
// Also send request on the wire to check for updates.
|
|
132
|
+
send(request)
|
|
122
133
|
cb({put: ack, err: err})
|
|
123
134
|
return
|
|
124
135
|
}
|
|
125
136
|
|
|
126
137
|
if (err) console.log(err)
|
|
127
138
|
|
|
128
|
-
const track = utils.text.random(9)
|
|
129
139
|
queue[track] = cb
|
|
130
|
-
send(
|
|
131
|
-
JSON.stringify({
|
|
132
|
-
"#": dup.track(track),
|
|
133
|
-
get: lex,
|
|
134
|
-
}),
|
|
135
|
-
)
|
|
140
|
+
send(request)
|
|
136
141
|
// Respond to callback with null if no response.
|
|
137
142
|
setTimeout(() => {
|
|
138
143
|
const cb = queue[track]
|
|
@@ -143,14 +148,14 @@ const Wire = opt => {
|
|
|
143
148
|
cb({put: ack})
|
|
144
149
|
delete queue[track]
|
|
145
150
|
}
|
|
146
|
-
},
|
|
151
|
+
}, _opt.wait || 100)
|
|
147
152
|
})
|
|
148
153
|
}
|
|
149
154
|
|
|
150
155
|
const api = send => {
|
|
151
156
|
return {
|
|
152
|
-
get: (lex, cb,
|
|
153
|
-
getWithCallback(lex, cb, send,
|
|
157
|
+
get: (lex, cb, _opt) => {
|
|
158
|
+
getWithCallback(lex, cb, send, _opt)
|
|
154
159
|
},
|
|
155
160
|
put: async (data, cb) => {
|
|
156
161
|
// Deferred updates are only stored using wire spec, they're ignored
|
|
@@ -172,7 +177,7 @@ const Wire = opt => {
|
|
|
172
177
|
}),
|
|
173
178
|
)
|
|
174
179
|
},
|
|
175
|
-
on: (lex, cb) => {
|
|
180
|
+
on: (lex, cb, _get, _opt) => {
|
|
176
181
|
const soul = lex && lex["#"]
|
|
177
182
|
if (!soul || !cb) return
|
|
178
183
|
|
|
@@ -181,6 +186,7 @@ const Wire = opt => {
|
|
|
181
186
|
} else {
|
|
182
187
|
listen[soul] = [{".": lex["."], cb: cb}]
|
|
183
188
|
}
|
|
189
|
+
if (_get) getWithCallback(lex, cb, send, _opt)
|
|
184
190
|
},
|
|
185
191
|
off: (lex, cb) => {
|
|
186
192
|
const soul = lex && lex["#"]
|
package/test/holster.get.test.js
CHANGED
|
@@ -36,8 +36,31 @@ describe("holster.get", () => {
|
|
|
36
36
|
})
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
test("get unknown keys in for loop callbacks null", (t, done) => {
|
|
40
|
+
let count = 0
|
|
41
|
+
for (let i = 0; i < 5; i++) {
|
|
42
|
+
holster.get("unknown" + i, data => {
|
|
43
|
+
assert.equal(data, null)
|
|
44
|
+
count++
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
if (count === 5) done()
|
|
49
|
+
}, 200)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test("nested unknown keys both callbacks null", (t, done) => {
|
|
53
|
+
holster.get("unknown", data => {
|
|
54
|
+
assert.equal(data, null)
|
|
55
|
+
|
|
56
|
+
holster.get("unknown", data => {
|
|
57
|
+
assert.equal(data, null)
|
|
58
|
+
done()
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test("get already called callback null", (t, done) => {
|
|
41
64
|
holster.get("chained").get("unknown", data => {
|
|
42
65
|
assert.equal(data, null)
|
|
43
66
|
done()
|
|
@@ -51,6 +74,17 @@ describe("holster.get", () => {
|
|
|
51
74
|
})
|
|
52
75
|
})
|
|
53
76
|
|
|
77
|
+
test("nested next chained unknown keys callback null", (t, done) => {
|
|
78
|
+
holster.get("chained").next("unknown", data => {
|
|
79
|
+
assert.equal(data, null)
|
|
80
|
+
|
|
81
|
+
holster.get("chained").next("unknown", data => {
|
|
82
|
+
assert.equal(data, null)
|
|
83
|
+
done()
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
54
88
|
test("cleanup", (t, done) => {
|
|
55
89
|
fs.rm("test/holster.get", {recursive: true, force: true}, err => {
|
|
56
90
|
assert.equal(err, null)
|
package/test/holster.on.test.js
CHANGED
|
@@ -37,10 +37,12 @@ describe("holster.on", () => {
|
|
|
37
37
|
done() // This done is not called and test would fail if it was.
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
holster.get("key2").put("value2", err => {
|
|
42
|
+
assert.equal(err, null)
|
|
43
|
+
done()
|
|
44
|
+
})
|
|
45
|
+
}, 100)
|
|
44
46
|
})
|
|
45
47
|
|
|
46
48
|
test("on for property on root two updates - two events", (t, done) => {
|
|
@@ -70,6 +72,45 @@ describe("holster.on", () => {
|
|
|
70
72
|
})
|
|
71
73
|
})
|
|
72
74
|
|
|
75
|
+
test("on for properties on root in for loop", (t, done) => {
|
|
76
|
+
for (let i = 0; i < 5; i++) {
|
|
77
|
+
holster.get("for" + i).put(i, err => {
|
|
78
|
+
assert.equal(err, null)
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Need to wait until after all initial puts are done to set on listeners.
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
for (let i = 0; i < 5; i++) {
|
|
85
|
+
holster.get("for" + i).on(data => {
|
|
86
|
+
assert.equal(data, "update" + i)
|
|
87
|
+
if (i === 4) done()
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
for (let i = 0; i < 5; i++) {
|
|
93
|
+
holster.get("for" + i).put("update" + i, err => {
|
|
94
|
+
assert.equal(err, null)
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
}, 100)
|
|
98
|
+
}, 500)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
test("on with get flag set - data returned", (t, done) => {
|
|
102
|
+
holster.get("key4").put("value4", err => {
|
|
103
|
+
assert.equal(err, null)
|
|
104
|
+
|
|
105
|
+
setTimeout(() => {
|
|
106
|
+
holster.get("key4").on(data => {
|
|
107
|
+
assert.equal(data, "value4")
|
|
108
|
+
done()
|
|
109
|
+
}, true)
|
|
110
|
+
}, 100)
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
|
|
73
114
|
test("chained next before on", (t, done) => {
|
|
74
115
|
// The node needs to exist before it can be listend to for updates.
|
|
75
116
|
holster
|
|
@@ -140,7 +181,7 @@ describe("holster.on", () => {
|
|
|
140
181
|
},
|
|
141
182
|
}
|
|
142
183
|
holster.get("nested").on(data => {
|
|
143
|
-
assert.deepEqual(data, update)
|
|
184
|
+
assert.deepEqual(data, {key: nested.key, ...update})
|
|
144
185
|
})
|
|
145
186
|
|
|
146
187
|
holster
|
package/test/holster.put.test.js
CHANGED
|
@@ -63,6 +63,27 @@ describe("holster.put", () => {
|
|
|
63
63
|
})
|
|
64
64
|
})
|
|
65
65
|
|
|
66
|
+
test("put and get values in for loop on root", (t, done) => {
|
|
67
|
+
for (let i = 0; i < 5; i++) {
|
|
68
|
+
holster.get("for" + i).put(i, err => {
|
|
69
|
+
assert.equal(err, null)
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
setTimeout(() => {
|
|
74
|
+
let count = 0
|
|
75
|
+
for (let i = 0; i < 5; i++) {
|
|
76
|
+
holster.get("for" + i, data => {
|
|
77
|
+
assert.equal(data, i)
|
|
78
|
+
count++
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
if (count === 5) done()
|
|
83
|
+
}, 200)
|
|
84
|
+
}, 200)
|
|
85
|
+
})
|
|
86
|
+
|
|
66
87
|
test("chained get before put", (t, done) => {
|
|
67
88
|
holster
|
|
68
89
|
.get("hello")
|
|
@@ -269,7 +290,7 @@ describe("holster.put", () => {
|
|
|
269
290
|
})
|
|
270
291
|
})
|
|
271
292
|
|
|
272
|
-
test("
|
|
293
|
+
test("put string with set", (t, done) => {
|
|
273
294
|
holster.get("set").put("first", true, err => {
|
|
274
295
|
assert.equal(err, null)
|
|
275
296
|
|
|
@@ -292,7 +313,7 @@ describe("holster.put", () => {
|
|
|
292
313
|
})
|
|
293
314
|
})
|
|
294
315
|
|
|
295
|
-
test("
|
|
316
|
+
test("put object with set", (t, done) => {
|
|
296
317
|
const set1 = {
|
|
297
318
|
key: "value 1",
|
|
298
319
|
child: "child value 1",
|
|
@@ -43,14 +43,6 @@ describe("holster.secure", () => {
|
|
|
43
43
|
})
|
|
44
44
|
})
|
|
45
45
|
|
|
46
|
-
// Chaining get creates a new context for each call.
|
|
47
|
-
test("get chained unknown keys callback null", (t, done) => {
|
|
48
|
-
holster.get("chained").get("unknown", data => {
|
|
49
|
-
assert.equal(data, null)
|
|
50
|
-
done()
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
|
|
54
46
|
test("next chained unknown keys callback null", (t, done) => {
|
|
55
47
|
holster.get("chained").next("unknown", data => {
|
|
56
48
|
assert.equal(data, null)
|
|
@@ -102,7 +94,7 @@ describe("holster.secure", () => {
|
|
|
102
94
|
})
|
|
103
95
|
})
|
|
104
96
|
|
|
105
|
-
test("put and get string", (t, done) => {
|
|
97
|
+
test("user put and get string", (t, done) => {
|
|
106
98
|
user.get("key").put("value", err => {
|
|
107
99
|
assert.equal(err, null)
|
|
108
100
|
|
|
@@ -62,11 +62,27 @@ describe("holster.user.get", () => {
|
|
|
62
62
|
})
|
|
63
63
|
})
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
test("get unknown keys in for loop callbacks null", (t, done) => {
|
|
66
|
+
let count = 0
|
|
67
|
+
for (let i = 0; i < 5; i++) {
|
|
68
|
+
user.get("unknown" + i, data => {
|
|
69
|
+
assert.equal(data, null)
|
|
70
|
+
count++
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
setTimeout(() => {
|
|
74
|
+
if (count === 5) done()
|
|
75
|
+
}, 200)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test("nested get unknown key callback null", (t, done) => {
|
|
79
|
+
user.get("unknown", data => {
|
|
68
80
|
assert.equal(data, null)
|
|
69
|
-
|
|
81
|
+
|
|
82
|
+
user.get("unknown", data => {
|
|
83
|
+
assert.equal(data, null)
|
|
84
|
+
done()
|
|
85
|
+
})
|
|
70
86
|
})
|
|
71
87
|
})
|
|
72
88
|
|
|
@@ -77,6 +93,17 @@ describe("holster.user.get", () => {
|
|
|
77
93
|
})
|
|
78
94
|
})
|
|
79
95
|
|
|
96
|
+
test("nested next chained unknown keys callback null", (t, done) => {
|
|
97
|
+
user.get("chained").next("unknown", data => {
|
|
98
|
+
assert.equal(data, null)
|
|
99
|
+
|
|
100
|
+
user.get("chained").next("unknown", data => {
|
|
101
|
+
assert.equal(data, null)
|
|
102
|
+
done()
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
80
107
|
test("cleanup", (t, done) => {
|
|
81
108
|
fs.rm("test/holster.user.get", {recursive: true, force: true}, err => {
|
|
82
109
|
assert.equal(err, null)
|
|
@@ -12,7 +12,6 @@ describe("holster.user.lex", () => {
|
|
|
12
12
|
maxAge: 100,
|
|
13
13
|
})
|
|
14
14
|
const user = holster.user()
|
|
15
|
-
let alice = ""
|
|
16
15
|
|
|
17
16
|
test("user create", (t, done) => {
|
|
18
17
|
user.create("alice", "password", err => {
|
|
@@ -25,7 +24,6 @@ describe("holster.user.lex", () => {
|
|
|
25
24
|
user.auth("alice", "password", err => {
|
|
26
25
|
assert.equal(err, null)
|
|
27
26
|
assert.equal(user.is.username, "alice")
|
|
28
|
-
alice = user.is.pub
|
|
29
27
|
done()
|
|
30
28
|
})
|
|
31
29
|
})
|
|
@@ -84,6 +82,7 @@ describe("holster.user.lex", () => {
|
|
|
84
82
|
other: "other child value",
|
|
85
83
|
},
|
|
86
84
|
}
|
|
85
|
+
|
|
87
86
|
user.get("nested").put(nested, err => {
|
|
88
87
|
assert.equal(err, null)
|
|
89
88
|
|
|
@@ -123,6 +122,7 @@ describe("holster.user.lex", () => {
|
|
|
123
122
|
has: "child update",
|
|
124
123
|
},
|
|
125
124
|
}
|
|
125
|
+
|
|
126
126
|
user
|
|
127
127
|
.get("on-nested")
|
|
128
128
|
.next("child")
|
|
@@ -69,6 +69,7 @@ describe("holster.user.on", () => {
|
|
|
69
69
|
assert.equal(data, "update1")
|
|
70
70
|
} else {
|
|
71
71
|
assert.equal(data, "update2")
|
|
72
|
+
user.get("key3").off()
|
|
72
73
|
done()
|
|
73
74
|
}
|
|
74
75
|
})
|
|
@@ -86,6 +87,58 @@ describe("holster.user.on", () => {
|
|
|
86
87
|
})
|
|
87
88
|
})
|
|
88
89
|
|
|
90
|
+
test("on for properties in for loop", (t, done) => {
|
|
91
|
+
;(async () => {
|
|
92
|
+
for (let i = 0; i < 5; i++) {
|
|
93
|
+
// Need to be careful putting user properties in a loop as they are
|
|
94
|
+
// verified per node, so wait for each update to return.
|
|
95
|
+
const err = await new Promise(res => {
|
|
96
|
+
user.get("for" + i).put(i, res)
|
|
97
|
+
})
|
|
98
|
+
assert.equal(err, null)
|
|
99
|
+
}
|
|
100
|
+
})()
|
|
101
|
+
|
|
102
|
+
// Need to wait until after all initial puts are done to set on listeners.
|
|
103
|
+
setTimeout(async () => {
|
|
104
|
+
let count = 0
|
|
105
|
+
for (let i = 0; i < 5; i++) {
|
|
106
|
+
user.get("for" + i).on(data => {
|
|
107
|
+
assert.equal(data, "update" + i)
|
|
108
|
+
user.get("for" + i).off()
|
|
109
|
+
count++
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
setTimeout(async () => {
|
|
114
|
+
for (let i = 0; i < 5; i++) {
|
|
115
|
+
// Same as above put, wait for each update to return.
|
|
116
|
+
const err = await new Promise(res => {
|
|
117
|
+
user.get("for" + i).put("update" + i, res)
|
|
118
|
+
})
|
|
119
|
+
assert.equal(err, null)
|
|
120
|
+
}
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
if (count === 5) done()
|
|
123
|
+
}, 500)
|
|
124
|
+
}, 500)
|
|
125
|
+
}, 1000)
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
test("on with get flag set - data returned", (t, done) => {
|
|
129
|
+
user.get("key4").put("value4", err => {
|
|
130
|
+
assert.equal(err, null)
|
|
131
|
+
|
|
132
|
+
setTimeout(() => {
|
|
133
|
+
user.get("key4").on(data => {
|
|
134
|
+
assert.equal(data, "value4")
|
|
135
|
+
user.get("key4").off()
|
|
136
|
+
done()
|
|
137
|
+
}, true)
|
|
138
|
+
}, 100)
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
|
|
89
142
|
test("chained next before on", (t, done) => {
|
|
90
143
|
// The node needs to exist before it can be listend to for updates.
|
|
91
144
|
user
|
|
@@ -119,6 +172,7 @@ describe("holster.user.on", () => {
|
|
|
119
172
|
key: "plain value",
|
|
120
173
|
number: 42,
|
|
121
174
|
}
|
|
175
|
+
|
|
122
176
|
user.get("plain").put(plain, err => {
|
|
123
177
|
assert.equal(err, null)
|
|
124
178
|
|
|
@@ -126,6 +180,7 @@ describe("holster.user.on", () => {
|
|
|
126
180
|
key: "update",
|
|
127
181
|
number: 42,
|
|
128
182
|
}
|
|
183
|
+
|
|
129
184
|
user.get("plain").on(data => {
|
|
130
185
|
assert.deepEqual(data, update)
|
|
131
186
|
done()
|
|
@@ -156,6 +211,7 @@ describe("holster.user.on", () => {
|
|
|
156
211
|
has: "child update",
|
|
157
212
|
},
|
|
158
213
|
}
|
|
214
|
+
|
|
159
215
|
user.get("nested").on(data => {
|
|
160
216
|
assert.deepEqual(data, update)
|
|
161
217
|
})
|
|
@@ -177,9 +233,11 @@ describe("holster.user.on", () => {
|
|
|
177
233
|
})
|
|
178
234
|
|
|
179
235
|
test("cleanup", (t, done) => {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
236
|
+
setTimeout(() => {
|
|
237
|
+
fs.rm("test/holster.user.on", {recursive: true, force: true}, err => {
|
|
238
|
+
assert.equal(err, null)
|
|
239
|
+
done()
|
|
240
|
+
})
|
|
241
|
+
}, 100)
|
|
184
242
|
})
|
|
185
243
|
})
|