@mblaney/holster 0.2.0 → 1.0.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.
package/examples/user.js CHANGED
@@ -10,7 +10,7 @@ let alice, bob
10
10
  // Wait for the websocket to connect.
11
11
  setTimeout(() => {
12
12
  user.create("alice", "password", err => {
13
- if (err !== "Username already exists") {
13
+ if (err && err !== "Username already exists") {
14
14
  console.log(err)
15
15
  return
16
16
  }
@@ -40,7 +40,7 @@ setTimeout(() => {
40
40
 
41
41
  setTimeout(() => {
42
42
  user.create("bob", "stronger password", err => {
43
- if (err !== "Username already exists") {
43
+ if (err && err !== "Username already exists") {
44
44
  console.log(err)
45
45
  return
46
46
  }
@@ -77,7 +77,7 @@ setTimeout(() => {
77
77
  }
78
78
 
79
79
  // Use Bob's public key to fetch shared data under his account.
80
- holster.user(bob.pub).get("shared", enc => {
80
+ user.get([bob.pub, "shared"], enc => {
81
81
  user.auth("alice", "password", async err => {
82
82
  if (err) {
83
83
  console.log(err)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mblaney/holster",
3
- "version": "0.2.0",
3
+ "version": "1.0.0",
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/get.js CHANGED
@@ -1,18 +1,25 @@
1
+ import {match} from "./utils.js"
2
+
1
3
  const Get = (lex, graph) => {
2
4
  const soul = lex["#"]
3
- const key = typeof lex["."] === "string" ? lex["."] : false
4
- var node = graph[soul]
5
+ if (!graph[soul]) return
5
6
 
6
- // Can only return a node if a key is provided, because the graph may not
7
- // have all the keys populated for a given soul. This is because Ham.mix
8
- // only adds incoming changes to the graph.
9
- if (!node || !key) return
7
+ const node = {_: {"#": soul, ">": {}}}
10
8
 
11
- let value = node[key]
12
- if (!value) return
9
+ if (typeof lex["."] === "string") {
10
+ const key = lex["."]
11
+ if (typeof graph[soul][key] === "undefined") return
13
12
 
14
- node = {_: node._, [key]: value}
15
- node._[">"] = {[key]: node._[">"][key]}
13
+ node[key] = graph[soul][key]
14
+ node._[">"][key] = graph[soul]._[">"][key]
15
+ } else {
16
+ for (const key of Object.keys(graph[soul])) {
17
+ if (match(lex["."], key)) {
18
+ node[key] = graph[soul][key]
19
+ node._[">"][key] = graph[soul]._[">"][key]
20
+ }
21
+ }
22
+ }
16
23
  return {[soul]: node}
17
24
  }
18
25
 
package/src/ham.js CHANGED
@@ -26,9 +26,9 @@ const Ham = (state, currentState, value, currentValue) => {
26
26
  }
27
27
 
28
28
  Ham.mix = async (change, graph, secure, listen) => {
29
- var machine = Date.now()
30
- var now = {}
31
- var defer = {}
29
+ const machine = Date.now()
30
+ const now = {}
31
+ const defer = {}
32
32
  let wait = 0
33
33
 
34
34
  for (const soul of Object.keys(change)) {
@@ -36,13 +36,14 @@ Ham.mix = async (change, graph, secure, listen) => {
36
36
  let updated = false
37
37
  let alias = false
38
38
  let nodeWait = 0
39
- let pub = ""
40
39
  let verify = secure
41
40
 
42
41
  if (!node || !node._) continue
43
42
 
43
+ const sig = node[utils.userSignature]
44
+ const pub = node[utils.userPublicKey]
44
45
  // If a signature and public key are provided then always verify.
45
- if (node._.s && node._.p) verify = true
46
+ if (sig && pub) verify = true
46
47
 
47
48
  // Special case if soul starts with "~". Node must be system data ie,
48
49
  // ~@alias or ~publickey. For aliases, key and value must be a self
@@ -53,25 +54,19 @@ Ham.mix = async (change, graph, secure, listen) => {
53
54
  alias = true
54
55
  verify = false
55
56
  } else {
56
- if (node._.p && soul != "~" + node._.p) {
57
+ if (pub && soul != "~" + pub) {
57
58
  console.log(`error public key does not match for soul: ${soul}`)
58
59
  continue
59
60
  }
60
61
 
61
- // Need to be able to create public key data before a user is
62
- // authenticated, in this case the soul is the public key which
63
- // should've been used to sign the data.
64
- node._.p = soul.slice(1)
65
62
  verify = true
66
63
  }
67
64
  }
68
65
  if (verify) {
69
- if (!node._.s || !node._.p) {
70
- console.log("error signature and public key required to verify data")
71
- continue
72
- }
66
+ // Partial nodes can be read from disk, just ignore them.
67
+ if (!sig || !pub) continue
73
68
 
74
- if (!(await SEA.verify({m: node, s: node._.s}, {pub: node._.p}))) {
69
+ if (!(await SEA.verify({m: node, s: sig}, {pub: pub}))) {
75
70
  console.log(`error could not verify soul: ${soul}`)
76
71
  continue
77
72
  }
@@ -81,11 +76,14 @@ Ham.mix = async (change, graph, secure, listen) => {
81
76
  if (key === "_") continue
82
77
 
83
78
  const value = node[key]
84
- const state = node._[">"][key]
79
+ const state = node._ && node._[">"] ? node._[">"][key] : 0
85
80
  const currentValue = (graph[soul] || {})[key]
86
81
  const currentState = (graph[soul] || {_: {">": {}}})._[">"][key] || 0
87
82
 
88
- if (alias && key !== utils.rel.is(value)) continue
83
+ if (alias && key !== utils.rel.is(value)) {
84
+ console.log(`error alias ${alias}: ${key} !== ${utils.rel.is(value)}`)
85
+ continue
86
+ }
89
87
 
90
88
  // Defer the update if ahead of machine time.
91
89
  const skew = state - machine
@@ -96,7 +94,7 @@ Ham.mix = async (change, graph, secure, listen) => {
96
94
  // Wait the shortest difference before trying the updates again.
97
95
  if (wait === 0 || skew < wait) wait = nodeWait = skew
98
96
  if (!defer[soul]) {
99
- defer[soul] = {_: {"#": soul, ">": {}, s: node._.s, p: node._.p}}
97
+ defer[soul] = {_: {"#": soul, ">": {}}}
100
98
  }
101
99
  defer[soul][key] = value
102
100
  defer[soul]._[">"][key] = state
@@ -104,13 +102,13 @@ Ham.mix = async (change, graph, secure, listen) => {
104
102
  const result = Ham(state, currentState, value, currentValue)
105
103
  if (result.incoming) {
106
104
  if (!now[soul]) {
107
- now[soul] = {_: {"#": soul, ">": {}, s: node._.s, p: node._.p}}
105
+ now[soul] = {_: {"#": soul, ">": {}}}
108
106
  }
109
107
  // TODO: graph should not just grow indefintitely in memory.
110
108
  // Need to have a max size after which start dropping the oldest state
111
109
  // Do something similar to Dup which can handle deletes?
112
110
  if (!graph[soul]) {
113
- graph[soul] = {_: {"#": soul, ">": {}, s: node._.s, p: node._.p}}
111
+ graph[soul] = {_: {"#": soul, ">": {}}}
114
112
  }
115
113
  graph[soul][key] = now[soul][key] = value
116
114
  graph[soul]._[">"][key] = now[soul]._[">"][key] = state