@mblaney/holster 0.1.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.
Files changed (46) hide show
  1. package/.github/workflows/node.js.yml +31 -0
  2. package/LICENSE.md +55 -0
  3. package/README.md +24 -0
  4. package/build/holster.js +4 -0
  5. package/build/holster.js.map +7 -0
  6. package/examples/index.html +33 -0
  7. package/examples/index.js +49 -0
  8. package/examples/user.html +31 -0
  9. package/examples/user.js +88 -0
  10. package/examples/wire.html +27 -0
  11. package/examples/wire.js +55 -0
  12. package/package.json +44 -0
  13. package/src/array.js +34 -0
  14. package/src/buffer.js +83 -0
  15. package/src/dup.js +23 -0
  16. package/src/get.js +19 -0
  17. package/src/ham.js +151 -0
  18. package/src/holster.js +502 -0
  19. package/src/index.js +21 -0
  20. package/src/radisk.js +438 -0
  21. package/src/radix.js +106 -0
  22. package/src/sea-utils.js +65 -0
  23. package/src/sea.js +224 -0
  24. package/src/store.js +225 -0
  25. package/src/user.js +330 -0
  26. package/src/utils.js +124 -0
  27. package/src/wire.js +290 -0
  28. package/test/holster.get.test.js +60 -0
  29. package/test/holster.lex.test.js +196 -0
  30. package/test/holster.off.test.js +53 -0
  31. package/test/holster.on.test.js +168 -0
  32. package/test/holster.put.test.js +278 -0
  33. package/test/holster.secure.test.js +210 -0
  34. package/test/holster.user.get.test.js +86 -0
  35. package/test/holster.user.lex.test.js +148 -0
  36. package/test/holster.user.off.test.js +72 -0
  37. package/test/holster.user.on.test.js +185 -0
  38. package/test/holster.user.put.test.js +381 -0
  39. package/test/kitty/! +9 -0
  40. package/test/names.js +225 -0
  41. package/test/radisk.test.js +191 -0
  42. package/test/radix.test.js +117 -0
  43. package/test/sea.test.js +284 -0
  44. package/test/store.test.js +316 -0
  45. package/test/user.test.js +173 -0
  46. package/test/wire.test.js +159 -0
