@mblaney/holster 1.0.4 → 1.0.6

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": "@mblaney/holster",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Holster is a service that allows synchronising data between devices using Node, Deno, Bun or the browser.",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/src/holster.js CHANGED
@@ -70,7 +70,7 @@ const Holster = opt => {
70
70
  const data = await new Promise(res => {
71
71
  const _ctxid = utils.text.random()
72
72
  allctx.set(_ctxid, {chain: [{item: null, soul: id}]})
73
- api(_ctxid).next(null, res)
73
+ api(_ctxid).next(null, res, _opt)
74
74
  })
75
75
  msg.put[soul][key] = data
76
76
  }
@@ -145,39 +145,65 @@ const Holster = opt => {
145
145
  // whole node for verification.
146
146
  const lex =
147
147
  ctx.user || opt.secure ? {"#": soul} : {"#": soul, ".": item}
148
- wire.get(lex, async msg => {
149
- if (msg.err) {
150
- if (ctx.user || opt.secure) {
151
- console.log(`error getting ${soul}: ${msg.err}`)
152
- } else {
153
- console.log(`error getting ${item} on ${soul}: ${msg.err}`)
148
+ wire.get(
149
+ lex,
150
+ async msg => {
151
+ if (msg.err) {
152
+ if (ctx.user || opt.secure) {
153
+ console.log(`error getting ${soul}: ${msg.err}`)
154
+ } else {
155
+ console.log(`error getting ${item} on ${soul}: ${msg.err}`)
156
+ }
157
+ if (cb) cb(null)
158
+ return
154
159
  }
155
- if (cb) cb(null)
156
- return
157
- }
158
160
 
159
- let node = msg.put && msg.put[soul]
160
- if (node && typeof node[item] !== "undefined") {
161
- let id = utils.rel.is(node[item])
162
- if (id) {
163
- ctx.chain[i].soul = id
164
- allctx.set(ctxid, {...ctx})
165
- // Call api again using the updated context.
166
- if (get) {
167
- api(ctxid).next(null, request.get, cb, request._opt)
161
+ let node = msg.put && msg.put[soul]
162
+ if (node && typeof node[item] !== "undefined") {
163
+ let id = utils.rel.is(node[item])
164
+ if (id) {
165
+ ctx.chain[i].soul = id
166
+ allctx.set(ctxid, {...ctx})
167
+ // Call api again using the updated context.
168
+ if (get) {
169
+ api(ctxid).next(null, request.get, cb, request._opt)
170
+ } else if (put) {
171
+ api(ctxid).put(request.put, cb)
172
+ } else if (on) {
173
+ api(ctxid).on(request.on, cb, request._get, request._opt)
174
+ } else if (off) {
175
+ api(ctxid).off(cb)
176
+ }
177
+ } else if (get) {
178
+ // Request was not for a node, return property on current soul.
179
+ cb(node[item])
168
180
  } else if (put) {
169
- api(ctxid).put(request.put, cb)
181
+ // Request was chained before put, so rel doesn't exist yet.
182
+ id = utils.text.random()
183
+ node[item] = utils.rel.ify(id)
184
+ const g = await graph(soul, node, ctx.user, cb)
185
+ if (g === null) return
186
+
187
+ wire.put(g, err => {
188
+ if (err) {
189
+ cb(`error putting ${item} on ${soul}: ${err}`)
190
+ return
191
+ }
192
+
193
+ ctx.chain[i].soul = id
194
+ api(ctxid).put(request.put, cb)
195
+ })
170
196
  } else if (on) {
171
- api(ctxid).on(request.on, cb, request._get, request._opt)
197
+ // Allow listening to a node that doesn't exist.
198
+ cb(null)
172
199
  } else if (off) {
173
- api(ctxid).off(cb)
200
+ // Allow stop listening to a node that doesn't exist.
201
+ if (cb) cb(null)
174
202
  }
175
- } else if (get) {
176
- // Request was not for a node, return property on current soul.
177
- cb(node[item])
178
203
  } else if (put) {
179
204
  // Request was chained before put, so rel doesn't exist yet.
180
- id = utils.text.random()
205
+ const id = utils.text.random()
206
+ if (!node) node = {}
181
207
  node[item] = utils.rel.ify(id)
182
208
  const g = await graph(soul, node, ctx.user, cb)
183
209
  if (g === null) return
@@ -191,35 +217,13 @@ const Holster = opt => {
191
217
  ctx.chain[i].soul = id
192
218
  api(ctxid).put(request.put, cb)
193
219
  })
194
- } else if (on) {
195
- // Allow listening to a node that doesn't exist.
196
- cb(null)
197
- } else if (off) {
198
- // Allow stop listening to a node that doesn't exist.
220
+ } else {
221
+ // Allow querying a node that doesn't exist.
199
222
  if (cb) cb(null)
200
223
  }
201
- } else if (put) {
202
- // Request was chained before put, so rel doesn't exist yet.
203
- const id = utils.text.random()
204
- if (!node) node = {}
205
- node[item] = utils.rel.ify(id)
206
- const g = await graph(soul, node, ctx.user, cb)
207
- if (g === null) return
208
-
209
- wire.put(g, err => {
210
- if (err) {
211
- cb(`error putting ${item} on ${soul}: ${err}`)
212
- return
213
- }
214
-
215
- ctx.chain[i].soul = id
216
- api(ctxid).put(request.put, cb)
217
- })
218
- } else {
219
- // Allow querying a node that doesn't exist.
220
- if (cb) cb(null)
221
- }
222
- })
224
+ },
225
+ request._opt,
226
+ )
223
227
  // Callback has been passed to next soul lookup or called above, so
224
228
  // return false as the calling code should not continue.
225
229
  return false
@@ -543,25 +547,29 @@ const Holster = opt => {
543
547
  allctx.set(ctxid, {chain: [{item: item, soul: soul}], on: true})
544
548
  // Map the user's callback because it can also be passed to off,
545
549
  // so need a reference to it to compare them.
546
- map.set(cb, () => api(ctxid).next(null, cb))
550
+ map.set(cb, () => api(ctxid).next(null, cb, _opt))
547
551
  // Check if item is a rel and add event listener for the node.
548
- wire.get({"#": soul, ".": item}, msg => {
549
- if (msg.err) {
550
- console.log(`error getting ${soul}.${item}: ${msg.err}`)
551
- return
552
- }
552
+ wire.get(
553
+ {"#": soul, ".": item},
554
+ msg => {
555
+ if (msg.err) {
556
+ console.log(`error getting ${soul}.${item}: ${msg.err}`)
557
+ return
558
+ }
553
559
 
554
- const current = msg.put && msg.put[soul] && msg.put[soul][item]
555
- const id = utils.rel.is(current)
556
- if (id) {
557
- if (lex) lex = utils.obj.put(lex, "#", id)
558
- else lex = {"#": id, ".": null}
559
- } else {
560
- if (lex) lex = utils.obj.put(lex, "#", soul)
561
- else lex = {"#": soul, ".": item}
562
- }
563
- wire.on(lex, map.get(cb), _get, _opt)
564
- })
560
+ const current = msg.put && msg.put[soul] && msg.put[soul][item]
561
+ const id = utils.rel.is(current)
562
+ if (id) {
563
+ if (lex) lex = utils.obj.put(lex, "#", id)
564
+ else lex = {"#": id, ".": null}
565
+ } else {
566
+ if (lex) lex = utils.obj.put(lex, "#", soul)
567
+ else lex = {"#": soul, ".": item}
568
+ }
569
+ wire.on(lex, map.get(cb), _get, _opt)
570
+ },
571
+ _opt,
572
+ )
565
573
  },
566
574
  off: cb => {
567
575
  if (!ctxid) {
package/src/radisk.js CHANGED
@@ -119,7 +119,6 @@ const Radisk = opt => {
119
119
  // 4. Read the previous file into memory
120
120
  // 5. Scan through in memory radix for all values lexically less than limit
121
121
  // 6. Merge and write all of those to the in-memory file and back to disk
122
- // 7. If file is to large then split. More details needed here
123
122
  radisk.save = (rad, cb) => {
124
123
  const save = {
125
124
  find: (tree, key) => {
@@ -176,70 +175,47 @@ const Radisk = opt => {
176
175
  cache = null
177
176
  const write = {
178
177
  text: "",
178
+ limit: "",
179
+ done: false,
179
180
  count: 0,
180
- file: file,
181
181
  each: (value, key, k, pre) => {
182
+ // each is called for all keys, but stop adding to write.text when
183
+ // write.slice is called, then the current contents of write.text
184
+ // will be written to file.
185
+ if (write.done) return
186
+
182
187
  write.count++
183
- var enc =
184
- Radisk.encode(pre.length) +
185
- "#" +
186
- Radisk.encode(k) +
187
- (typeof value === "undefined" ? "" : "=" + Radisk.encode(value)) +
188
- "\n"
188
+ value = typeof value === "undefined" ? "" : "=" + Radisk.encode(value)
189
+ const enc =
190
+ Radisk.encode(pre.length) + "#" + Radisk.encode(k) + value + "\n"
189
191
  // Cannot split the file if only have one entry to write. Also don't
190
192
  // start a split if in the middle of writing a node (pre > 0).
191
193
  if (
192
- pre.length === 0 &&
193
194
  write.count > 1 &&
195
+ pre.length === 0 &&
194
196
  write.text.length + enc.length > opt.size
195
197
  ) {
196
- write.text = ""
197
- // Otherwise split the entries in half.
198
- write.limit = Math.ceil(write.count / 2)
199
- write.count = 0
198
+ const end = k.indexOf(enq)
199
+ write.limit = end === -1 ? k : k.substring(0, end)
200
+ write.done = true
200
201
  write.sub = Radix()
201
202
  Radix.map(rad, write.slice)
202
- return true
203
+ radisk.write(write.limit, write.sub, cb)
204
+ return
203
205
  }
204
206
 
205
207
  write.text += enc
206
208
  },
207
- put: () => {
208
- opt.store.put(file, write.text, cb)
209
- },
210
209
  slice: (value, key) => {
211
- if (key < write.file) return
212
-
213
- if (++write.count > write.limit) {
214
- var name = write.file
215
- // Use only the soul of the key as the filename so that all
216
- // properties of a soul are written to the same file.
217
- let end = key.indexOf(enq)
218
- if (end === -1) {
219
- write.file = key
220
- } else {
221
- write.file = key.substring(0, end)
222
- }
223
- write.count = 0
224
- radisk.write(name, write.sub, write.next)
225
- return true
226
- }
210
+ if (key < write.limit) return
227
211
 
228
212
  write.sub(key, value)
229
213
  },
230
- next: err => {
231
- if (err) return cb(err)
232
-
233
- write.sub = Radix()
234
- if (!Radix.map(rad, write.slice)) {
235
- radisk.write(write.file, write.sub, cb)
236
- }
237
- },
238
214
  }
239
- // If Radix.map doesn't return true when called with write.each as a
240
- // callback then didn't need to split the data. The accumulated write.text
241
- // can then be stored with write.put().
242
- if (!Radix.map(rad, write.each, true)) write.put()
215
+ Radix.map(rad, write.each, true)
216
+ // There is always accumulated write.text to store once write.each has
217
+ // finished.
218
+ opt.store.put(file, write.text, cb)
243
219
  }
244
220
 
245
221
  radisk.read = (key, cb) => {
@@ -248,11 +224,8 @@ const Radisk = opt => {
248
224
  if (typeof value !== "undefined") return cb(u, value)
249
225
  }
250
226
  // Only the soul of the key is compared to filenames (see radisk.write).
251
- let soul = key
252
- let end = key.indexOf(enq)
253
- if (end !== -1) {
254
- soul = key.substring(0, end)
255
- }
227
+ const end = key.indexOf(enq)
228
+ const soul = end === -1 ? key : key.substring(0, end)
256
229
 
257
230
  const read = {
258
231
  lex: file => {
package/src/wire.js CHANGED
@@ -231,10 +231,7 @@ const Wire = opt => {
231
231
  return
232
232
  }
233
233
 
234
- if (retry++ > 5) {
235
- clearInterval(interval)
236
- console.log("websocket not available")
237
- }
234
+ if (retry++ > 5) clearInterval(interval)
238
235
  }, 1000)
239
236
  }
240
237
  })
@@ -279,10 +276,7 @@ const Wire = opt => {
279
276
  return
280
277
  }
281
278
 
282
- if (retry++ > 5) {
283
- clearInterval(interval)
284
- console.log("websocket not available")
285
- }
279
+ if (retry++ > 5) clearInterval(interval)
286
280
  }, 1000)
287
281
  }
288
282
  })
@@ -1,8 +1,6 @@
1
1
  import {describe, test} from "node:test"
2
2
  import assert from "node:assert/strict"
3
3
  import Radisk from "../src/radisk.js"
4
- import Names from "./names.js"
5
- const names = Names()
6
4
 
7
5
  describe("radisk", () => {
8
6
  const puts = {}
@@ -175,8 +173,8 @@ describe("radisk", () => {
175
173
  "!":
176
174
  '\x1F+0\x1F#\x1F"key\x1F=\x1F"value\ncontinued\x0312345\x1F\n' +
177
175
  '\x1F+1\x1F#\x1F"A\x1F=\x1F"valueA\x1F\n' +
178
- '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n',
179
- keyC: '\x1F+0\x1F#\x1F"keyC\x1F=\x1F"valueC\x1F\n',
176
+ '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
177
+ '\x1F+1\x1F#\x1F"C\x1F=\x1F"valueC\x1F\n',
180
178
  newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"' + big + "\x1F\n",
181
179
  })
182
180
  radisk("newFile", (err, value) => {
@@ -198,8 +196,8 @@ describe("radisk", () => {
198
196
  "!":
199
197
  '\x1F+0\x1F#\x1F"key\x1F=\x1F"value\ncontinued\x0312345\x1F\n' +
200
198
  '\x1F+1\x1F#\x1F"A\x1F=\x1F"valueA\x1F\n' +
201
- '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n',
202
- keyC: '\x1F+0\x1F#\x1F"keyC\x1F=\x1F"valueC\x1F\n',
199
+ '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
200
+ '\x1F+1\x1F#\x1F"C\x1F=\x1F"valueC\x1F\n',
203
201
  newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"' + big + "\x1F\n",
204
202
  small: '\x1F+0\x1F#\x1F"small\x1F=\x1F"small value\x1F\n',
205
203
  })
@@ -220,8 +218,8 @@ describe("radisk", () => {
220
218
  "!":
221
219
  '\x1F+0\x1F#\x1F"key\x1F=\x1F"value\ncontinued\x0312345\x1F\n' +
222
220
  '\x1F+1\x1F#\x1F"A\x1F=\x1F"valueA\x1F\n' +
223
- '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n',
224
- keyC: '\x1F+0\x1F#\x1F"keyC\x1F=\x1F"valueC\x1F\n',
221
+ '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
222
+ '\x1F+1\x1F#\x1F"C\x1F=\x1F"valueC\x1F\n',
225
223
  newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"removed...\x1F\n',
226
224
  small: '\x1F+0\x1F#\x1F"small\x1F=\x1F"small value\x1F\n',
227
225
  })
@@ -244,8 +242,8 @@ describe("radisk", () => {
244
242
  '\x1F+1\x1F#\x1F"A\x1F=\x1F"' +
245
243
  big +
246
244
  "\x1F\n" +
247
- '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n',
248
- keyC: '\x1F+0\x1F#\x1F"keyC\x1F=\x1F"valueC\x1F\n',
245
+ '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
246
+ '\x1F+1\x1F#\x1F"C\x1F=\x1F"valueC\x1F\n',
249
247
  newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"removed...\x1F\n',
250
248
  small: '\x1F+0\x1F#\x1F"small\x1F=\x1F"small value\x1F\n',
251
249
  })
@@ -265,8 +263,8 @@ describe("radisk", () => {
265
263
  '\x1F+1\x1F#\x1F"A\x1F=\x1F"' +
266
264
  big +
267
265
  "\x1F\n" +
268
- '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n',
269
- keyC: '\x1F+0\x1F#\x1F"keyC\x1F=\x1F"valueC\x1F\n',
266
+ '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
267
+ '\x1F+1\x1F#\x1F"C\x1F=\x1F"valueC\x1F\n',
270
268
  newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"removed...\x1F\n',
271
269
  small:
272
270
  '\x1F+0\x1F#\x1F"small\x1F=\x1F"small value\x1F\n' +
@@ -292,9 +290,8 @@ describe("radisk", () => {
292
290
  '\x1F+1\x1F#\x1F"A\x1F=\x1F"' +
293
291
  big +
294
292
  "\x1F\n" +
295
- '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n',
296
- keyC:
297
- '\x1F+0\x1F#\x1F"key\x1F\n\x1F+1\x1F#\x1F"C\x1F=\x1F \x1F\n' +
293
+ '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
294
+ '\x1F+1\x1F#\x1F"C\x1F=\x1F \x1F\n' +
298
295
  '\x1F+1\x1F#\x1F"D\x1F=\x1F"valueD\x1F\n',
299
296
  newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"removed...\x1F\n',
300
297
  small:
@@ -319,9 +316,8 @@ describe("radisk", () => {
319
316
  "!":
320
317
  '\x1F+0\x1F#\x1F"key\x1F=\x1F \x1F\n' +
321
318
  '\x1F+1\x1F#\x1F"A\x1F=\x1F \x1F\n' +
322
- '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n',
323
- keyC:
324
- '\x1F+0\x1F#\x1F"key\x1F\n\x1F+1\x1F#\x1F"C\x1F=\x1F \x1F\n' +
319
+ '\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
320
+ '\x1F+1\x1F#\x1F"C\x1F=\x1F \x1F\n' +
325
321
  '\x1F+1\x1F#\x1F"D\x1F=\x1F"valueD\x1F\n',
326
322
  newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"removed...\x1F\n',
327
323
  small: