statebus 6.1.28 → 6.1.29

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.
@@ -0,0 +1,3 @@
1
+ import statebus from 'statebus'
2
+
3
+ console.log(statebus)
package/extras/tests.js CHANGED
@@ -967,6 +967,34 @@ test(function braid_proxies (done) {
967
967
  // Getting a normal property should do a fetch
968
968
  })
969
969
 
970
+ test(function key_patterns (done) {
971
+ bus('path/:pattern/stuff*').to_fetch = function (key, key_parts, t) {
972
+ t.done({ key: key, key_parts, val: 3 })
973
+ }
974
+
975
+ bus.fetch_once('path/foo/stuff(yes:maam,okay)', (o) => {
976
+ assert(o.val === 3)
977
+ assert(o.key_parts.pattern === 'foo')
978
+ done()
979
+ })
980
+ })
981
+
982
+ test(function kson (done) {
983
+ bus('kson_stuff/foo/stuff*').to_fetch = function (key, kson, t) {
984
+ t.done({
985
+ key: key,
986
+ kson: kson
987
+ })
988
+ }
989
+
990
+ bus.fetch_once('kson_stuff/foo/stuff(yes:maam,okay)', (o) => {
991
+ console.log(o)
992
+ assert(o.kson.yes === 'maam')
993
+ assert(o.kson.okay)
994
+ done()
995
+ })
996
+ })
997
+
970
998
  test(function only_one (done) {
971
999
  bus('only_one/*').to_fetch = function (k) {
972
1000
  var id = k[k.length-1]
package/package.json CHANGED
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "statebus",
3
- "version": "6.1.28",
3
+ "version": "6.1.29",
4
4
  "description": "Synchronize state.",
5
5
  "main": "statebus.js",
6
6
  "scripts": {
7
7
  "test": "node extras/tests.js"
8
8
  },
9
9
  "author": "Michael Toomim",
10
+ "files": [
11
+ "statebus.js",
12
+ "client.js",
13
+ "server.js",
14
+ "extras/",
15
+ "readme.md"
16
+ ],
10
17
  "repository": "invisible-college/statebus",
11
18
  "dependencies": {
12
19
  "bcrypt-nodejs": "0.0.3",
package/server.js CHANGED
@@ -48,7 +48,7 @@ function import_server (bus, options)
48
48
 
49
49
  serve: function serve (options) {
50
50
  var master = bus
51
- bus.honk = 'statelog'
51
+ bus.honk = options.honk ?? 'statelog'
52
52
  master.label = 'master'
53
53
 
54
54
  // Initialize Options
package/statebus.js CHANGED
@@ -263,10 +263,10 @@
263
263
  var id = 'bus ' + Math.random().toString(36).substring(7)
264
264
  bus.toString = function () { return bus.label || id }
265
265
  bus.delete_bus = function () {
266
- // // Forget all wildcard handlers
267
- // for (var i=0; i<wildcard_handlers.length; i++) {
268
- // console.log('Forgetting', funk_name(wildcard_handlers[i].funk))
269
- // wildcard_handlers[i].funk.forget()
266
+ // // Forget all pattern handlers
267
+ // for (var i=0; i<pattern_handlers.length; i++) {
268
+ // console.log('Forgetting', funk_name(pattern_handlers[i].funk))
269
+ // pattern_handlers[i].funk.forget()
270
270
  // }
271
271
 
272
272
  // // Forget all handlers
@@ -600,12 +600,12 @@
600
600
  func.defined = func.defined || []
601
601
  func.defined.push(
602
602
  {as:'handler', bus:bus, method:method, key:key})
603
- bind(key, method, func, 'allow_wildcards')
603
+ bind(key, method, func, 'pattern')
604
604
  },
605
605
  get: function () {
606
606
  var result = bindings(key, method)
607
607
  for (var i=0; i<result.length; i++) result[i] = result[i].func
608
- result.delete = function (func) { unbind (key, method, func, 'allow_wildcards') }
608
+ result.delete = function (func) { unbind (key, method, func, 'pattern') }
609
609
  return result
610
610
  }
611
611
  })
@@ -628,6 +628,8 @@
628
628
  case 'key':
629
629
  case 'k':
630
630
  handler.args['key'] = i; break
631
+ case 'key_parts':
632
+ handler.args['key_parts'] = i; break
631
633
  case 'json':
632
634
  case 'vars':
633
635
  handler.args['vars'] = i; break
@@ -645,44 +647,71 @@
645
647
  handler.args['obj'] = i; break
646
648
  case 'old':
647
649
  handler.args['old'] = i; break
650
+ case 'kson':
651
+ handler.args['kson'] = i; break
648
652
  }
649
653
  }
650
654
 
651
655
  // The funks attached to each key, maps e.g. 'fetch /point/3' to '/30'
652
656
  var handlers = new One_To_Many()
653
- var wildcard_handlers = [] // An array of {prefix, method, funk}
657
+ var pattern_handlers = [] // An array of {pattern, method, funk}
654
658
 
655
659
  // A set of timers, for keys to send forgets on
656
660
  var to_be_forgotten = {}
657
- function bind (key, method, func, allow_wildcards) {
658
- bogus_check(key)
659
- if (allow_wildcards && key[key.length-1] === '*')
660
- wildcard_handlers.push({prefix: key,
661
- method: method,
662
- funk: func})
661
+ function bind (pattern, method, func, type) {
662
+ bogus_check(pattern)
663
+
664
+ function pattern_matcher (pattern) {
665
+ var param_names = []
666
+ var regex = new RegExp('^' + pattern.replace(/(?<=^|\/):[^/()]+|\*/g, match => {
667
+ // Replace * with .*
668
+ if (match === '*') return '.*'
669
+
670
+ // Replace :foo with ([^/]+), and remember the "foo" name
671
+ param_names.push(match.slice(1))
672
+ return '([^/]+)'
673
+ }) + '$')
674
+
675
+ return path => {
676
+ var match = path.match(regex)
677
+ if (!match) return null
678
+ var params = {}
679
+ match.slice(1).forEach((val, i) => params[param_names[i]] = val)
680
+ return params
681
+ }
682
+ }
683
+
684
+ // Add patterns to the list, not the hash
685
+ if (type === 'pattern' && /[:*]/.test(pattern)) // Is it a pattern?
686
+ pattern_handlers.push({pattern: pattern,
687
+ matcher: pattern_matcher(pattern),
688
+ method: method,
689
+ funk: func})
690
+
691
+ // Add simple keys to the hash
663
692
  else
664
- handlers.add(method + ' ' + key, funk_key(func))
693
+ handlers.add(method + ' ' + pattern, funk_key(func))
665
694
 
666
695
  // Now check if the method is a fetch and there's a fetched
667
696
  // key in this space, and if so call the handler.
668
697
  }
669
- function unbind (key, method, funk, allow_wildcards) {
670
- bogus_check(key)
671
- if (allow_wildcards && key[key.length-1] === '*')
672
- // Delete wildcard connection
673
- for (var i=0; i<wildcard_handlers.length; i++) {
674
- var handler = wildcard_handlers[i]
675
- if (handler.prefix === key
698
+ function unbind (pattern, method, funk, type) {
699
+ bogus_check(pattern)
700
+ if (type === 'pattern' && /[:*]/.test(pattern)) // Is it a pattern?
701
+ // Delete pattern connection
702
+ for (var i=0; i < pattern_handlers.length; i++) {
703
+ var handler = pattern_handlers[i]
704
+ if (handler.pattern === pattern
676
705
  && handler.method === method
677
706
  && handler.funk === funk) {
678
707
 
679
- wildcard_handlers.splice(i,1) // Splice this element out of the array
680
- i-- // And decrement the counter while we're looping
708
+ pattern_handlers.splice(i,1) // Splice this element out of the array
709
+ i-- // And decrement the counter while we're looping
681
710
  }
682
711
  }
683
712
  else
684
713
  // Delete direct connection
685
- handlers.delete(method + ' ' + key, funk_key(funk))
714
+ handlers.delete(method + ' ' + pattern, funk_key(funk))
686
715
  }
687
716
 
688
717
  function bindings(key, method) {
@@ -707,16 +736,23 @@
707
736
  }
708
737
  }
709
738
 
710
- // Now iterate through prefixes
711
- for (var i=0; i < wildcard_handlers.length; i++) {
712
- handler = wildcard_handlers[i]
713
-
714
- var prefix = handler.prefix.slice(0, -1) // Cut off the *
715
- if (prefix === key.substr(0,prefix.length) // If the prefix matches
716
- && method === handler.method // And it has the right method
739
+ // Now iterate through patterns
740
+ for (var i=0; i < pattern_handlers.length; i++) {
741
+ handler = pattern_handlers[i]
742
+ var matches = handler.matcher(key)
743
+ if (matches // If the pattern matches
744
+ && method === handler.method // And it has the right method
717
745
  && !seen[funk_key(handler.funk)]) {
718
- handler.funk.statebus_binding = {key:handler.prefix, method:method}
719
- result.push({method:method, key:handler.prefix, func:handler.funk})
746
+
747
+ // Todo: add the match to statebus_binding or result.push
748
+ // below as necessary:
749
+
750
+ handler.funk.statebus_binding = {
751
+ key: handler.pattern,
752
+ method: method,
753
+ params: matches
754
+ }
755
+ result.push({method, key:handler.pattern, func:handler.funk})
720
756
  seen[funk_key(handler.funk)] = true
721
757
  }
722
758
  }
@@ -795,6 +831,46 @@
795
831
  return 'Bad JSON "' + r + '" for key ' + key_arg()
796
832
  }
797
833
  }
834
+ // Parse out query params for URLs in the style /foo/bar(param1,param2:val2).
835
+ // We're currently calling that (param1,param2:val2) part "kson", and presuming
836
+ // that it exists in the * part of the pattern like in /foo/bar*.
837
+ function kson_args () {
838
+ // This code is copied from Raphael Walker's parser.coffee
839
+ function split_once (str, char) {
840
+ var i = str.indexOf(char)
841
+ return i === -1 ? [str, ""] : [str.slice(0, i), str.slice(i + 1)]
842
+ }
843
+
844
+ // KSON = Kinda Simple Object Notation
845
+ // but it rhymes with JSON
846
+ function parse_kson (str) {
847
+ // Coffeescript doesn't have object comprehensions :(
848
+ var ret = {}
849
+
850
+ // Now process the string:
851
+ str
852
+ // Pull out the parentheses
853
+ .slice(1, -1)
854
+ // Split by commas. TODO: Allow spaces after commas?
855
+ .split(",")
856
+ // Delete empty parts (this ensures that empty strings
857
+ // will properly result in empty KSON, and allows trailing
858
+ // commas)
859
+ .filter(part => part.length)
860
+ .forEach(part => {
861
+ // If the part has a comma, its a key:value, otherwise
862
+ // it's just a singleton
863
+ var [k, v] = split_once(part, ":")
864
+
865
+ if (v.length === 0) ret[k] = true
866
+ // If the value is itself a KSON object, parse it recursively
867
+ else if (v.startsWith("(")) ret[k] = parse_kson(v)
868
+ else ret[k] = v
869
+ })
870
+ return ret
871
+ }
872
+ return parse_kson(rest_arg())
873
+ }
798
874
  var f = reactive(function () {
799
875
 
800
876
  // Initialize transaction
@@ -861,6 +937,9 @@
861
937
  switch (k) {
862
938
  case 'key':
863
939
  args[func.args[k]] = key_arg(); break
940
+ case 'key_parts':
941
+ args[func.args[k]] = func.statebus_binding && func.statebus_binding.params
942
+ break
864
943
  case 'rest':
865
944
  args[func.args[k]] = rest_arg(); break
866
945
  case 'vars':
@@ -874,6 +953,8 @@
874
953
  var key = key_arg()
875
954
  args[func.args[k]] = bus.cache[key] || (bus.cache[key] = {key:key})
876
955
  break
956
+ case 'kson':
957
+ args[func.args[k]] = kson_args(rest_arg()); break
877
958
  }
878
959
  }
879
960