@@ -0,0 +1,168 @@
1
+ import fs from "fs"
2
+ import {Server} from "mock-socket"
3
+ import {describe, test} from "node:test"
4
+ import assert from "node:assert/strict"
5
+ import Holster from "../src/holster.js"
6
+
7
+ describe("holster.on", () => {
8
+ const wss = new Server("ws://localhost:1234")
9
+ const holster = Holster({file: "test/holster.on", wss: wss, maxAge: 100})
10
+
11
+ test("calling on without get callback null", (t, done) => {
12
+ holster.on(data => {
13
+ assert.equal(data, null)
14
+ done()
15
+ })
16
+ })
17
+
18
+ test("on for property on root then update - event", (t, done) => {
19
+ // The property needs to exist before it can be listend to for updates.
20
+ holster.get("key").put("value", err => {
21
+ assert.equal(err, null)
22
+
23
+ holster.get("key").on(data => {
24
+ assert.equal(data, "update")
25
+ done()
26
+ })
27
+
28
+ holster.get("key").put("update", err => {
29
+ assert.equal(err, null)
30
+ })
31
+ })
32
+ })
33
+
34
+ test("on for different property on root - no event", (t, done) => {
35
+ holster.get("key1").on(data => {
36
+ console.log("should not be called for key1:", data)
37
+ done() // This done is not called and test would fail if it was.
38
+ })
39
+
40
+ holster.get("key2").put("value2", err => {
41
+ assert.equal(err, null)
42
+ done()
43
+ })
44
+ })
45
+
46
+ test("on for property on root two updates - two events", (t, done) => {
47
+ holster.get("key3").put("value3", err => {
48
+ assert.equal(err, null)
49
+
50
+ let first = true
51
+ holster.get("key3").on(data => {
52
+ if (first) {
53
+ assert.equal(data, "update1")
54
+ } else {
55
+ assert.equal(data, "update2")
56
+ done()
57
+ }
58
+ })
59
+
60
+ holster.get("key3").put("update1", err => {
61
+ assert.equal(err, null)
62
+ })
63
+
64
+ setTimeout(() => {
65
+ first = false
66
+ holster.get("key3").put("update2", err => {
67
+ assert.equal(err, null)
68
+ })
69
+ }, 200)
70
+ })
71
+ })
72
+
73
+ test("chained next before on", (t, done) => {
74
+ // The node needs to exist before it can be listend to for updates.
75
+ holster
76
+ .get("hello")
77
+ .next("world!")
78
+ .put("ok", err => {
79
+ assert.equal(err, null)
80
+
81
+ holster
82
+ .get("hello")
83
+ .next("world!")
84
+ .on(data => {
85
+ assert.equal(data, "update")
86
+ holster.get("hello").next("world!").off()
87
+ done()
88
+ })
89
+
90
+ setTimeout(() => {
91
+ holster
92
+ .get("hello")
93
+ .next("world!")
94
+ .put("update", err => {
95
+ assert.equal(err, null)
96
+ })
97
+ }, 10)
98
+ })
99
+ })
100
+
101
+ test("on and put object on root in graph format", (t, done) => {
102
+ const plain = {
103
+ key: "plain value",
104
+ number: 42,
105
+ }
106
+ holster.get("plain").put(plain, err => {
107
+ assert.equal(err, null)
108
+
109
+ const update = {
110
+ key: "update",
111
+ number: 42,
112
+ }
113
+ holster.get("plain").on(data => {
114
+ assert.deepEqual(data, update)
115
+ done()
116
+ })
117
+
118
+ setTimeout(() => {
119
+ holster.get("plain").put(update, err => {
120
+ assert.equal(err, null)
121
+ })
122
+ }, 10)
123
+ })
124
+ })
125
+
126
+ test("on and put nested object", (t, done) => {
127
+ const nested = {
128
+ key: "nested key",
129
+ child: {
130
+ has: "child key",
131
+ },
132
+ }
133
+ // The node needs to exist before it can be listend to for updates.
134
+ holster.get("nested").put(nested, err => {
135
+ assert.equal(err, null)
136
+
137
+ const update = {
138
+ child: {
139
+ has: "child update",
140
+ },
141
+ }
142
+ holster.get("nested").on(data => {
143
+ assert.deepEqual(data, update)
144
+ })
145
+
146
+ holster
147
+ .get("nested")
148
+ .next("child")
149
+ .on(data => {
150
+ assert.deepEqual(data, update.child)
151
+ done()
152
+ })
153
+
154
+ setTimeout(() => {
155
+ holster.get("nested").put(update, err => {
156
+ assert.equal(err, null)
157
+ })
158
+ }, 10)
159
+ })
160
+ })
161
+
162
+ test("cleanup", (t, done) => {
163
+ fs.rm("test/holster.on", {recursive: true, force: true}, err => {
164
+ assert.equal(err, null)
165
+ done()
166
+ })
167
+ })
168
+ })
@@ -0,0 +1,278 @@
1
+ import fs from "fs"
2
+ import {Server} from "mock-socket"
3
+ import {describe, test} from "node:test"
4
+ import assert from "node:assert/strict"
5
+ import Holster from "../src/holster.js"
6
+
7
+ describe("holster.put", () => {
8
+ const wss = new Server("ws://localhost:1234")
9
+ const holster = Holster({file: "test/holster.put", wss: wss, maxAge: 100})
10
+
11
+ test("put and get string on root", (t, done) => {
12
+ holster.get("key").put("value", err => {
13
+ assert.equal(err, null)
14
+
15
+ holster.get("key", data => {
16
+ assert.equal(data, "value")
17
+ done()
18
+ })
19
+ })
20
+ })
21
+
22
+ test("put value to null on root", (t, done) => {
23
+ holster.get("key").put(null, err => {
24
+ assert.equal(err, null)
25
+
26
+ holster.get("key", data => {
27
+ assert.equal(data, null)
28
+ done()
29
+ })
30
+ })
31
+ })
32
+
33
+ test("put and get true on root", (t, done) => {
34
+ holster.get("true").put(true, err => {
35
+ assert.equal(err, null)
36
+
37
+ holster.get("true", data => {
38
+ assert.equal(data, true)
39
+ done()
40
+ })
41
+ })
42
+ })
43
+
44
+ test("put and get false on root", (t, done) => {
45
+ holster.get("false").put(false, err => {
46
+ assert.equal(err, null)
47
+
48
+ holster.get("false", data => {
49
+ assert.equal(data, false)
50
+ done()
51
+ })
52
+ })
53
+ })
54
+
55
+ test("put and get number on root", (t, done) => {
56
+ holster.get("pi").put(3.14159, err => {
57
+ assert.equal(err, null)
58
+
59
+ holster.get("pi", data => {
60
+ assert.equal(data, 3.14159)
61
+ done()
62
+ })
63
+ })
64
+ })
65
+
66
+ test("chained get before put", (t, done) => {
67
+ holster
68
+ .get("hello")
69
+ .next("world!")
70
+ .put("ok", err => {
71
+ assert.equal(err, null)
72
+
73
+ holster.get("hello").next("world!", data => {
74
+ assert.equal(data, "ok")
75
+ done()
76
+ })
77
+ })
78
+ })
79
+
80
+ test("more chained gets before put", (t, done) => {
81
+ holster
82
+ .get("1")
83
+ .next("2")
84
+ .next("3")
85
+ .put("4", err => {
86
+ assert.equal(err, null)
87
+
88
+ holster
89
+ .get("1")
90
+ .next("2")
91
+ .next("3", data => {
92
+ assert.equal(data, "4")
93
+ done()
94
+ })
95
+ })
96
+ })
97
+
98
+ test("put and get object on root in graph format", (t, done) => {
99
+ const plain = {
100
+ key: "plain value",
101
+ true: true,
102
+ false: false,
103
+ number: 42,
104
+ }
105
+ holster.get("plain").put(plain, err => {
106
+ assert.equal(err, null)
107
+
108
+ holster.get("plain", data => {
109
+ assert.deepEqual(data, plain)
110
+ done()
111
+ })
112
+ })
113
+ })
114
+
115
+ test("put object to null on root", (t, done) => {
116
+ holster.get("plain").put(null, err => {
117
+ assert.equal(err, null)
118
+
119
+ holster.get("plain", data => {
120
+ assert.equal(data, null)
121
+ done()
122
+ })
123
+ })
124
+ })
125
+
126
+ test("chained get before put object in graph format", (t, done) => {
127
+ const plain = {
128
+ key: "hello plain value",
129
+ }
130
+ holster
131
+ .get("hello")
132
+ .next("plain")
133
+ .put(plain, err => {
134
+ assert.equal(err, null)
135
+
136
+ holster.get("hello").next("plain", data => {
137
+ assert.deepEqual(data, plain)
138
+ done()
139
+ })
140
+ })
141
+ })
142
+
143
+ test("put and get nested object", (t, done) => {
144
+ const nested = {
145
+ key: "nested value",
146
+ child: {
147
+ has: "child value",
148
+ },
149
+ }
150
+ holster.get("nested").put(nested, err => {
151
+ assert.equal(err, null)
152
+
153
+ // Getting a nested object requires waiting for radisk to write to disk,
154
+ // as it will batch the writes. (Default wait is 1 millisecond.)
155
+ setTimeout(() => {
156
+ holster.get("nested", data => {
157
+ assert.deepEqual(data, nested)
158
+
159
+ holster.get("nested").next("key", data => {
160
+ assert.equal(data, "nested value")
161
+
162
+ holster.get("nested").next("child", data => {
163
+ assert.deepEqual(data, {has: "child value"})
164
+ done()
165
+ })
166
+ })
167
+ })
168
+ }, 2)
169
+ })
170
+ })
171
+
172
+ test("chained get before put nested object", (t, done) => {
173
+ const nested = {
174
+ key: "hello nested value",
175
+ child: {
176
+ has: "hello child value",
177
+ },
178
+ }
179
+ holster
180
+ .get("hello")
181
+ .next("nested")
182
+ .put(nested, err => {
183
+ assert.equal(err, null)
184
+
185
+ setTimeout(() => {
186
+ holster.get("hello").next("nested", data => {
187
+ assert.deepEqual(data, nested)
188
+
189
+ holster
190
+ .get("hello")
191
+ .next("nested")
192
+ .next("key", data => {
193
+ assert.equal(data, "hello nested value")
194
+
195
+ holster
196
+ .get("hello")
197
+ .next("nested")
198
+ .next("child", data => {
199
+ assert.deepEqual(data, {has: "hello child value"})
200
+ done()
201
+ })
202
+ })
203
+ })
204
+ }, 2)
205
+ })
206
+ })
207
+
208
+ test("put and get two nested objects", (t, done) => {
209
+ const two = {
210
+ key: "two nested values",
211
+ child1: {
212
+ has: "child value 1",
213
+ },
214
+ child2: {
215
+ has: "child value 2",
216
+ },
217
+ }
218
+ holster.get("two").put(two, err => {
219
+ assert.equal(err, null)
220
+
221
+ setTimeout(() => {
222
+ holster.get("two", data => {
223
+ assert.deepEqual(data, two)
224
+
225
+ holster.get("two").next("child1", data => {
226
+ assert.deepEqual(data, {has: "child value 1"})
227
+
228
+ holster.get("two").next("child2", data => {
229
+ assert.deepEqual(data, {has: "child value 2"})
230
+ done()
231
+ })
232
+ })
233
+ })
234
+ }, 2)
235
+ })
236
+ })
237
+
238
+ test("put and get multiple nested object", (t, done) => {
239
+ const multiple = {
240
+ key: "multiple nested values",
241
+ child: {
242
+ has: "child value",
243
+ grandchild: {
244
+ has: "grandchild value",
245
+ other: "(not returned in lex query)",
246
+ },
247
+ },
248
+ }
249
+ holster.get("multiple").put(multiple, err => {
250
+ assert.equal(err, null)
251
+
252
+ setTimeout(() => {
253
+ holster.get("multiple", data => {
254
+ assert.deepEqual(data, multiple)
255
+
256
+ holster.get("multiple").next("child", {".": "has"}, data => {
257
+ assert.deepEqual(data, {has: "child value"})
258
+
259
+ holster
260
+ .get("multiple")
261
+ .next("child")
262
+ .next("grandchild", {".": "has"}, data => {
263
+ assert.deepEqual(data, {has: "grandchild value"})
264
+ done()
265
+ })
266
+ })
267
+ })
268
+ }, 2)
269
+ })
270
+ })
271
+
272
+ test("cleanup", (t, done) => {
273
+ fs.rm("test/holster.put", {recursive: true, force: true}, err => {
274
+ assert.equal(err, null)
275
+ done()
276
+ })
277
+ })
278
+ })
@@ -0,0 +1,210 @@
1
+ import fs from "fs"
2
+ import {Server} from "mock-socket"
3
+ import {describe, test} from "node:test"
4
+ import assert from "node:assert/strict"
5
+ import Holster from "../src/holster.js"
6
+
7
+ describe("holster.secure", () => {
8
+ const wss = new Server("ws://localhost:1234")
9
+ const holster = Holster({
10
+ file: "test/holster.secure",
11
+ wss: wss,
12
+ maxAge: 100,
13
+ secure: true,
14
+ })
15
+ const user = holster.user()
16
+ const expect = "error putting data on root: user required in secure mode"
17
+
18
+ test("empty key callback null", (t, done) => {
19
+ holster.get("", data => {
20
+ assert.equal(data, null)
21
+ done()
22
+ })
23
+ })
24
+
25
+ test("null key callback null", (t, done) => {
26
+ holster.get(null, data => {
27
+ assert.equal(data, null)
28
+ done()
29
+ })
30
+ })
31
+
32
+ test("underscore as key callback null", (t, done) => {
33
+ holster.get("_", data => {
34
+ assert.equal(data, null)
35
+ done()
36
+ })
37
+ })
38
+
39
+ test("get unknown key callback null", (t, done) => {
40
+ holster.get("unknown", data => {
41
+ assert.equal(data, null)
42
+ done()
43
+ })
44
+ })
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
+ test("next chained unknown keys callback null", (t, done) => {
55
+ holster.get("chained").next("unknown", data => {
56
+ assert.equal(data, null)
57
+ done()
58
+ })
59
+ })
60
+
61
+ test("put string on root error", (t, done) => {
62
+ holster.get("key").put("value", err => {
63
+ assert.equal(err, expect)
64
+ done()
65
+ })
66
+ })
67
+
68
+ test("chained get before put", (t, done) => {
69
+ holster
70
+ .get("hello")
71
+ .next("world!")
72
+ .put("ok", err => {
73
+ assert.equal(err, expect)
74
+ done()
75
+ })
76
+ })
77
+
78
+ test("chained get before put object in graph format", (t, done) => {
79
+ const plain = {
80
+ key: "hello plain value",
81
+ }
82
+ holster
83
+ .get("hello")
84
+ .next("plain")
85
+ .put(plain, err => {
86
+ assert.equal(err, expect)
87
+ done()
88
+ })
89
+ })
90
+
91
+ test("user create", (t, done) => {
92
+ user.create("alice", "password", err => {
93
+ assert.equal(err, null)
94
+ done()
95
+ })
96
+ })
97
+
98
+ test("user auth", (t, done) => {
99
+ user.auth("alice", "password", err => {
100
+ assert.equal(err, null)
101
+ done()
102
+ })
103
+ })
104
+
105
+ test("put and get string", (t, done) => {
106
+ user.get("key").put("value", err => {
107
+ assert.equal(err, null)
108
+
109
+ user.get("key", data => {
110
+ assert.equal(data, "value")
111
+ done()
112
+ })
113
+ })
114
+ })
115
+
116
+ test("user chained get before put", (t, done) => {
117
+ user
118
+ .get("hello")
119
+ .next("world!")
120
+ .put("ok", err => {
121
+ assert.equal(err, null)
122
+
123
+ user.get("hello").next("world!", data => {
124
+ assert.equal(data, "ok")
125
+ done()
126
+ })
127
+ })
128
+ })
129
+
130
+ test("user put and get object in graph format", (t, done) => {
131
+ const plain = {
132
+ key: "plain value",
133
+ true: true,
134
+ false: false,
135
+ number: 42,
136
+ }
137
+ user.get("plain").put(plain, err => {
138
+ assert.equal(err, null)
139
+
140
+ user.get("plain", data => {
141
+ assert.deepEqual(data, plain)
142
+ done()
143
+ })
144
+ })
145
+ })
146
+
147
+ test("user put object to null", (t, done) => {
148
+ user.get("plain").put(null, err => {
149
+ assert.equal(err, null)
150
+
151
+ user.get("plain", data => {
152
+ assert.equal(data, null)
153
+ done()
154
+ })
155
+ })
156
+ })
157
+
158
+ test("user chained get before put object in graph format", (t, done) => {
159
+ const plain = {
160
+ key: "hello plain value",
161
+ }
162
+ user
163
+ .get("hello")
164
+ .next("plain")
165
+ .put(plain, err => {
166
+ assert.equal(err, null)
167
+
168
+ user.get("hello").next("plain", data => {
169
+ assert.deepEqual(data, plain)
170
+ done()
171
+ })
172
+ })
173
+ })
174
+
175
+ test("user put and get nested object", (t, done) => {
176
+ const nested = {
177
+ key: "nested value",
178
+ child: {
179
+ has: "child value",
180
+ },
181
+ }
182
+ user.get("nested").put(nested, err => {
183
+ assert.equal(err, null)
184
+
185
+ // Getting a nested object requires waiting for radisk to write to disk,
186
+ // as it will batch the writes. (Default wait is 1 millisecond.)
187
+ setTimeout(() => {
188
+ user.get("nested", data => {
189
+ assert.deepEqual(data, nested)
190
+
191
+ user.get("nested").next("key", data => {
192
+ assert.equal(data, "nested value")
193
+
194
+ user.get("nested").next("child", data => {
195
+ assert.deepEqual(data, {has: "child value"})
196
+ done()
197
+ })
198
+ })
199
+ })
200
+ }, 2)
201
+ })
202
+ })
203
+
204
+ test("cleanup", (t, done) => {
205
+ fs.rm("test/holster.secure", {recursive: true, force: true}, err => {
206
+ assert.equal(err, null)
207
+ done()
208
+ })
209
+ })
210
+ })