@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,31 @@
1
+ # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
3
+
4
+ name: Node.js CI
5
+
6
+ on:
7
+ push:
8
+ branches: [ "main" ]
9
+ pull_request:
10
+ branches: [ "main" ]
11
+
12
+ jobs:
13
+ build:
14
+
15
+ runs-on: ubuntu-latest
16
+
17
+ strategy:
18
+ matrix:
19
+ node-version: [18.x, 20.x, 22.x]
20
+ # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
21
+
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - name: Use Node.js ${{ matrix.node-version }}
25
+ uses: actions/setup-node@v4
26
+ with:
27
+ node-version: ${{ matrix.node-version }}
28
+ cache: 'npm'
29
+ - run: npm ci
30
+ - run: npm run build --if-present
31
+ - run: npm test
package/LICENSE.md ADDED
@@ -0,0 +1,55 @@
1
+ Copyright (c) 2015 Mark Nadal
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
20
+
21
+ ---
22
+
23
+ Copyright (c) 2015 Mark Nadal
24
+
25
+ This software is provided 'as-is', without any express or implied
26
+ warranty. In no event will the authors be held liable for any damages
27
+ arising from the use of this software.
28
+
29
+ Permission is granted to anyone to use this software for any purpose,
30
+ including commercial applications, and to alter it and redistribute it
31
+ freely, subject to the following restrictions:
32
+
33
+ 1. The origin of this software must not be misrepresented; you must not
34
+ claim that you wrote the original software. If you use this software
35
+ in a product, an acknowledgement in the product documentation would be
36
+ appreciated but is not required.
37
+ 2. Altered source versions must be plainly marked as such, and must not be
38
+ misrepresented as being the original software.
39
+ 3. This notice may not be removed or altered from any source distribution.
40
+
41
+ ---
42
+
43
+ Copyright 2015 Mark Nadal
44
+
45
+ Licensed under the Apache License, Version 2.0 (the "License");
46
+ you may not use this file except in compliance with the License.
47
+ You may obtain a copy of the License at
48
+
49
+ http://www.apache.org/licenses/LICENSE-2.0
50
+
51
+ Unless required by applicable law or agreed to in writing, software
52
+ distributed under the License is distributed on an "AS IS" BASIS,
53
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
54
+ See the License for the specific language governing permissions and
55
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ Holster is a service that allows synchronising data between devices using Node,
2
+ Deno, Bun or the browser.
3
+
4
+ It is a port of [GunDB](https://gun.eco), following
5
+ [Porting Gun](https://github.com/gundb/port) and is implemented as JavaScript
6
+ modules so that it can run in any environment. A build version of Holster is
7
+ also provided using [esbuild](https://esbuild.github.io), to run in production.
8
+
9
+ Check out the [Github Wiki](https://github.com/mblaney/holster/wiki) for how
10
+ to get started using the API, and for more information.
11
+
12
+ ### Quick Start
13
+
14
+ - Clone this repo and run `npm install`.
15
+ - Run the server with `node src/index.js`.
16
+ - Open `http://localhost:3000/examples/index.html` in the browser.
17
+ - You will then also have access to the Holster API via the `holster` object in
18
+ the console.
19
+
20
+ ### Development
21
+
22
+ - When modifying src files run: `npx prettier src --write && npm run build`
23
+ - When modifying tests run: `npx prettier test --write`
24
+ - To run the tests use: `npm run test`
@@ -0,0 +1,4 @@
1
+ var X={is:e=>!(e instanceof Array)&&(e-parseFloat(e)+1>=0||e===1/0||e===-1/0)},_={is:e=>e?e instanceof Object&&e.constructor===Object||Object.prototype.toString.call(e).match(/^\[object (\w+)\]$/)[1]==="Object":!1,map:(e,t,o)=>{var r=Object.keys(e);for(let n=0;n<r.length;n++){let u=t(e[r[n]],r[n],o);if(typeof u<"u")return u}},put:(e,t,o)=>(e||(e={}),e[t]=o,e),del:(e,t)=>{if(e)return e[t]=null,delete e[t],e}},ve=(e,t,o)=>{if(o.id){o.id=!1;return}if(t==="#"&&typeof e=="string"){o.id=e;return}o.id=!1},T={is:e=>{if(e&&e["#"]&&!e._&&_.is(e)){let t={};if(_.map(e,ve,t),t.id)return t.id}return!1},ify:e=>_.put({},"#",e)},J="_holster_user_public_key",W=(e,t,o,r)=>{let n={[e]:{_:{"#":e,">":{},s:o,p:r}}};for(let[u,l]of Object.entries(t))n[e][u]=l,n[e]._[">"][u]=Date.now();return r&&(n[e][J]=r,n[e]._[">"][J]=Date.now()),n},z=(e,t)=>{if(typeof t>"u")return e===null;if(typeof e>"u")return!0;if(typeof e=="string")return e===t;if(!_.is(e)||!t)return!1;let o=e["*"];if(o)return t.slice(0,o.length)===o;let r=e[">"],n=e["<"];return r&&n?t>=r&&t<=n:r?t>=r:n?t<=n:!1},E={random:e=>{var t="";let o="0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";e||(e=24);for(let r=0;r<e;r++)t+=o.charAt(Math.floor(Math.random()*o.length));return t}};var Se=e=>{e||(e=9e3);let t={store:{}};return t.check=o=>t.store[o]?t.track(o):!1,t.track=o=>(t.store[o]=Date.now(),t.expiry||(t.expiry=setTimeout(()=>{let r=Date.now();Object.keys(t.store).forEach(n=>{r-t.store[n]>e&&delete t.store[n]}),t.expiry=null},e)),o),t},le=Se;var ke=(e,t)=>{let o=e["#"],r=typeof e["."]=="string"?e["."]:!1;var n=t[o];if(!n||!r)return;let u=n[r];if(u)return n={_:n._,[r]:u},n._[">"]={[r]:n._[">"][r]},{[o]:n}},ne=ke;typeof btoa>"u"&&(globalThis.btoa=e=>Buffer.from(e,"binary").toString("base64"),globalThis.atob=e=>Buffer.from(e,"base64").toString("binary"));function Z(){}Object.assign(Z,{from:Array.from});Z.prototype=Object.create(Array.prototype);Z.prototype.toString=function(e,t,o){e||(e="utf8"),t||(t=0);let r=this.length;if(e==="hex"){let n=new Uint8Array(this);return[...Array((o&&o+1||r)-t).keys()].map(u=>n[u+t].toString(16).padStart(2,"0")).join("")}if(e==="utf8")return Array.from({length:(o||r)-t},(n,u)=>String.fromCharCode(this[u+t])).join("");if(e==="base64")return btoa(this)};var M=Z;function I(...e){return console.warn("new SafeBuffer() is deprecated, please use SafeBuffer.from()"),I.from(...e)}I.prototype=Object.create(Array.prototype);Object.assign(I,{from(){if(!Object.keys(arguments).length||arguments[0]==null)throw new TypeError("First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.");let e=arguments[0],t;if(typeof e=="string"){let r=arguments[1]||"utf8";if(r==="hex"){let n=e.match(/([\da-fA-F]{2})/g).map(u=>parseInt(u,16));if(!n||!n.length)throw new TypeError("Invalid first argument for type 'hex'.");t=M.from(n)}else if(r==="utf8"||r==="binary"){let n=e.length,u=new Uint16Array(n);Array.from({length:n},(l,s)=>u[s]=e.charCodeAt(s)),t=M.from(u)}else if(r==="base64"){let n=atob(e),u=n.length,l=new Uint8Array(u);Array.from({length:u},(s,i)=>l[i]=n.charCodeAt(i)),t=M.from(l)}else console.info("SafeBuffer.from unknown encoding: "+r);return t}if(e.byteLength?e.byteLength:e.length){let r;return e instanceof ArrayBuffer&&(r=new Uint8Array(e)),M.from(r||e)}},alloc(e,t=0){return M.from(new Uint8Array(Array.from({length:e},()=>t)))},concat(e){if(!Array.isArray(e))throw new TypeError("First argument must be Array containing ArrayBuffer or Uint8Array instances.");return M.from(e.reduce((t,o)=>t.concat(Array.from(o)),[]))}});I.prototype.from=I.from;I.prototype.toString=M.prototype.toString;var N=I;var je=typeof document>"u",fe=je?(await import("node:crypto")).webcrypto:globalThis.crypto,$=fe.subtle,Y=e=>typeof e=="string"?e:JSON.stringify(e),L=e=>{try{return JSON.parse(e)}catch{return e}},V=e=>{let t=new Uint8Array(N.alloc(e));return N.from(fe.getRandomValues(t))},q=(e,t)=>{let[o,r]=e.split(".");return{kty:"EC",crv:"P-256",x:o,y:r,d:t,ext:!0,key_ops:t?["sign"]:["verify"]}},ee=async e=>{let t=await $.digest({name:"SHA-256"},new TextEncoder().encode(Y(e)));return N.from(t)},ie=async(e,t)=>{let o=e+t.toString("utf8"),r=N.from(await ee(o),"binary"),n=xe(r);return await $.importKey("jwk",n,{name:"AES-GCM"},!1,["encrypt","decrypt"])},xe=e=>({kty:"oct",k:e.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/\=/g,""),ext:!1,alg:"A256GCM"});var _e={pair:async e=>{let t=await $.generateKey({name:"ECDSA",namedCurve:"P-256"},!0,["sign","verify"]).then(async n=>{let u=await $.exportKey("jwk",n.publicKey);return{priv:(await $.exportKey("jwk",n.privateKey)).d,pub:u.x+"."+u.y}}),o=await $.generateKey({name:"ECDH",namedCurve:"P-256"},!0,["deriveKey"]).then(async n=>{let u=await $.exportKey("jwk",n.publicKey);return{epriv:(await $.exportKey("jwk",n.privateKey)).d,epub:u.x+"."+u.y}}),r={pub:t.pub,priv:t.priv,epub:o.epub,epriv:o.epriv};return e&&e(r),r},encrypt:async(e,t,o)=>{if(!t||!t.epriv)return o&&o(null),null;let r={s:V(9),iv:V(15)},n=await ie(t.epriv,r.s).then(l=>$.encrypt({name:"AES-GCM",iv:new Uint8Array(r.iv)},l,new TextEncoder().encode(Y(e)))),u={ct:N.from(n,"binary").toString("base64"),iv:r.iv.toString("base64"),s:r.s.toString("base64")};return o&&o(u),u},decrypt:async(e,t,o)=>{if(!e||!e.ct||!e.iv||!e.s||!t||!t.epriv)return o&&o(null),null;let r={ct:N.from(e.ct,"base64"),iv:N.from(e.iv,"base64"),s:N.from(e.s,"base64")};try{let n=await ie(t.epriv,r.s).then(l=>$.decrypt({name:"AES-GCM",iv:new Uint8Array(r.iv),tagLength:128},l,new Uint8Array(r.ct))),u=L(new TextDecoder("utf8").decode(n));return o&&o(u),u}catch{return o&&o(null),null}},verify:async(e,t,o)=>{if(!t||!t.pub)return o&&o(null),null;let r=L(e),n=await $.importKey("jwk",q(t.pub),{name:"ECDSA",namedCurve:"P-256"},!1,["verify"]),u={};if(typeof r.m=="string")u=r.m;else for(let a of Object.keys(r.m))a!=="_"&&a!=J&&(u[a]=r.m[a]);let l=await ee(u),s=new Uint8Array(N.from(r.s,"base64")),i={name:"ECDSA",hash:{name:"SHA-256"}};if(await $.verify(i,n,s,new Uint8Array(l))){let a=L(r.m);return o&&o(a),a}return o&&o(null),null},sign:async(e,t,o)=>{if(!t||!t.pub||!t.priv)return o&&o(null),null;let r=L(e),n=await ee(r),u=q(t.pub,t.priv),l={name:"ECDSA",namedCurve:"P-256"},s=await $.importKey("jwk",u,l,!1,["sign"]).then(a=>$.sign({name:"ECDSA",hash:{name:"SHA-256"}},a,new Uint8Array(n))),i={m:r,s:N.from(s,"binary").toString("base64")};return o&&o(i),i},work:async(e,t,o)=>{typeof t=="function"&&(o=t,t=void 0),typeof t>"u"&&(t=V(9));let r=await $.importKey("raw",new TextEncoder().encode(Y(e)),{name:"PBKDF2"},!1,["deriveBits"]),n={name:"PBKDF2",iterations:1e5,salt:new TextEncoder().encode(t),hash:{name:"SHA-256"}},u=await $.deriveBits(n,r,512),l={epriv:N.from(u,"binary").toString("base64")};return o&&o(l),l},secret:async(e,t,o)=>{if(!e||!e.epub||!t||!t.epub||!t.epriv)return o&&o(null),null;let r={name:"ECDH",namedCurve:"P-256"},n=q(e.epub),u=await $.importKey("jwk",n,r,!0,[]),l=q(t.epub,t.epriv,!1);delete l.key_ops;let s=await $.importKey("jwk",l,r,!1,["deriveBits"]).then(async i=>{let a=await $.deriveBits({public:u,name:"ECDH",namedCurve:"P-256"},i,256),h=await $.importKey("raw",new Uint8Array(a),{name:"AES-GCM",length:256},!0,["encrypt","decrypt"]);return $.exportKey("jwk",h).then(({k:y})=>y)});return o&&o({epriv:s}),{epriv:s}}},K=_e;var oe=(e,t,o,r)=>e<t?{historical:!0}:e>t?{incoming:!0}:(typeof o!="string"&&(o=JSON.stringify(o)||""),typeof r!="string"&&(r=JSON.stringify(r)||""),o===r?{state:!0}:o<r?{current:!0}:{incoming:!0});oe.mix=async(e,t,o,r)=>{var n=Date.now(),u={},l={};let s=0;for(let i of Object.keys(e)){let a=e[i],h=!1,y=!1,b=0,d="",c=o;if(!(!a||!a._)){if(a._.s&&a._.p&&(c=!0),i.length>1&&i[0]==="~")if(i[1]==="@")y=!0,c=!1;else{if(a._.p&&i!="~"+a._.p){console.log(`error public key does not match for soul: ${i}`);continue}a._.p=i.slice(1),c=!0}if(c){if(!a._.s||!a._.p){console.log("error signature and public key required to verify data");continue}if(!await K.verify({m:a,s:a._.s},{pub:a._.p})){console.log(`error could not verify soul: ${i}`);continue}}for(let f of Object.keys(a)){if(f==="_")continue;let p=a[f],g=a._[">"][f],w=(t[i]||{})[f],v=(t[i]||{_:{">":{}}})._[">"][f]||0;if(y&&f!==T.is(p))continue;let m=g-n;if(m>0){if(m>864e5)continue;(s===0||m<s)&&(s=b=m),l[i]||(l[i]={_:{"#":i,">":{},s:a._.s,p:a._.p}}),l[i][f]=p,l[i]._[">"][f]=g}else oe(g,v,p,w).incoming&&(u[i]||(u[i]={_:{"#":i,">":{},s:a._.s,p:a._.p}}),t[i]||(t[i]={_:{"#":i,">":{},s:a._.s,p:a._.p}}),t[i][f]=u[i][f]=p,t[i]._[">"][f]=u[i]._[">"][f]=g,r[i]&&setTimeout(()=>{r[i]&&r[i].filter(S=>z(S["."],f)).forEach(S=>S.cb())},100),h=!0)}c&&b!==0&&u[i]&&(Object.assign(l[i],u[i]),delete u[i]),h&&r[i]&&setTimeout(()=>{r[i]&&r[i].filter(f=>z(f["."])).forEach(f=>f.cb())},100)}}return{now:u,defer:l,wait:s}};var se=oe;var U="",G="",ae=()=>{let e=(t,o,r)=>{if(r||(e[U]||(e[U]={}),r=e[U]),!t)return r;let n=0,u={},l=t[n],s=t.length-1,i=typeof o>"u",a=r[l];for(;!a&&n<s;)l+=t[++n],a=r[l];if(a)if(n===s){if(i)return typeof a[G]>"u"?a[U]:a[G];a[G]=o}else return!a[U]&&!i&&(a[U]={}),e(t.slice(++n),o,a[U]);else if(_.map(r,(y,b)=>{let d=0,c="";for(;b[d]===t[d];)c+=b[d++];if(c){if(i)return d<=s?void 0:(u[b.slice(d)]=y,y);let f={[b.slice(d)]:y,[t.slice(d)]:{[G]:o}};return r[c]={[U]:f},delete r[b],!0}})){if(i)return u}else{if(i)return;r[l]||(r[l]={}),r[l][G]=o}};return e};ae.map=function e(t,o,r,n){n||(n=[]);var u=t[U]||t,l=Object.keys(u).sort(),s;for(let i=0;i<l.length;i++){let a=l[i],h=u[a],y=h[G];if(typeof y<"u"){if(y=o(y,n.join("")+a,a,n),typeof y<"u")return y}else r&&o(s,n.join(""),a,n);if(h[U]){if(n.push(a),y=e(h[U],o,r,n),typeof y<"u")return y;n.pop()}}};var B=ae;var pe="",ce="",O="",R=e=>{var t,o=null;if(e||(e={}),e.log||(e.log=console.log),e.batch||(e.batch=10*1e3),e.write||(e.write=1),e.size||(e.size=1024*1024),!e.store){e.log("Radisk needs `store` interface with `{get: fn, put: fn, list: fn}`");return}if(!e.store.get){e.log("Radisk needs `store.get` interface with `(file, cb)`");return}if(!e.store.put){e.log("Radisk needs `store.put` interface with `(file, data, cb)`");return}if(!e.store.list){e.log("Radisk needs a streaming `store.list` interface with `(cb)`");return}let r=(n,u,l)=>{if(n=""+n,typeof u=="function")return l=u,u=r.batch(n),typeof u<"u"||r.thrash.at&&(u=r.thrash.at(n),typeof u<"u")?l(t,u):r.read(n,l);if(r.batch(n,u),l&&r.batch.acks.push(l),++r.batch.ed>=e.batch)return r.thrash();clearTimeout(r.batch.timeout),r.batch.timeout=setTimeout(r.thrash,e.write)};return r.batch=B(),r.batch.acks=[],r.batch.ed=0,r.thrash=()=>{if(r.thrash.ing)return r.thrash.more=!0;clearTimeout(r.batch.timeout),r.thrash.more=!1,r.thrash.ing=!0;var n=r.thrash.at=r.batch;r.batch=null,r.batch=B(),r.batch.acks=[],r.batch.ed=0;let u=0;r.save(n,l=>{++u>1||(l&&e.log(l),n.acks.forEach(s=>s(l)),r.thrash.at=null,r.thrash.ing=!1,r.thrash.more&&r.thrash())})},r.save=(n,u)=>{let l={find:(s,i)=>{if(!(i<l.start))return l.start=i,e.store.list(l.lex),!0},lex:s=>{if(!s||s>l.start)return l.end=s,l.mix(l.file||"!",l.start,l.end),!0;l.file=s},mix:(s,i,a)=>{l.start=l.end=l.file=t,r.parse(s,(h,y)=>{if(h)return u(h);B.map(n,(b,d)=>{if(!(d<i)){if(a&&a<d)return l.start=d,l.start;y(d,b)}}),r.write(s,y,l.next)})},next:s=>{if(s)return u(s);if(l.start)return B.map(n,l.find);u(s)}};B.map(n,l.find)},r.write=(n,u,l)=>{o=null;let s={text:"",count:0,file:n,each:(i,a,h,y)=>{s.count++;var b=R.encode(y.length)+"#"+R.encode(h)+(typeof i>"u"?"":"="+R.encode(i))+`
2
+ `;if(s.count>1&&s.text.length+b.length>e.size)return s.text="",s.limit=Math.ceil(s.count/2),s.count=0,s.sub=B(),B.map(u,s.slice),!0;s.text+=b},put:()=>{e.store.put(n,s.text,l)},slice:(i,a)=>{if(!(a<s.file)){if(++s.count>s.limit){var h=s.file;let y=a.indexOf(ce);return y===-1?s.file=a:s.file=a.substring(0,y),s.sub(s.file,null),s.count=0,r.write(h,s.sub,s.next),!0}s.sub(a,i)}},next:i=>{if(i)return l(i);s.sub=B(),B.map(u,s.slice)||r.write(s.file,s.sub,l)}};B.map(u,s.each,!0)||s.put()},r.read=(n,u)=>{if(o){let a=o(n);if(typeof a<"u")return u(t,a)}let l=n,s=n.indexOf(ce);s!==-1&&(l=n.substring(0,s));let i={lex:a=>{if(!a){if(!i.file){u("no file found",t);return}r.parse(i.file,i.it);return}a>l||a<i.file||(i.file=a)},it:(a,h)=>{a&&e.log(a),h&&(o=h,i.value=h(n)),u(a,i.value)}};e.store.list(i.lex)},r.parse=(n,u)=>{let l={disk:B(),read:(s,i)=>{if(s)return u(s);if(!i)return u(t,l.disk);let a=[],h=l.split(i);for(;h;){let y,b,d=h[1];h=l.split(h[2])||"",h[0]==="#"&&(y=h[1],a=a.slice(0,d),d<=a.length&&a.push(y)),h=l.split(h[2])||"",h[0]!==`
3
+ `&&(h[0]==="="&&(b=h[1]),typeof y<"u"&&typeof b<"u"&&l.disk(a.join(""),b),h=l.split(h[2]))}u(t,l.disk)},split:s=>{if(!s)return;let i=-1,a="",h=null;for(;(h=s[++i])&&h!==O;)a+=h;let y={};if(h)return[a,R.decode(s.slice(i),y),s.slice(i+y.i)]}};e.store.get(n,l.read)},r};R.encode=e=>{let t="";if(e instanceof Array&&e.length===2&&(t=pe+e[1],e=e[0]),typeof e=="string"){let r=0,n=null,u=O;for(;n=e[r++];)n===O&&(u+=O);return u+'"'+e+t+O}let o=T.is(e);if(o)return O+"#"+o+t+O;if(X.is(e))return O+"+"+(e||0)+t+O;if(e===!0)return O+"+"+t+O;if(e===!1)return O+"-"+t+O;if(e===null)return O+" "+t+O};R.decode=(e,t)=>{var o="",r=-1,n=0,u=null,l=null;if(e[0]!==O)return;for(;u=e[++r];)if(l){if(u===O&&--n<=0)break;o+=u}else u===O?n++:l=u||!0;t&&(t.i=r+1);let[s,i]=o.split(pe);if(i){if(i=parseFloat(i),l==='"')return[s,i];if(l==="#")return[T.ify(s),i];if(l==="+")return s.length===0?[!0,i]:[parseFloat(s),i];if(l==="-")return[!1,i];if(l===" ")return[null,i]}else{if(l==='"')return o;if(l==="#")return T.ify(o);if(l==="+")return o.length===0?!0:parseFloat(o);if(l==="-")return!1;if(l===" ")return null}};var de=R;var he=typeof document>"u",F=he?await import("node:fs"):void 0,ge="",te="",ue=te+"+0"+te+"#"+te+'"root'+te,Ae=e=>{let t=e.file;if(he)return F.existsSync(t)||F.mkdirSync(t),F.existsSync(t+"/!")||F.writeFileSync(t+"/!",ue),{get:(o,r)=>{F.readFile(t+"/"+o,(n,u)=>{if(n){if(n.code==="ENOENT"){r();return}console.log("fs.readFile error:",n)}u&&(u=u.toString()),r(n,u)})},put:(o,r,n)=>{var u=Math.random().toString(36).slice(-9),l=o+"."+u+".tmp";F.writeFile(l,r,s=>{if(s){n(s);return}F.rename(l,t+"/"+o,n)})},list:o=>{F.readdir(t,(r,n)=>{n.forEach(o),o()})}};if(e.indexedDB){let o,r=indexedDB.open(t,1);return r.onupgradeneeded=n=>{n.target.result.createObjectStore(t)},r.onerror=n=>{console.log(n)},r.onsuccess=()=>{if(o=r.result,o){let u=o.transaction([t],"readonly").objectStore(t).getKey("!");u.onerror=()=>{console.log(`error getting key ${t}/!`)},u.onsuccess=()=>{if(!u.result){let s=o.transaction([t],"readwrite").objectStore(t).put(ue,"!");s.onerror=()=>{console.log(`error putting root on ${t}/!`)}}}}else console.log("error indexedDB not available")},{get:(n,u)=>{if(o){let s=o.transaction([t],"readonly").objectStore(t).get(n);s.onerror=()=>{console.log(`error getting ${t}/${n}`)},s.onsuccess=()=>{u(null,s.result)}}else u("error indexedDB not available")},put:(n,u,l)=>{if(o){let i=o.transaction([t],"readwrite").objectStore(t).put(u,n);i.onerror=()=>{console.log(`error putting data on ${t}/${n}`)},i.onsuccess=()=>{l(null)}}else l("error indexedDB not available")},list:n=>{if(o){let l=o.transaction([t],"readonly").objectStore(t).getAllKeys();l.onerror=()=>console.log("error getting keys for",t),l.onsuccess=()=>{l.result.forEach(n),n()}}else console.log("error indexedDB not available"),n()}}}return{get:(o,r)=>{r(null,ue)},put:(o,r,n)=>{n(null)},list:o=>{o("!"),o()}}},Oe=e=>{_.is(e)||(e={}),e.file=String(e.file||"radata"),e.store||(e.store=Ae(e));let t=de(e);return{get:(o,r)=>{if(!o){r("lex required");return}var n=o["#"],u=typeof o["."]=="string"?o["."]:"",l;let s=(i,a)=>{z(o["."],a)&&(l||(l={_:{"#":n,">":{}}}),l[a]=i[0],l._[">"][a]=i[1])};t(n+ge+u,(i,a)=>{let h;_.is(a)?(B.map(a,s),l||s(a,u),h={[n]:l}):a&&(s(a,u),h={[n]:l}),r(i,h)})},put:(o,r)=>{if(!o){r("graph required");return}var n=0;let u=l=>{if(n--,!u.err){if(u.err=l,u.err){r(u.err);return}n===0&&r(null)}};Object.keys(o).forEach(l=>{var s=o[l];Object.keys(s).forEach(i=>{if(i==="_")return;n++;let a=s[i],h=s._[">"][i];t(l+ge+i,[a,h],u)})})}}},ye=Oe;var me=typeof document>"u",we=me?await import("ws"):void 0;typeof globalThis.WebSocket>"u"&&(globalThis.WebSocket=we?.WebSocket);var Ce=e=>{_.is(e)||(e={});let t=le(e.maxAge),o=ye(e),r={},n={},u={},l=async(c,f,p)=>{for(let g of Object.keys(c)){let w=await new Promise(S=>{a({"#":g},S,f)});if(w.err)return p&&p(w.err),!1;let v=c[g],m=v._?v._.p:void 0,k=J;if(!(!w.put||!w.put[g]||w.put[g][k]===m))return p&&p(`error in wire check public key does not match for soul: ${g}`),!1}return!0},s=(c,f)=>{let p=ne(c.get,r);p?f(JSON.stringify({"#":t.track(E.random(9)),"@":c["#"],put:p})):o.get(c.get,(g,w)=>{f(JSON.stringify({"#":t.track(E.random(9)),"@":c["#"],put:w,err:g}))})},i=async(c,f)=>{let p=await se.mix(c.put,r,e.secure,u);if(Object.keys(p.now).length){if(!await l(p.now,f))return;o.put(p.now,g=>{f(JSON.stringify({"#":t.track(E.random(9)),"@":c["#"],err:g}))})}Object.keys(p.defer).length&&setTimeout(()=>i({put:p.defer},f),p.wait)},a=(c,f,p,g)=>{if(!f)return;_.is(g)||(g={});let w=ne(c,r);if(w){f({put:w});return}o.get(c,(v,m)=>{if(m){f({put:m,err:v});return}v&&console.log(v);let k=E.random(9);n[k]=f,p(JSON.stringify({"#":t.track(k),get:c})),setTimeout(()=>{let S=n[k];if(S){let j=c["#"],A={[j]:null};typeof c["."]=="string"&&(A[j]={[c["."]]:null}),S({put:A}),delete n[k]}},g.wait||100)})},h=c=>({get:(f,p,g)=>{a(f,p,c,g)},put:async(f,p)=>{let g=await se.mix(f,r,e.secure,u);Object.keys(g.now).length===0||!await l(g.now,c,p)||(o.put(g.now,p),c(JSON.stringify({"#":t.track(E.random(9)),put:f})))},on:(f,p)=>{let g=f&&f["#"];!g||!p||(u[g]?u[g].push({".":f["."],cb:p}):u[g]=[{".":f["."],cb:p}])},off:(f,p)=>{let g=f&&f["#"];if(!(!g||!u[g]))if(p){let w=u[g].find(v=>v.cb===p);w&&u[g].splice(u[g].indexOf(w),1)}else delete u[g]}});if(me){let c=e.wss,f=()=>c.clients();c||(c=new we.WebSocketServer({port:8080}),f=()=>c.clients);let p=(g,w)=>{f().forEach(v=>{v.readyState===WebSocket.OPEN&&v.send(g,{binary:w})})};return c.on("connection",g=>{g.on("error",console.error),g.on("message",(w,v)=>{let m=JSON.parse(w);if(t.check(m["#"]))return;t.track(m["#"]),m.get&&s(m,p),m.put&&i(m,p),p(w,v);let k=m["@"],S=n[k];S&&(delete m["#"],delete m["@"],S(m),delete n[k])})}),h(p)}let y=new WebSocket("ws://localhost:8080"),b=c=>{if(!y||y.readyState!==WebSocket.OPEN){console.log("websocket not available");return}y.send(c)},d=()=>{y||(y=new WebSocket("ws://localhost:8080")),y.onclose=c=>{y=null,setTimeout(d,Math.floor(Math.random()*5e3))},y.onerror=c=>{console.error(c)},y.onmessage=c=>{let f=JSON.parse(c.data);if(t.check(f["#"]))return;t.track(f["#"]),f.get&&s(f,b),f.put&&i(f,b),b(c.data);let p=f["@"],g=n[p];g&&(delete f["#"],delete f["@"],g(f),delete n[p])}};return d(),h(b)},re=Ce;var Ee=(e,t)=>{t||(t=re(e));let o=[],r=!1,n=!1,u=0,l=(i,a,h,y)=>{let b=p=>{u++,l(p,a,h,y)},d=p=>{o=[],u=0,n=!1,y(p)},c=()=>{if(o.length===0){d("Wrong username or password");return}let p=o.shift();t.get({"#":p},async g=>{if(g.err){d(`error getting ${p}: ${g.err}`);return}let w=g.put&&g.put[p];if(!w||!w.auth)return c();let v=JSON.parse(w.auth),m=await K.work(a,v.salt),k=await K.decrypt(v.enc,m);if(!k)return c();if(s.is={username:i,pub:w.pub,epub:w.epub,priv:k.priv,epriv:k.epriv},s.ctx="~"+w.pub,h!==""){let S=E.random(64),j=await K.work(h,S),A=await K.encrypt(k,j),x={auth:JSON.stringify({enc:A,salt:S})},C=await K.sign(x,s.is),D=W(p,C.m,C.s,w.pub);t.put(D,P=>{d(P?`error putting ${x} on ${p}: ${P}`:null)});return}return d(null)})};if(u>9){d("Wrong username or password");return}let f="~@"+i;t.get({"#":f},async p=>{if(p.err){d(`error getting ${f}: ${p.err}`);return}let g=p.put&&p.put[f];if(!g)return b(i);delete p.put[f]._,o=Object.keys(g),c()})},s={create:(i,a,h)=>{let y=d=>{h?h(d):console.log(d)};if(r){y("User is already being created");return}if(i===""){y("Please provide a username");return}if(a===""){y("Please provide a password");return}r=!0;let b="~@"+i;t.get({"#":b},async d=>{if(d.err){r=!1,y(`error getting ${b}: ${d.err}`);return}if(d.put&&d.put[b]){r=!1,y("Username already exists");return}let c=E.random(64),f=await K.work(a,c),p=await K.pair(),g={priv:p.priv,epriv:p.epriv},w=await K.encrypt(g,f),v={username:i,pub:p.pub,epub:p.epub,auth:JSON.stringify({enc:w,salt:c})},m="~"+p.pub,k=await K.sign(v,p),S=W(m,k.m,k.s,p.pub);t.put(S,j=>{if(r=!1,j){y(`error putting ${v} on ${m}: ${j}`);return}let A={[m]:{"#":m}};t.put(W(b,A),x=>{if(x){y(`error putting ${A} on ${b}: ${x}`);return}h&&h(null)})})})},auth:(i,a,h)=>{let y=b=>{h?h(b):b&&console.log(b)};if(n){y("User is already authenticating");return}if(s.is=null,i===""){y("Please provide a username");return}if(a===""){y("Please provide a password");return}n=!0,l(i,a,"",y)},change:(i,a,h,y)=>{let b=d=>{y?y(d):d&&console.log(d)};if(n){b("User is already authenticating");return}if(s.is=null,i===""){b("Please provide a username");return}if(a===""){b("Please provide a password");return}if(h===""){b("Please provide a new password");return}n=!0,l(i,a,h,b)},store:i=>{if(!s.is){console.log("Please authenticate before calling store");return}if(i){typeof globalThis.localStorage<"u"&&globalThis.localStorage.setItem("user.is",JSON.stringify(s.is));return}typeof globalThis.sessionStorage<"u"&&globalThis.sessionStorage.setItem("user.is",JSON.stringify(s.is))},recall:i=>{if(i){if(typeof globalThis.localStorage<"u"){let a=globalThis.localStorage.getItem("user.is");a?(s.is=JSON.parse(a),s.ctx="~"+s.is.pub):console.log("User credentials not stored in local storage")}return}if(typeof globalThis.sessionStorage<"u"){let a=globalThis.sessionStorage.getItem("user.is");a?(s.is=JSON.parse(a),s.ctx="~"+s.is.pub):console.log("User credentials not stored in session storage")}},leave:()=>{s.is=null,s.ctx=null,typeof globalThis.localStorage<"u"&&globalThis.localStorage.removeItem("user.is"),typeof globalThis.sessionStorage<"u"&&globalThis.sessionStorage.removeItem("user.is")},delete:(i,a,h)=>{let y=b=>{h?h(b):console.log(b)};if(n){y("User is already authenticating");return}if(i===""){y("Please provide a username");return}if(a===""){y("Please provide a password");return}n=!0,l(i,a,"",async b=>{if(b){y(b);return}let d={username:null,pub:null,epub:null,auth:null},c=await K.sign(d,s.is),f="~"+s.is.pub,p=W(f,c.m,c.s,s.is.pub);t.put(p,g=>{if(g){y(`error putting null on ${f}: ${g}`);return}s.is=null,s.ctx=null,h&&h(null)})})}};return s},be=Ee;var Te=e=>{let t=re(e),o=be(null,t),r=new Map,n=new Map,u=i=>i===null||i===!0||i===!1||typeof i=="string"||T.is(i)||X.is(i),l=i=>{if(u(i))return!0;if(_.is(i)){let a=[];for(let[h,y]of Object.entries(i)){if(h==="_")return"error underscore cannot be used as an item name";if(_.is(y)||u(y)){a.push(h);continue}return`error {${h}:${y}} cannot be converted to graph`}if(a.length!==0)return a}return`error ${i} cannot be converted to a graph`},s=i=>{let a=(d,c,f)=>{t.get(_.put(d,"#",c),async p=>{if(p.err&&console.log(p.err),p.put&&p.put[c]){delete p.put[c]._,delete p.put[c][J];for(let g of Object.keys(p.put[c])){let w=T.is(p.put[c][g]);if(w){let v=await new Promise(m=>{let k=E.random();n.set(k,{chain:[{item:null,soul:w}]}),s(k).next(null,m)});p.put[c][g]=v}}f(p.put[c])}else f(null)})},h=async(d,c,f)=>{if(f||(f=console.log),!o.is)return e.secure?(f(`error putting data on ${d}: user required in secure mode`),null):W(d,c);if(!o.is)return f(`error putting data on ${d}: user not authenticated`),null;let p=await K.sign(c,o.is);return W(d,p.m,p.s,o.is.pub)},y=d=>{let c=n.get(i);c&&typeof c.cb<"u"?c.cb(d):d&&console.log(d),c&&!c.on&&n.delete(i)},b=(d,c)=>{let f=d&&typeof d.get<"u",p=d&&typeof d.put<"u",g=d&&typeof d.on<"u",w=d&&typeof d.off<"u",v=!1,m=n.get(i);for(var k=1;k<m.chain.length;k++)if(m.chain[k].soul===null){v=!0;break}if(v){let{item:S,soul:j}=m.chain[k-1];return t.get({"#":j,".":S},async A=>{if(A.err){console.log(`error getting ${S} on ${j}: ${A.err}`),c&&c(null);return}let x=A.put&&A.put[j];if(x&&typeof x[S]<"u"){let C=T.is(x[S]);if(C)m.chain[k].soul=C,n.set(i,{chain:m.chain,cb:m.cb}),f?s(i).next(null,d.get,c):p?s(i).put(d.put,c):g?s(i).on(d.on,c):w&&s(i).off(c);else if(f)c(x[S]);else if(p){C=E.random();let D={[S]:T.ify(C)},P=await h(j,D,c);if(P===null)return;t.put(P,Q=>{if(Q){c(`error putting ${S} on ${j}: ${Q}`);return}m.chain[k].soul=C,s(i).put(d.put,c)})}else g?(console.log(`error resolving on for ${S} on ${j}`),c(null)):w&&(console.log(`error resolving off for ${S} on ${j}`),c&&c(null))}else p?c(`error ${S} not found on ${j}`):(console.log(`error ${S} not found on ${j}`),c&&c(null))}),!1}return f&&m.chain[m.chain.length-1].item!==null?(m.chain.push({item:null,soul:null}),s(i).next(null,d.get,c),!1):m.chain[m.chain.length-1]};return{get:(d,c,f)=>{if(typeof c=="function"&&(f=c,c=null),d===null||d===""||d==="_"){f&&f(null);return}if(c&&!f){console.log("lex requires a callback function");return}let p=o.ctx?o.ctx:"root";if(i=E.random(),n.set(i,{chain:[{item:d,soul:p}],cb:f}),!f)return s(i);let{soul:g}=b({get:c},y);g&&a(c,g,y)},next:(d,c,f)=>{let p=v=>{f?f(v):y(v)};if(typeof c=="function"&&(f=c,c=null),!i){console.log("please provide a key using get(key)"),p(null);return}if(d===""||d==="_"){p(null);return}if(c&&!f){console.log("lex requires a callback function");return}let g=n.get(i);if(!g)return;if(f&&typeof g.cb>"u"&&(g.cb=f,f=null),d!==null&&g.chain.push({item:d,soul:null}),!g.cb)return s(i);let{soul:w}=b({get:c},p);w&&a(c,w,p)},put:(d,c)=>{let f=m=>{c?c(m):y(m)};if(!i){f("please provide a key using get(key)");return}let p=n.get(i);if(!p)return;if(!p.cb){if(!c)return;p.cb=c,c=null}let g=l(d);if(typeof g=="string"){f(g);return}let{item:w,soul:v}=b({put:d},f);if(v){if(g===!0){t.get({"#":v,".":w},async m=>{if(m.err){console.log(`error getting ${v}: ${m.err}`);return}let k=m.put&&m.put[v]&&m.put[v][w],S=T.is(k);if(!S){let j=await h(v,{[w]:d},f);if(j===null)return;t.put(j,f);return}t.get({"#":S},async j=>{if(j.err){console.log(`error getting ${S}: ${j.err}`);return}if(!j.put||!j.put[S]){console.log(`error ${S} not found`);return}delete j.put[S]._;for(let x of Object.keys(j.put[S])){if(x===J)continue;let C=await new Promise(D=>{let P=E.random();n.set(P,{chain:[{item:x,soul:S}]}),s(P).put(null,D)});if(C){f(C);return}}let A=await h(v,{[w]:d},f);A!==null&&t.put(A,f)})});return}t.get({"#":v,".":w},async m=>{if(m.err){f(`error getting ${v}.${w}: ${m.err}`);return}let k=m.put&&m.put[v]&&m.put[v][w],S=T.is(k);if(!S){let x={[w]:T.ify(E.random())},C=await h(v,x,f);if(C===null)return;t.put(C,D=>{if(D)f(`error putting ${w} on ${v}: ${D}`);else{let P=E.random(),Q=[{item:w,soul:v}];n.set(P,{chain:Q,cb:p.cb}),s(P).put(d)}});return}let j=!1,A={};for(let x of g){let C=await new Promise(D=>{if(_.is(d[x])){let P=E.random();n.set(P,{chain:[{item:x,soul:S}]}),s(P).put(d[x],D)}else j=!0,A[x]=d[x],D(null)});if(C){f(C);return}}if(j){let x=await h(S,A,f);if(x===null)return;t.put(x,f)}else f(null)})}},on:(d,c)=>{if(typeof d=="function"&&(c=d,d=null),!c)return;if(!i){console.log("please provide a key using get(key)"),c(null);return}let{item:f,soul:p}=b({on:d},c);p&&(n.set(i,{chain:[{item:f,soul:p}],on:!0}),r.set(c,()=>s(i).next(null,c)),t.get({"#":p,".":f},g=>{if(g.err){console.log(`error getting ${p}.${f}: ${g.err}`);return}let w=g.put&&g.put[p]&&g.put[p][f],v=T.is(w);v?d?d=_.put(d,"#",v):d={"#":v,".":null}:d?d=_.put(d,"#",p):d={"#":p,".":f},t.on(d,r.get(c))}))},off:d=>{if(!i){console.log("please provide a key using get(key)"),d&&d(null);return}let{item:c,soul:f}=b({off:!0},d);f&&t.get({"#":f,".":c},p=>{if(p.err){console.log(`error getting ${f}.${c}: ${p.err}`);return}let g=p.put&&p.put[f]&&p.put[f][c],w=T.is(g);w?t.off({"#":w},r.get(d)):t.off({"#":f},r.get(d)),r.delete(d),n.delete(i)})},user:d=>(d&&(o.ctx="~"+d),Object.assign(o,s())),wire:t,SEA:K}};return s()},st=Te;export{st as default};
4
+ //# sourceMappingURL=holster.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/utils.js", "../src/dup.js", "../src/get.js", "../src/array.js", "../src/buffer.js", "../src/sea-utils.js", "../src/sea.js", "../src/ham.js", "../src/radix.js", "../src/radisk.js", "../src/store.js", "../src/wire.js", "../src/user.js", "../src/holster.js"],
4
+ "sourcesContent": ["export const num = {\n is: n =>\n !(n instanceof Array) &&\n (n - parseFloat(n) + 1 >= 0 || Infinity === n || -Infinity === n),\n}\n\nexport const obj = {\n is: o => {\n if (!o) return false\n\n return (\n (o instanceof Object && o.constructor === Object) ||\n Object.prototype.toString.call(o).match(/^\\[object (\\w+)\\]$/)[1] ===\n \"Object\"\n )\n },\n map: (list, cb, o) => {\n var keys = Object.keys(list)\n for (let i = 0; i < keys.length; i++) {\n let result = cb(list[keys[i]], keys[i], o)\n if (typeof result !== \"undefined\") return result\n }\n },\n put: (o, key, value) => {\n if (!o) o = {}\n o[key] = value\n return o\n },\n del: (o, key) => {\n if (!o) return\n\n o[key] = null\n delete o[key]\n return o\n },\n}\n\nconst map_soul = (soul, key, o) => {\n // If id is already defined AND we're still looping through the object,\n // then it is considered invalid.\n if (o.id) {\n o.id = false\n return\n }\n\n if (key === \"#\" && typeof soul === \"string\") {\n o.id = soul\n return\n }\n\n // If there exists anything else on the object that isn't the soul,\n // then it is considered invalid.\n o.id = false\n}\n\n// Check if an object is a soul relation, ie {'#': 'UUID'}\nexport const rel = {\n is: value => {\n if (value && value[\"#\"] && !value._ && obj.is(value)) {\n let o = {}\n obj.map(value, map_soul, o)\n if (o.id) return o.id\n }\n\n return false\n },\n // Convert a soul into a relation and return it.\n ify: soul => obj.put({}, \"#\", soul),\n}\n\nexport const userPublicKey = \"_holster_user_public_key\"\n\n// graph converts objects to graph format with updated states,\n// with optional meta data to verify signed data.\nexport const graph = (soul, data, sig, pub) => {\n const g = {[soul]: {_: {\"#\": soul, \">\": {}, s: sig, p: pub}}}\n for (const [key, value] of Object.entries(data)) {\n g[soul][key] = value\n g[soul]._[\">\"][key] = Date.now()\n }\n // If a public key is provided it also needs to be stored on the node to\n // ensure that future updates are only possible with the same public key.\n if (pub) {\n g[soul][userPublicKey] = pub\n g[soul]._[\">\"][userPublicKey] = Date.now()\n }\n return g\n}\n\nexport const match = (lex, key) => {\n // Null is used to match listeners on souls, which don't provide a key.\n if (typeof key === \"undefined\") return lex === null\n\n if (typeof lex === \"undefined\") return true\n\n if (typeof lex === \"string\") return lex === key\n\n if (!obj.is(lex) || !key) return false\n\n const prefix = lex[\"*\"]\n if (prefix) return key.slice(0, prefix.length) === prefix\n\n const gt = lex[\">\"]\n const lt = lex[\"<\"]\n if (gt && lt) return key >= gt && key <= lt\n\n if (gt) return key >= gt\n\n if (lt) return key <= lt\n\n return false\n}\n\nexport const text = {\n random: length => {\n var s = \"\"\n const c = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz\"\n if (!length) length = 24\n for (let i = 0; i < length; i++) {\n s += c.charAt(Math.floor(Math.random() * c.length))\n }\n return s\n },\n}\n", "const Dup = maxAge => {\n // Allow maxAge to be passed in as tests wait on the setTimeout.\n if (!maxAge) maxAge = 9000\n const dup = {store: {}}\n dup.check = id => (dup.store[id] ? dup.track(id) : false)\n dup.track = id => {\n // Keep the liveliness of the message up while it is being received.\n dup.store[id] = Date.now()\n if (!dup.expiry) {\n dup.expiry = setTimeout(() => {\n const now = Date.now()\n Object.keys(dup.store).forEach(id => {\n if (now - dup.store[id] > maxAge) delete dup.store[id]\n })\n dup.expiry = null\n }, maxAge)\n }\n return id\n }\n return dup\n}\n\nexport default Dup\n", "const Get = (lex, graph) => {\n const soul = lex[\"#\"]\n const key = typeof lex[\".\"] === \"string\" ? lex[\".\"] : false\n var node = graph[soul]\n\n // Can only return a node if a key is provided, because the graph may not\n // have all the keys populated for a given soul. This is because Ham.mix\n // only adds incoming changes to the graph.\n if (!node || !key) return\n\n let value = node[key]\n if (!value) return\n\n node = {_: node._, [key]: value}\n node._[\">\"] = {[key]: node._[\">\"][key]}\n return {[soul]: node}\n}\n\nexport default Get\n", "if (typeof btoa === \"undefined\") {\n globalThis.btoa = data => Buffer.from(data, \"binary\").toString(\"base64\")\n globalThis.atob = data => Buffer.from(data, \"base64\").toString(\"binary\")\n}\n\n// This is Array extended to have .toString([\"utf8\"|\"hex\"|\"base64\"])\nfunction SeaArray() {}\n\nObject.assign(SeaArray, {from: Array.from})\nSeaArray.prototype = Object.create(Array.prototype)\nSeaArray.prototype.toString = function (enc, start, end) {\n if (!enc) enc = \"utf8\"\n if (!start) start = 0\n\n const length = this.length\n if (enc === \"hex\") {\n const buf = new Uint8Array(this)\n return [...Array(((end && end + 1) || length) - start).keys()]\n .map(i => buf[i + start].toString(16).padStart(2, \"0\"))\n .join(\"\")\n }\n\n if (enc === \"utf8\") {\n return Array.from({length: (end || length) - start}, (_, i) =>\n String.fromCharCode(this[i + start]),\n ).join(\"\")\n }\n\n if (enc === \"base64\") {\n return btoa(this)\n }\n}\n\nexport default SeaArray\n", "import SeaArray from \"./array.js\"\n\n// This is Buffer implementation used in SEA. Functionality is mostly\n// compatible with NodeJS \"safe-buffer\" and is used for encoding conversions\n// between binary and \"hex\" | \"utf8\" | \"base64\"\n// See documentation and validation for safe implementation in:\n// https://github.com/feross/safe-buffer#update\nfunction SafeBuffer(...props) {\n console.warn(\"new SafeBuffer() is deprecated, please use SafeBuffer.from()\")\n return SafeBuffer.from(...props)\n}\n\nSafeBuffer.prototype = Object.create(Array.prototype)\nObject.assign(SafeBuffer, {\n // (data, enc) where typeof data === \"string\" then\n // enc === \"utf8\"|\"hex\"|\"base64\"\n from() {\n if (!Object.keys(arguments).length || arguments[0] == null) {\n throw new TypeError(\n \"First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.\",\n )\n }\n const input = arguments[0]\n let buf\n if (typeof input === \"string\") {\n const enc = arguments[1] || \"utf8\"\n if (enc === \"hex\") {\n const bytes = input\n .match(/([\\da-fA-F]{2})/g)\n .map(byte => parseInt(byte, 16))\n if (!bytes || !bytes.length) {\n throw new TypeError(\"Invalid first argument for type 'hex'.\")\n }\n buf = SeaArray.from(bytes)\n } else if (enc === \"utf8\" || enc === \"binary\") {\n const length = input.length\n const words = new Uint16Array(length)\n Array.from({length: length}, (_, i) => (words[i] = input.charCodeAt(i)))\n buf = SeaArray.from(words)\n } else if (enc === \"base64\") {\n const dec = atob(input)\n const length = dec.length\n const bytes = new Uint8Array(length)\n Array.from({length: length}, (_, i) => (bytes[i] = dec.charCodeAt(i)))\n buf = SeaArray.from(bytes)\n } else {\n console.info(\"SafeBuffer.from unknown encoding: \" + enc)\n }\n return buf\n }\n const length = input.byteLength ? input.byteLength : input.length\n if (length) {\n let buf\n if (input instanceof ArrayBuffer) {\n buf = new Uint8Array(input)\n }\n const check = SeaArray.from(buf || input)\n return check\n }\n },\n // This is \"safe-buffer.alloc\" sans encoding support\n alloc(length, fill = 0) {\n return SeaArray.from(\n new Uint8Array(Array.from({length: length}, () => fill)),\n )\n },\n // This puts together array of array like members\n concat(arr) {\n // octet array\n if (!Array.isArray(arr)) {\n throw new TypeError(\n \"First argument must be Array containing ArrayBuffer or Uint8Array instances.\",\n )\n }\n return SeaArray.from(\n arr.reduce((ret, item) => ret.concat(Array.from(item)), []),\n )\n },\n})\nSafeBuffer.prototype.from = SafeBuffer.from\nSafeBuffer.prototype.toString = SeaArray.prototype.toString\n\nexport default SafeBuffer\n", "import SafeBuffer from \"./buffer.js\"\n\nconst isNode = typeof document === \"undefined\"\nconst crypto = isNode\n ? (await import(\"node:crypto\")).webcrypto\n : globalThis.crypto\nexport const subtle = crypto.subtle\n\nexport const stringify = data => {\n return typeof data === \"string\" ? data : JSON.stringify(data)\n}\n\nexport const parse = text => {\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n}\n\nexport const random = length => {\n const array = new Uint8Array(SafeBuffer.alloc(length))\n return SafeBuffer.from(crypto.getRandomValues(array))\n}\n\nexport const jwk = (pub, priv) => {\n const [x, y] = pub.split(\".\")\n const ops = priv ? [\"sign\"] : [\"verify\"]\n return {\n kty: \"EC\",\n crv: \"P-256\",\n x: x,\n y: y,\n d: priv,\n ext: true,\n key_ops: ops,\n }\n}\n\nexport const sha256 = async data => {\n const hash = await subtle.digest(\n {name: \"SHA-256\"},\n new TextEncoder().encode(stringify(data)),\n )\n return SafeBuffer.from(hash)\n}\n\nexport const aeskey = async (key, salt) => {\n const combined = key + salt.toString(\"utf8\")\n const hash = SafeBuffer.from(await sha256(combined), \"binary\")\n const jwk = keyToJwk(hash)\n return await subtle.importKey(\"jwk\", jwk, {name: \"AES-GCM\"}, false, [\n \"encrypt\",\n \"decrypt\",\n ])\n}\n\nconst keyToJwk = key => {\n const k = key\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/\\=/g, \"\")\n return {kty: \"oct\", k: k, ext: false, alg: \"A256GCM\"}\n}\n", "import {userPublicKey} from \"./utils.js\"\nimport * as utils from \"./sea-utils.js\"\nimport SafeBuffer from \"./buffer.js\"\n\n// Security, Encryption, and Authorization: SEA.js from GunDB.\nconst SEA = {\n pair: async cb => {\n // ECDSA keys for signing/verifying.\n const ecdsa = await utils.subtle\n .generateKey({name: \"ECDSA\", namedCurve: \"P-256\"}, true, [\n \"sign\",\n \"verify\",\n ])\n .then(async keys => {\n const pub = await utils.subtle.exportKey(\"jwk\", keys.publicKey)\n return {\n priv: (await utils.subtle.exportKey(\"jwk\", keys.privateKey)).d,\n pub: pub.x + \".\" + pub.y,\n }\n })\n\n // ECDH keys for encryption/decryption.\n const ecdh = await utils.subtle\n .generateKey({name: \"ECDH\", namedCurve: \"P-256\"}, true, [\"deriveKey\"])\n .then(async keys => {\n const pub = await utils.subtle.exportKey(\"jwk\", keys.publicKey)\n return {\n epriv: (await utils.subtle.exportKey(\"jwk\", keys.privateKey)).d,\n epub: pub.x + \".\" + pub.y,\n }\n })\n\n const pair = {\n pub: ecdsa.pub,\n priv: ecdsa.priv,\n epub: ecdh.epub,\n epriv: ecdh.epriv,\n }\n if (cb) cb(pair)\n return pair\n },\n encrypt: async (data, pair, cb) => {\n if (!pair || !pair.epriv) {\n if (cb) cb(null)\n return null\n }\n\n const rand = {s: utils.random(9), iv: utils.random(15)}\n const ct = await utils.aeskey(pair.epriv, rand.s).then(aes => {\n return utils.subtle.encrypt(\n {\n name: \"AES-GCM\",\n iv: new Uint8Array(rand.iv),\n },\n aes,\n new TextEncoder().encode(utils.stringify(data)),\n )\n })\n const enc = {\n ct: SafeBuffer.from(ct, \"binary\").toString(\"base64\"),\n iv: rand.iv.toString(\"base64\"),\n s: rand.s.toString(\"base64\"),\n }\n if (cb) cb(enc)\n return enc\n },\n decrypt: async (enc, pair, cb) => {\n if (!enc || !enc.ct || !enc.iv || !enc.s || !pair || !pair.epriv) {\n if (cb) cb(null)\n return null\n }\n\n const data = {\n ct: SafeBuffer.from(enc.ct, \"base64\"),\n iv: SafeBuffer.from(enc.iv, \"base64\"),\n s: SafeBuffer.from(enc.s, \"base64\"),\n }\n try {\n const ct = await utils.aeskey(pair.epriv, data.s).then(aes => {\n return utils.subtle.decrypt(\n {\n name: \"AES-GCM\",\n iv: new Uint8Array(data.iv),\n tagLength: 128,\n },\n aes,\n new Uint8Array(data.ct),\n )\n })\n const dec = utils.parse(new TextDecoder(\"utf8\").decode(ct))\n if (cb) cb(dec)\n return dec\n } catch (err) {\n // An error will be thrown if the wrong key is used.\n if (cb) cb(null)\n return null\n }\n },\n verify: async (data, pair, cb) => {\n if (!pair || !pair.pub) {\n if (cb) cb(null)\n return null\n }\n\n const signed = utils.parse(data)\n const key = await utils.subtle.importKey(\n \"jwk\",\n utils.jwk(pair.pub),\n {name: \"ECDSA\", namedCurve: \"P-256\"},\n false,\n [\"verify\"],\n )\n\n let msg = {}\n if (typeof signed.m === \"string\") {\n msg = signed.m\n } else {\n // Allow data to be passed in with graph meta data,\n // (which should not be part of signature, so not verified).\n for (const k of Object.keys(signed.m)) {\n if (k !== \"_\" && k != userPublicKey) msg[k] = signed.m[k]\n }\n }\n const hash = await utils.sha256(msg)\n const sig = new Uint8Array(SafeBuffer.from(signed.s, \"base64\"))\n const alg = {name: \"ECDSA\", hash: {name: \"SHA-256\"}}\n if (await utils.subtle.verify(alg, key, sig, new Uint8Array(hash))) {\n const verified = utils.parse(signed.m)\n if (cb) cb(verified)\n return verified\n }\n\n if (cb) cb(null)\n return null\n },\n sign: async (data, pair, cb) => {\n if (!pair || !pair.pub || !pair.priv) {\n if (cb) cb(null)\n return null\n }\n\n const msg = utils.parse(data)\n const hash = await utils.sha256(msg)\n const jwk = utils.jwk(pair.pub, pair.priv)\n const alg = {name: \"ECDSA\", namedCurve: \"P-256\"}\n const sig = await utils.subtle\n .importKey(\"jwk\", jwk, alg, false, [\"sign\"])\n .then(key =>\n utils.subtle.sign(\n {name: \"ECDSA\", hash: {name: \"SHA-256\"}},\n key,\n new Uint8Array(hash),\n ),\n )\n const signed = {\n m: msg,\n s: SafeBuffer.from(sig, \"binary\").toString(\"base64\"),\n }\n\n if (cb) cb(signed)\n return signed\n },\n work: async (data, salt, cb) => {\n if (typeof salt === \"function\") {\n cb = salt\n salt = undefined\n }\n if (typeof salt === \"undefined\") salt = utils.random(9)\n\n const key = await utils.subtle.importKey(\n \"raw\",\n new TextEncoder().encode(utils.stringify(data)),\n {name: \"PBKDF2\"},\n false,\n [\"deriveBits\"],\n )\n const alg = {\n name: \"PBKDF2\",\n iterations: 100000,\n salt: new TextEncoder().encode(salt),\n hash: {name: \"SHA-256\"},\n }\n const work = await utils.subtle.deriveBits(alg, key, 512)\n // Use \"pair\" format so that work can be used as epriv by decrypt.\n const pair = {epriv: SafeBuffer.from(work, \"binary\").toString(\"base64\")}\n if (cb) cb(pair)\n return pair\n },\n secret: async (to, from, cb) => {\n if (!to || !to.epub || !from || !from.epub || !from.epriv) {\n if (cb) cb(null)\n return null\n }\n\n const alg = {name: \"ECDH\", namedCurve: \"P-256\"}\n const pub = utils.jwk(to.epub)\n const pubKey = await utils.subtle.importKey(\"jwk\", pub, alg, true, [])\n const priv = utils.jwk(from.epub, from.epriv, false)\n // utils.jwk provides default key_ops but it shouldn't be used here.\n delete priv.key_ops\n const derived = await utils.subtle\n .importKey(\"jwk\", priv, alg, false, [\"deriveBits\"])\n .then(async key => {\n const derivedBits = await utils.subtle.deriveBits(\n {public: pubKey, name: \"ECDH\", namedCurve: \"P-256\"},\n key,\n 256,\n )\n const derivedKey = await utils.subtle.importKey(\n \"raw\",\n new Uint8Array(derivedBits),\n {name: \"AES-GCM\", length: 256},\n true,\n [\"encrypt\", \"decrypt\"],\n )\n return utils.subtle.exportKey(\"jwk\", derivedKey).then(({k}) => k)\n })\n // Use \"pair\" format so that secret can be used as epriv by encrypt.\n if (cb) cb({epriv: derived})\n return {epriv: derived}\n },\n}\n\nexport default SEA\n", "import * as utils from \"./utils.js\"\nimport SEA from \"./sea.js\"\n\n// state and value are the incoming changes.\n// currentState and currentValue are the current graph data.\nconst Ham = (state, currentState, value, currentValue) => {\n if (state < currentState) return {historical: true}\n\n if (state > currentState) return {incoming: true}\n\n // state is equal to currentState, lexically compare to resolve conflict.\n if (typeof value !== \"string\") {\n value = JSON.stringify(value) || \"\"\n }\n if (typeof currentValue !== \"string\") {\n currentValue = JSON.stringify(currentValue) || \"\"\n }\n // No update required.\n if (value === currentValue) return {state: true}\n\n // Keep the current value.\n if (value < currentValue) return {current: true}\n\n // Otherwise update using the incoming value.\n return {incoming: true}\n}\n\nHam.mix = async (change, graph, secure, listen) => {\n var machine = Date.now()\n var now = {}\n var defer = {}\n let wait = 0\n\n for (const soul of Object.keys(change)) {\n const node = change[soul]\n let updated = false\n let alias = false\n let nodeWait = 0\n let pub = \"\"\n let verify = secure\n\n if (!node || !node._) continue\n\n // If a signature and public key are provided then always verify.\n if (node._.s && node._.p) verify = true\n\n // Special case if soul starts with \"~\". Node must be system data ie,\n // ~@alias or ~publickey. For aliases, key and value must be a self\n // identifying rel. For public keys, data needs to be signed and verified.\n // (This is also true for any data when the secure flag is used.)\n if (soul.length > 1 && soul[0] === \"~\") {\n if (soul[1] === \"@\") {\n alias = true\n verify = false\n } else {\n if (node._.p && soul != \"~\" + node._.p) {\n console.log(`error public key does not match for soul: ${soul}`)\n continue\n }\n\n // Need to be able to create public key data before a user is\n // authenticated, in this case the soul is the public key which\n // should've been used to sign the data.\n node._.p = soul.slice(1)\n verify = true\n }\n }\n if (verify) {\n if (!node._.s || !node._.p) {\n console.log(\"error signature and public key required to verify data\")\n continue\n }\n\n if (!(await SEA.verify({m: node, s: node._.s}, {pub: node._.p}))) {\n console.log(`error could not verify soul: ${soul}`)\n continue\n }\n }\n\n for (const key of Object.keys(node)) {\n if (key === \"_\") continue\n\n const value = node[key]\n const state = node._[\">\"][key]\n const currentValue = (graph[soul] || {})[key]\n const currentState = (graph[soul] || {_: {\">\": {}}})._[\">\"][key] || 0\n\n if (alias && key !== utils.rel.is(value)) continue\n\n // Defer the update if ahead of machine time.\n const skew = state - machine\n if (skew > 0) {\n // Ignore update if ahead by more than 24 hours.\n if (skew > 86400000) continue\n\n // Wait the shortest difference before trying the updates again.\n if (wait === 0 || skew < wait) wait = nodeWait = skew\n if (!defer[soul]) {\n defer[soul] = {_: {\"#\": soul, \">\": {}, s: node._.s, p: node._.p}}\n }\n defer[soul][key] = value\n defer[soul]._[\">\"][key] = state\n } else {\n const result = Ham(state, currentState, value, currentValue)\n if (result.incoming) {\n if (!now[soul]) {\n now[soul] = {_: {\"#\": soul, \">\": {}, s: node._.s, p: node._.p}}\n }\n // TODO: graph should not just grow indefintitely in memory.\n // Need to have a max size after which start dropping the oldest state\n // Do something similar to Dup which can handle deletes?\n if (!graph[soul]) {\n graph[soul] = {_: {\"#\": soul, \">\": {}, s: node._.s, p: node._.p}}\n }\n graph[soul][key] = now[soul][key] = value\n graph[soul]._[\">\"][key] = now[soul]._[\">\"][key] = state\n // Call event listeners for update on key, mix is called before\n // put has finished so wait for what could be multiple nested\n // updates on a node.\n if (listen[soul]) {\n setTimeout(() => {\n if (listen[soul]) {\n listen[soul]\n .filter(l => utils.match(l[\".\"], key))\n .forEach(l => l.cb())\n }\n }, 100)\n }\n updated = true\n }\n }\n }\n\n if (verify && nodeWait !== 0 && now[soul]) {\n // Secure updates can't be split, so move now to deferred as well.\n Object.assign(defer[soul], now[soul])\n delete now[soul]\n }\n // Call event listeners for update on soul.\n if (updated && listen[soul]) {\n setTimeout(() => {\n if (listen[soul]) {\n listen[soul].filter(l => utils.match(l[\".\"])).forEach(l => l.cb())\n }\n }, 100)\n }\n }\n return {now: now, defer: defer, wait: wait}\n}\n\nexport default Ham\n", "import * as utils from \"./utils.js\"\n\n// ASCII character for group separator.\nconst group = String.fromCharCode(29)\n// ASCII character for record separator.\nconst record = String.fromCharCode(30)\n\nconst Radix = () => {\n const radix = (keys, value, tree) => {\n if (!tree) {\n if (!radix[group]) radix[group] = {}\n tree = radix[group]\n }\n if (!keys) return tree\n\n let i = 0\n let tmp = {}\n let key = keys[i]\n const max = keys.length - 1\n const noValue = typeof value === \"undefined\"\n // Find a matching value using the shortest string from keys.\n let found = tree[key]\n while (!found && i < max) {\n key += keys[++i]\n found = tree[key]\n }\n\n if (!found) {\n // If not found from the provided keys try matching with an existing key.\n const result = utils.obj.map(tree, (hasValue, hasKey) => {\n let j = 0\n let matchingKey = \"\"\n while (hasKey[j] === keys[j]) {\n matchingKey += hasKey[j++]\n }\n if (matchingKey) {\n if (noValue) {\n // matchingKey has to be as long as the original keys when reading.\n if (j <= max) return\n\n tmp[hasKey.slice(j)] = hasValue\n return hasValue\n }\n\n let replace = {\n [hasKey.slice(j)]: hasValue,\n [keys.slice(j)]: {[record]: value},\n }\n tree[matchingKey] = {[group]: replace}\n delete tree[hasKey]\n return true\n }\n })\n if (!result) {\n if (noValue) return\n\n if (!tree[key]) tree[key] = {}\n tree[key][record] = value\n } else if (noValue) {\n return tmp\n }\n } else if (i === max) {\n // If no value use the key provided to return a whole group or record.\n if (noValue) {\n // If an individual record isn't found then return the whole group.\n return typeof found[record] === \"undefined\"\n ? found[group]\n : found[record]\n }\n // Otherwise create a new record at the provided key for value.\n found[record] = value\n } else {\n // Found at a shorter key, try again.\n if (!found[group] && !noValue) found[group] = {}\n return radix(keys.slice(++i), value, found[group])\n }\n }\n return radix\n}\n\nRadix.map = function map(radix, cb, opt, pre) {\n if (!pre) pre = []\n var tree = radix[group] || radix\n var keys = Object.keys(tree).sort()\n var u\n\n for (let i = 0; i < keys.length; i++) {\n let key = keys[i]\n let found = tree[key]\n let tmp = found[record]\n if (typeof tmp !== \"undefined\") {\n tmp = cb(tmp, pre.join(\"\") + key, key, pre)\n if (typeof tmp !== \"undefined\") return tmp\n } else if (opt) {\n cb(u, pre.join(\"\"), key, pre)\n }\n if (found[group]) {\n pre.push(key)\n tmp = map(found[group], cb, opt, pre)\n if (typeof tmp !== \"undefined\") return tmp\n pre.pop()\n }\n }\n}\n\nexport default Radix\n", "import Radix from \"./radix.js\"\nimport * as utils from \"./utils.js\"\n\n// ASCII character for end of text.\nconst etx = String.fromCharCode(3)\n// ASCII character for enquiry.\nconst enq = String.fromCharCode(5)\n// ASCII character for unit separator.\nconst unit = String.fromCharCode(31)\n\n// Radisk provides access to a radix tree that is stored in the provided\n// opt.store interface.\nconst Radisk = opt => {\n var u\n var cache = null\n\n if (!opt) opt = {}\n if (!opt.log) opt.log = console.log\n if (!opt.batch) opt.batch = 10 * 1000\n if (!opt.write) opt.write = 1 // Wait time before write in milliseconds.\n if (!opt.size) opt.size = 1024 * 1024 // File size on disk, default 1MB.\n if (!opt.store) {\n opt.log(\n \"Radisk needs `store` interface with `{get: fn, put: fn, list: fn}`\",\n )\n return\n }\n if (!opt.store.get) {\n opt.log(\"Radisk needs `store.get` interface with `(file, cb)`\")\n return\n }\n if (!opt.store.put) {\n opt.log(\"Radisk needs `store.put` interface with `(file, data, cb)`\")\n return\n }\n if (!opt.store.list) {\n opt.log(\"Radisk needs a streaming `store.list` interface with `(cb)`\")\n return\n }\n\n // Any and all storage adapters should:\n // 1. Because writing to disk takes time, we should batch data to disk.\n // This improves performance, and reduces potential disk corruption.\n // 2. If a batch exceeds a certain number of writes, we should immediately\n // write to disk when physically possible. This caps total performance,\n // but reduces potential loss.\n const radisk = (key, value, cb) => {\n key = \"\" + key\n\n // If no value is provided then the second parameter is the callback\n // function. Read value from memory or disk and call callback with it.\n if (typeof value === \"function\") {\n cb = value\n value = radisk.batch(key)\n if (typeof value !== \"undefined\") {\n return cb(u, value)\n }\n\n if (radisk.thrash.at) {\n value = radisk.thrash.at(key)\n if (typeof value !== \"undefined\") {\n return cb(u, value)\n }\n }\n\n return radisk.read(key, cb)\n }\n\n // Otherwise store the value provided.\n radisk.batch(key, value)\n if (cb) {\n radisk.batch.acks.push(cb)\n }\n // Don't wait if we have batched too many.\n if (++radisk.batch.ed >= opt.batch) {\n return radisk.thrash()\n }\n\n // Otherwise wait for more updates before writing.\n clearTimeout(radisk.batch.timeout)\n radisk.batch.timeout = setTimeout(radisk.thrash, opt.write)\n }\n\n radisk.batch = Radix()\n radisk.batch.acks = []\n radisk.batch.ed = 0\n\n radisk.thrash = () => {\n if (radisk.thrash.ing) {\n return (radisk.thrash.more = true)\n }\n\n clearTimeout(radisk.batch.timeout)\n radisk.thrash.more = false\n radisk.thrash.ing = true\n var batch = (radisk.thrash.at = radisk.batch)\n radisk.batch = null\n radisk.batch = Radix()\n radisk.batch.acks = []\n radisk.batch.ed = 0\n let i = 0\n radisk.save(batch, err => {\n // This is to ignore multiple callbacks from radisk.save calling\n // radisk.write? It looks like multiple callbacks will be made if a\n // file needs to be split.\n if (++i > 1) return\n\n if (err) opt.log(err)\n batch.acks.forEach(cb => cb(err))\n radisk.thrash.at = null\n radisk.thrash.ing = false\n if (radisk.thrash.more) radisk.thrash()\n })\n }\n\n // 1. Find the first radix item in memory\n // 2. Use that as the starting index in the directory of files\n // 3. Find the first file that is lexically larger than it\n // 4. Read the previous file into memory\n // 5. Scan through in memory radix for all values lexically less than limit\n // 6. Merge and write all of those to the in-memory file and back to disk\n // 7. If file is to large then split. More details needed here\n radisk.save = (rad, cb) => {\n const save = {\n find: (tree, key) => {\n // This is false for any key until save.start is set to an initial key.\n if (key < save.start) return\n\n save.start = key\n opt.store.list(save.lex)\n return true\n },\n lex: file => {\n if (!file || file > save.start) {\n save.end = file\n // ! is used as the first file name as it's the first printable\n // character, so always matches as lexically less than any node.\n save.mix(save.file || \"!\", save.start, save.end)\n return true\n }\n\n save.file = file\n },\n mix: (file, start, end) => {\n save.start = save.end = save.file = u\n radisk.parse(file, (err, disk) => {\n if (err) return cb(err)\n\n Radix.map(rad, (value, key) => {\n if (key < start) return\n\n if (end && end < key) {\n save.start = key\n return save.start\n }\n\n disk(key, value)\n })\n radisk.write(file, disk, save.next)\n })\n },\n next: err => {\n if (err) return cb(err)\n\n if (save.start) return Radix.map(rad, save.find)\n\n cb(err)\n },\n }\n Radix.map(rad, save.find)\n }\n\n radisk.write = (file, rad, cb) => {\n // Invalidate cache on write.\n cache = null\n const write = {\n text: \"\",\n count: 0,\n file: file,\n each: (value, key, k, pre) => {\n write.count++\n var enc =\n Radisk.encode(pre.length) +\n \"#\" +\n Radisk.encode(k) +\n (typeof value === \"undefined\" ? \"\" : \"=\" + Radisk.encode(value)) +\n \"\\n\"\n // Cannot split the file if only have one entry to write.\n if (write.count > 1 && write.text.length + enc.length > opt.size) {\n write.text = \"\"\n // Otherwise split the entries in half.\n write.limit = Math.ceil(write.count / 2)\n write.count = 0\n write.sub = Radix()\n Radix.map(rad, write.slice)\n return true\n }\n\n write.text += enc\n },\n put: () => {\n opt.store.put(file, write.text, cb)\n },\n slice: (value, key) => {\n if (key < write.file) return\n\n if (++write.count > write.limit) {\n var name = write.file\n // Use only the soul of the key as the filename so that all\n // properties of a soul are written to the same file.\n let end = key.indexOf(enq)\n if (end === -1) {\n write.file = key\n } else {\n write.file = key.substring(0, end)\n }\n // write.limit can be reached after already writing properties of\n // the current node, so remove it from write.sub before writing to\n // disk so that it's not duplicated across files.\n write.sub(write.file, null)\n write.count = 0\n radisk.write(name, write.sub, write.next)\n return true\n }\n\n write.sub(key, value)\n },\n next: err => {\n if (err) return cb(err)\n\n write.sub = Radix()\n if (!Radix.map(rad, write.slice)) {\n radisk.write(write.file, write.sub, cb)\n }\n },\n }\n // If Radix.map doesn't return true when called with write.each as a\n // callback then didn't need to split the data. The accumulated write.text\n // can then be stored with write.put().\n if (!Radix.map(rad, write.each, true)) write.put()\n }\n\n radisk.read = (key, cb) => {\n if (cache) {\n let value = cache(key)\n if (typeof value !== \"undefined\") return cb(u, value)\n }\n // Only the soul of the key is compared to filenames (see radisk.write).\n let soul = key\n let end = key.indexOf(enq)\n if (end !== -1) {\n soul = key.substring(0, end)\n }\n\n const read = {\n lex: file => {\n // store.list should call lex without a file last, which means all file\n // names were compared to soul, so the current read.file is ok to use.\n if (!file) {\n if (!read.file) {\n cb(\"no file found\", u)\n return\n }\n\n radisk.parse(read.file, read.it)\n return\n }\n\n // Want the filename closest to soul.\n if (file > soul || file < read.file) return\n\n read.file = file\n },\n it: (err, disk) => {\n if (err) opt.log(err)\n if (disk) {\n cache = disk\n read.value = disk(key)\n }\n cb(err, read.value)\n },\n }\n opt.store.list(read.lex)\n }\n\n // Let us start by assuming we are the only process that is\n // changing the directory or bucket. Not because we do not want\n // to be multi-process/machine, but because we want to experiment\n // with how much performance and scale we can get out of only one.\n // Then we can work on the harder problem of being multi-process.\n radisk.parse = (file, cb) => {\n const parse = {\n disk: Radix(),\n read: (err, data) => {\n if (err) return cb(err)\n\n if (!data) return cb(u, parse.disk)\n\n let pre = []\n // Work though data by splitting into 3 values. The first value says\n // if the second value is one of: the radix level for a key, the key\n // iteself, or a value. The third is the rest of the data to work with.\n let tmp = parse.split(data)\n while (tmp) {\n let key\n let value\n let i = tmp[1]\n tmp = parse.split(tmp[2]) || \"\"\n if (tmp[0] === \"#\") {\n key = tmp[1]\n pre = pre.slice(0, i)\n if (i <= pre.length) pre.push(key)\n }\n tmp = parse.split(tmp[2]) || \"\"\n if (tmp[0] === \"\\n\") continue\n\n if (tmp[0] === \"=\") value = tmp[1]\n if (typeof key !== \"undefined\" && typeof value !== \"undefined\") {\n parse.disk(pre.join(\"\"), value)\n }\n tmp = parse.split(tmp[2])\n }\n cb(u, parse.disk)\n },\n split: data => {\n if (!data) return\n\n let i = -1\n let a = \"\"\n let c = null\n while ((c = data[++i])) {\n if (c === unit) break\n\n a += c\n }\n let o = {}\n if (c) {\n return [a, Radisk.decode(data.slice(i), o), data.slice(i + o.i)]\n }\n },\n }\n opt.store.get(file, parse.read)\n }\n\n return radisk\n}\n\nRadisk.encode = data => {\n // A key should be passed in as a string to encode, a value can optionally be\n // an array of 2 items to include the value's state, as is done by store.js.\n let state = \"\"\n if (data instanceof Array && data.length === 2) {\n state = etx + data[1]\n data = data[0]\n }\n\n if (typeof data === \"string\") {\n let i = 0\n let current = null\n let text = unit\n while ((current = data[i++])) {\n if (current === unit) text += unit\n }\n return text + '\"' + data + state + unit\n }\n\n const rel = utils.rel.is(data)\n if (rel) return unit + \"#\" + rel + state + unit\n\n if (utils.num.is(data)) return unit + \"+\" + (data || 0) + state + unit\n\n if (data === true) return unit + \"+\" + state + unit\n\n if (data === false) return unit + \"-\" + state + unit\n\n if (data === null) return unit + \" \" + state + unit\n}\n\nRadisk.decode = (data, obj) => {\n var text = \"\"\n var i = -1\n var n = 0\n var current = null\n var previous = null\n if (data[0] !== unit) return\n\n // Find a control character previous to the text we want, skipping\n // consecutive unit separator characters at the beginning of the data.\n while ((current = data[++i])) {\n if (previous) {\n if (current === unit) {\n if (--n <= 0) break\n }\n text += current\n } else if (current === unit) {\n n++\n } else {\n previous = current || true\n }\n }\n\n if (obj) obj.i = i + 1\n\n let [value, state] = text.split(etx)\n if (!state) {\n if (previous === '\"') return text\n\n if (previous === \"#\") return utils.rel.ify(text)\n\n if (previous === \"+\") {\n if (text.length === 0) return true\n\n return parseFloat(text)\n }\n\n if (previous === \"-\") return false\n\n if (previous === \" \") return null\n } else {\n state = parseFloat(state)\n // If state was found then return an array.\n if (previous === '\"') return [value, state]\n\n if (previous === \"#\") return [utils.rel.ify(value), state]\n\n if (previous === \"+\") {\n if (value.length === 0) return [true, state]\n\n return [parseFloat(value), state]\n }\n\n if (previous === \"-\") return [false, state]\n\n if (previous === \" \") return [null, state]\n }\n}\n\nexport default Radisk\n", "import Radisk from \"./radisk.js\"\nimport Radix from \"./radix.js\"\nimport * as utils from \"./utils.js\"\n\nconst isNode = typeof document === \"undefined\"\nconst fs = isNode ? await import(\"node:fs\") : undefined\n\n// ASCII character for enquiry.\nconst enq = String.fromCharCode(5)\n// ASCII character for unit separator.\nconst unit = String.fromCharCode(31)\n// On-disk root node format.\nconst root = unit + \"+0\" + unit + \"#\" + unit + '\"root' + unit\n\nconst fileSystem = opt => {\n const dir = opt.file\n\n if (isNode) {\n if (!fs.existsSync(dir)) fs.mkdirSync(dir)\n if (!fs.existsSync(dir + \"/!\")) fs.writeFileSync(dir + \"/!\", root)\n\n return {\n get: (file, cb) => {\n fs.readFile(dir + \"/\" + file, (err, data) => {\n if (err) {\n if (err.code === \"ENOENT\") {\n cb()\n return\n }\n\n console.log(\"fs.readFile error:\", err)\n }\n if (data) data = data.toString()\n cb(err, data)\n })\n },\n put: (file, data, cb) => {\n var random = Math.random().toString(36).slice(-9)\n // Don't put tmp files under dir so that they're not listed.\n var tmp = file + \".\" + random + \".tmp\"\n fs.writeFile(tmp, data, err => {\n if (err) {\n cb(err)\n return\n }\n\n fs.rename(tmp, dir + \"/\" + file, cb)\n })\n },\n list: cb => {\n fs.readdir(dir, (err, files) => {\n files.forEach(cb)\n cb()\n })\n },\n }\n }\n\n if (opt.indexedDB) {\n let db\n const o = indexedDB.open(dir, 1)\n o.onupgradeneeded = event => {\n event.target.result.createObjectStore(dir)\n }\n o.onerror = event => {\n console.log(event)\n }\n o.onsuccess = () => {\n db = o.result\n // Create the root node if it doesn't exist.\n if (db) {\n const tx = db.transaction([dir], \"readonly\")\n const req = tx.objectStore(dir).getKey(\"!\")\n req.onerror = () => {\n console.log(`error getting key ${dir}/!`)\n }\n req.onsuccess = () => {\n if (!req.result) {\n const tx = db.transaction([dir], \"readwrite\")\n const req = tx.objectStore(dir).put(root, \"!\")\n req.onerror = () => {\n console.log(`error putting root on ${dir}/!`)\n }\n }\n }\n } else {\n console.log(\"error indexedDB not available\")\n }\n }\n\n return {\n get: (file, cb) => {\n if (db) {\n const tx = db.transaction([dir], \"readonly\")\n const req = tx.objectStore(dir).get(file)\n req.onerror = () => {\n console.log(`error getting ${dir}/${file}`)\n }\n req.onsuccess = () => {\n cb(null, req.result)\n }\n } else {\n cb(\"error indexedDB not available\")\n }\n },\n put: (file, data, cb) => {\n if (db) {\n const tx = db.transaction([dir], \"readwrite\")\n const req = tx.objectStore(dir).put(data, file)\n req.onerror = () => {\n console.log(`error putting data on ${dir}/${file}`)\n }\n req.onsuccess = () => {\n cb(null)\n }\n } else {\n cb(\"error indexedDB not available\")\n }\n },\n list: cb => {\n if (db) {\n const tx = db.transaction([dir], \"readonly\")\n const req = tx.objectStore(dir).getAllKeys()\n req.onerror = () => console.log(\"error getting keys for\", dir)\n req.onsuccess = () => {\n req.result.forEach(cb)\n cb()\n }\n } else {\n console.log(\"error indexedDB not available\")\n cb()\n }\n },\n }\n }\n\n // No browser storage.\n return {\n get: (file, cb) => {\n cb(null, root)\n },\n put: (file, data, cb) => {\n cb(null)\n },\n list: cb => {\n cb(\"!\")\n cb()\n },\n }\n}\n\n// Store provides get and put methods that can access radisk.\nconst Store = opt => {\n if (!utils.obj.is(opt)) opt = {}\n opt.file = String(opt.file || \"radata\")\n if (!opt.store) opt.store = fileSystem(opt)\n const radisk = Radisk(opt)\n\n return {\n get: (lex, cb) => {\n if (!lex) {\n cb(\"lex required\")\n return\n }\n\n var soul = lex[\"#\"]\n var key = typeof lex[\".\"] === \"string\" ? lex[\".\"] : \"\"\n var node\n const each = (value, key) => {\n if (!utils.match(lex[\".\"], key)) return\n\n if (!node) node = {_: {\"#\": soul, \">\": {}}}\n node[key] = value[0]\n node._[\">\"][key] = value[1]\n }\n\n radisk(soul + enq + key, (err, value) => {\n let graph\n if (utils.obj.is(value)) {\n Radix.map(value, each)\n if (!node) each(value, key)\n graph = {[soul]: node}\n } else if (value) {\n each(value, key)\n graph = {[soul]: node}\n }\n cb(err, graph)\n })\n },\n put: (graph, cb) => {\n if (!graph) {\n cb(\"graph required\")\n return\n }\n\n var count = 0\n const ack = err => {\n count--\n if (ack.err) return\n\n ack.err = err\n if (ack.err) {\n cb(ack.err)\n return\n }\n\n if (count === 0) cb(null)\n }\n\n Object.keys(graph).forEach(soul => {\n var node = graph[soul]\n Object.keys(node).forEach(key => {\n if (key === \"_\") return\n\n count++\n let value = node[key]\n let state = node._[\">\"][key]\n radisk(soul + enq + key, [value, state], ack)\n })\n })\n },\n }\n}\n\nexport default Store\n", "import Dup from \"./dup.js\"\nimport Get from \"./get.js\"\nimport Ham from \"./ham.js\"\nimport Store from \"./store.js\"\nimport * as utils from \"./utils.js\"\n\nconst isNode = typeof document === \"undefined\"\n\nconst wsModule = isNode ? await import(\"ws\") : undefined\n\nif (typeof globalThis.WebSocket === \"undefined\") {\n globalThis.WebSocket = wsModule?.WebSocket\n}\n\n// Wire starts a websocket client or server and returns get and put methods\n// for access to the wire spec and storage.\nconst Wire = opt => {\n if (!utils.obj.is(opt)) opt = {}\n\n const dup = Dup(opt.maxAge)\n const store = Store(opt)\n const graph = {}\n const queue = {}\n const listen = {}\n\n // The check function is required because user data must provide a public key\n // so that it can be verified. The public key might verify the provided\n // signature but not actually match the user under which the data is being\n // stored. To avoid this, the current data on a soul needs to be checked to\n // make sure the stored public key matches the one provided with the update.\n const check = async (data, send, cb) => {\n for (const soul of Object.keys(data)) {\n const msg = await new Promise(res => {\n getWithCallback({\"#\": soul}, res, send)\n })\n if (msg.err) {\n if (cb) cb(msg.err)\n return false\n }\n\n const node = data[soul]\n const pub = node._ ? node._.p : undefined\n const key = utils.userPublicKey\n // If there is no current node then the data is ok to write without\n // matching public keys, as the provided soul also needs a rel on the\n // parent node which then also requires checking. Otherwise publc keys\n // need to match for existing data.\n if (!msg.put || !msg.put[soul] || msg.put[soul][key] === pub) {\n continue\n }\n\n // If a soul exists but does not have a public key, then one should not be\n // added because the node is not user data. The above check fails in this\n // case if a public key is provided. Note that this is only an error case\n // if called via the API, which is when a callback is provided here.\n // (The wire spec can fetch and put data on the wire without a signature\n // or public key and this can be ignored.)\n if (cb) {\n cb(`error in wire check public key does not match for soul: ${soul}`)\n }\n return false\n }\n\n return true\n }\n\n const get = (msg, send) => {\n const ack = Get(msg.get, graph)\n if (ack) {\n send(\n JSON.stringify({\n \"#\": dup.track(utils.text.random(9)),\n \"@\": msg[\"#\"],\n put: ack,\n }),\n )\n } else {\n store.get(msg.get, (err, ack) => {\n send(\n JSON.stringify({\n \"#\": dup.track(utils.text.random(9)),\n \"@\": msg[\"#\"],\n put: ack,\n err: err,\n }),\n )\n })\n }\n }\n\n const put = async (msg, send) => {\n // Store updates returned from Ham.mix and defer updates if required.\n const update = await Ham.mix(msg.put, graph, opt.secure, listen)\n if (Object.keys(update.now).length) {\n if (!(await check(update.now, send))) return\n\n store.put(update.now, err => {\n send(\n JSON.stringify({\n \"#\": dup.track(utils.text.random(9)),\n \"@\": msg[\"#\"],\n err: err,\n }),\n )\n })\n }\n if (Object.keys(update.defer).length) {\n setTimeout(() => put({put: update.defer}, send), update.wait)\n }\n }\n\n const getWithCallback = (lex, cb, send, opt) => {\n if (!cb) return\n\n if (!utils.obj.is(opt)) opt = {}\n const ack = Get(lex, graph)\n if (ack) {\n cb({put: ack})\n return\n }\n\n store.get(lex, (err, ack) => {\n if (ack) {\n cb({put: ack, err: err})\n return\n }\n\n if (err) console.log(err)\n\n const track = utils.text.random(9)\n queue[track] = cb\n send(\n JSON.stringify({\n \"#\": dup.track(track),\n get: lex,\n }),\n )\n // Respond to callback with null if no response.\n setTimeout(() => {\n const cb = queue[track]\n if (cb) {\n const id = lex[\"#\"]\n const ack = {[id]: null}\n if (typeof lex[\".\"] === \"string\") ack[id] = {[lex[\".\"]]: null}\n cb({put: ack})\n delete queue[track]\n }\n }, opt.wait || 100)\n })\n }\n\n const api = send => {\n return {\n get: (lex, cb, opt) => {\n getWithCallback(lex, cb, send, opt)\n },\n put: async (data, cb) => {\n // Deferred updates are only stored using wire spec, they're ignored\n // here using the api. This is ok because correct timestamps should be\n // used whereas wire spec needs to handle clock skew for updates\n // across the network.\n const update = await Ham.mix(data, graph, opt.secure, listen)\n const none = Object.keys(update.now).length === 0\n if (none || !(await check(update.now, send, cb))) return\n\n store.put(update.now, cb)\n // Also put data on the wire spec.\n // TODO: Note that this means all clients now receive all updates, so\n // need to filter what should be stored, both in graph and on disk.\n send(\n JSON.stringify({\n \"#\": dup.track(utils.text.random(9)),\n put: data,\n }),\n )\n },\n on: (lex, cb) => {\n const soul = lex && lex[\"#\"]\n if (!soul || !cb) return\n\n if (listen[soul]) {\n listen[soul].push({\".\": lex[\".\"], cb: cb})\n } else {\n listen[soul] = [{\".\": lex[\".\"], cb: cb}]\n }\n },\n off: (lex, cb) => {\n const soul = lex && lex[\"#\"]\n if (!soul || !listen[soul]) return\n\n if (cb) {\n const found = listen[soul].find(l => l.cb === cb)\n if (found) {\n listen[soul].splice(listen[soul].indexOf(found), 1)\n }\n } else {\n // Remove all callbacks when none provided.\n delete listen[soul]\n }\n },\n }\n }\n\n if (isNode) {\n let wss = opt.wss\n // Node's websocket server provides clients as an array, whereas\n // mock-sockets provides clients as a function that returns an array.\n let clients = () => wss.clients()\n if (!wss) {\n wss = new wsModule.WebSocketServer({port: 8080})\n clients = () => wss.clients\n }\n\n const send = (data, isBinary) => {\n clients().forEach(client => {\n if (client.readyState === WebSocket.OPEN) {\n client.send(data, {binary: isBinary})\n }\n })\n }\n wss.on(\"connection\", ws => {\n ws.on(\"error\", console.error)\n\n ws.on(\"message\", (data, isBinary) => {\n const msg = JSON.parse(data)\n if (dup.check(msg[\"#\"])) return\n\n dup.track(msg[\"#\"])\n if (msg.get) get(msg, send)\n if (msg.put) put(msg, send)\n send(data, isBinary)\n\n const id = msg[\"@\"]\n const cb = queue[id]\n if (cb) {\n delete msg[\"#\"]\n delete msg[\"@\"]\n cb(msg)\n\n delete queue[id]\n }\n })\n })\n return api(send)\n }\n\n let ws = new WebSocket(\"ws://localhost:8080\")\n const send = data => {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n console.log(\"websocket not available\")\n return\n }\n\n ws.send(data)\n }\n const start = () => {\n if (!ws) ws = new WebSocket(\"ws://localhost:8080\")\n ws.onclose = c => {\n ws = null\n setTimeout(start, Math.floor(Math.random() * 5000))\n }\n ws.onerror = e => {\n console.error(e)\n }\n ws.onmessage = m => {\n const msg = JSON.parse(m.data)\n if (dup.check(msg[\"#\"])) return\n\n dup.track(msg[\"#\"])\n if (msg.get) get(msg, send)\n if (msg.put) put(msg, send)\n send(m.data)\n\n const id = msg[\"@\"]\n const cb = queue[id]\n if (cb) {\n delete msg[\"#\"]\n delete msg[\"@\"]\n cb(msg)\n\n delete queue[id]\n }\n }\n }\n\n start()\n return api(send)\n}\n\nexport default Wire\n", "import * as utils from \"./utils.js\"\nimport Wire from \"./wire.js\"\nimport SEA from \"./sea.js\"\n\nconst User = (opt, wire) => {\n if (!wire) wire = Wire(opt)\n let pubs = []\n let creating = false\n let authing = false\n let retries = 0\n\n const auth = (username, password, newPassword, ack) => {\n const retry = username => {\n retries++\n auth(username, password, newPassword, ack)\n }\n const done = err => {\n pubs = []\n retries = 0\n authing = false\n ack(err)\n }\n const next = () => {\n if (pubs.length === 0) {\n done(\"Wrong username or password\")\n return\n }\n\n const pub = pubs.shift()\n wire.get({\"#\": pub}, async msg => {\n if (msg.err) {\n done(`error getting ${pub}: ${msg.err}`)\n return\n }\n\n const data = msg.put && msg.put[pub]\n if (!data || !data.auth) return next()\n\n const auth = JSON.parse(data.auth)\n const work = await SEA.work(password, auth.salt)\n const dec = await SEA.decrypt(auth.enc, work)\n if (!dec) return next()\n\n user.is = {\n username: username,\n pub: data.pub,\n epub: data.epub,\n priv: dec.priv,\n epriv: dec.epriv,\n }\n // Holster API uses ctx to set the root node for user data.\n user.ctx = \"~\" + data.pub\n\n if (newPassword !== \"\") {\n // Encrypt private key using new password and a new salt.\n const salt = utils.text.random(64)\n const work = await SEA.work(newPassword, salt)\n const enc = await SEA.encrypt(dec, work)\n const auth = {auth: JSON.stringify({enc: enc, salt: salt})}\n const signed = await SEA.sign(auth, user.is)\n const graph = utils.graph(pub, signed.m, signed.s, data.pub)\n wire.put(graph, err => {\n if (err) {\n done(`error putting ${auth} on ${pub}: ${err}`)\n } else {\n done(null)\n }\n })\n return\n }\n\n return done(null)\n })\n }\n\n if (retries > 9) {\n done(\"Wrong username or password\")\n return\n }\n\n const soul = \"~@\" + username\n wire.get({\"#\": soul}, async msg => {\n if (msg.err) {\n done(`error getting ${soul}: ${msg.err}`)\n return\n }\n\n const data = msg.put && msg.put[soul]\n if (!data) return retry(username)\n\n delete msg.put[soul]._\n // Usernames aren't guaranteed to be unique, so store the list and then\n // try each of them until one is successful with the given password.\n pubs = Object.keys(data)\n next()\n })\n }\n\n const user = {\n create: (username, password, cb) => {\n const ack = err => {\n if (cb) cb(err)\n else console.log(err)\n }\n\n if (creating) {\n ack(\"User is already being created\")\n return\n }\n\n if (username === \"\") {\n ack(\"Please provide a username\")\n return\n }\n\n if (password === \"\") {\n ack(\"Please provide a password\")\n return\n }\n\n creating = true\n\n const soul = \"~@\" + username\n wire.get({\"#\": soul}, async msg => {\n if (msg.err) {\n creating = false\n ack(`error getting ${soul}: ${msg.err}`)\n return\n }\n\n if (msg.put && msg.put[soul]) {\n creating = false\n ack(\"Username already exists\")\n return\n }\n\n const salt = utils.text.random(64)\n const work = await SEA.work(password, salt)\n const pair = await SEA.pair()\n const priv = {priv: pair.priv, epriv: pair.epriv}\n const enc = await SEA.encrypt(priv, work)\n const data = {\n username: username,\n pub: pair.pub,\n epub: pair.epub,\n auth: JSON.stringify({enc: enc, salt: salt}),\n }\n\n const pub = \"~\" + pair.pub\n const signed = await SEA.sign(data, pair)\n const graph = utils.graph(pub, signed.m, signed.s, pair.pub)\n wire.put(graph, err => {\n creating = false\n if (err) {\n ack(`error putting ${data} on ${pub}: ${err}`)\n return\n }\n\n const rel = {[pub]: {\"#\": pub}}\n wire.put(utils.graph(soul, rel), err => {\n if (err) {\n ack(`error putting ${rel} on ${soul}: ${err}`)\n return\n }\n\n // Return null on success.\n if (cb) cb(null)\n })\n })\n })\n },\n auth: (username, password, cb) => {\n const ack = err => {\n if (cb) cb(err)\n else if (err) console.log(err)\n }\n\n if (authing) {\n ack(\"User is already authenticating\")\n return\n }\n\n user.is = null\n\n if (username === \"\") {\n ack(\"Please provide a username\")\n return\n }\n\n if (password === \"\") {\n ack(\"Please provide a password\")\n return\n }\n\n authing = true\n auth(username, password, \"\", ack)\n },\n change: (username, password, newPassword, cb) => {\n const ack = err => {\n if (cb) cb(err)\n else if (err) console.log(err)\n }\n\n if (authing) {\n ack(\"User is already authenticating\")\n return\n }\n\n user.is = null\n\n if (username === \"\") {\n ack(\"Please provide a username\")\n return\n }\n\n if (password === \"\") {\n ack(\"Please provide a password\")\n return\n }\n\n if (newPassword === \"\") {\n ack(\"Please provide a new password\")\n return\n }\n\n authing = true\n auth(username, password, newPassword, ack)\n },\n store: localStorage => {\n if (!user.is) {\n console.log(\"Please authenticate before calling store\")\n return\n }\n\n if (localStorage) {\n if (typeof globalThis.localStorage !== \"undefined\") {\n globalThis.localStorage.setItem(\"user.is\", JSON.stringify(user.is))\n }\n return\n }\n\n if (typeof globalThis.sessionStorage !== \"undefined\") {\n globalThis.sessionStorage.setItem(\"user.is\", JSON.stringify(user.is))\n }\n },\n recall: localStorage => {\n if (localStorage) {\n if (typeof globalThis.localStorage !== \"undefined\") {\n const is = globalThis.localStorage.getItem(\"user.is\")\n if (is) {\n user.is = JSON.parse(is)\n user.ctx = \"~\" + user.is.pub\n } else {\n console.log(\"User credentials not stored in local storage\")\n }\n }\n return\n }\n\n if (typeof globalThis.sessionStorage !== \"undefined\") {\n const is = globalThis.sessionStorage.getItem(\"user.is\")\n if (is) {\n user.is = JSON.parse(is)\n user.ctx = \"~\" + user.is.pub\n } else {\n console.log(\"User credentials not stored in session storage\")\n }\n }\n },\n leave: () => {\n user.is = null\n user.ctx = null\n if (typeof globalThis.localStorage !== \"undefined\") {\n globalThis.localStorage.removeItem(\"user.is\")\n }\n if (typeof globalThis.sessionStorage !== \"undefined\") {\n globalThis.sessionStorage.removeItem(\"user.is\")\n }\n },\n delete: (username, password, cb) => {\n const ack = err => {\n if (cb) cb(err)\n else console.log(err)\n }\n\n if (authing) {\n ack(\"User is already authenticating\")\n return\n }\n\n if (username === \"\") {\n ack(\"Please provide a username\")\n return\n }\n\n if (password === \"\") {\n ack(\"Please provide a password\")\n return\n }\n\n authing = true\n auth(username, password, \"\", async err => {\n if (err) {\n ack(err)\n return\n }\n\n const data = {username: null, pub: null, epub: null, auth: null}\n const signed = await SEA.sign(data, user.is)\n const pub = \"~\" + user.is.pub\n const graph = utils.graph(pub, signed.m, signed.s, user.is.pub)\n wire.put(graph, err => {\n if (err) {\n ack(`error putting null on ${pub}: ${err}`)\n return\n }\n\n user.is = null\n user.ctx = null\n // Return null on success. Note currently not updating ~@username,\n // not sure if allowing username re-user is a good idea anyway?\n if (cb) cb(null)\n })\n })\n },\n }\n return user\n}\n\nexport default User\n", "import * as utils from \"./utils.js\"\nimport Wire from \"./wire.js\"\nimport User from \"./user.js\"\nimport SEA from \"./sea.js\"\n\nconst Holster = opt => {\n const wire = Wire(opt)\n const user = User(null, wire)\n // Map callbacks since the user's callback is not passed to wire.on.\n const map = new Map()\n // Allow concurrent calls to the api by storing each context.\n const allctx = new Map()\n\n const ok = data => {\n return (\n data === null ||\n data === true ||\n data === false ||\n typeof data === \"string\" ||\n utils.rel.is(data) ||\n utils.num.is(data)\n )\n }\n\n // check returns true if data is ok to add to a graph, an error string if\n // the data can't be converted, and the keys on the data object otherwise.\n const check = data => {\n if (ok(data)) return true\n\n if (utils.obj.is(data)) {\n const keys = []\n for (const [key, value] of Object.entries(data)) {\n if (key === \"_\") {\n return \"error underscore cannot be used as an item name\"\n }\n if (utils.obj.is(value) || ok(value)) {\n keys.push(key)\n continue\n }\n return `error {${key}:${value}} cannot be converted to graph`\n }\n if (keys.length !== 0) return keys\n }\n return `error ${data} cannot be converted to a graph`\n }\n\n const api = ctxid => {\n const get = (lex, soul, ack) => {\n wire.get(utils.obj.put(lex, \"#\", soul), async msg => {\n if (msg.err) console.log(msg.err)\n if (msg.put && msg.put[soul]) {\n delete msg.put[soul]._\n delete msg.put[soul][utils.userPublicKey]\n // Resolve any rels on the node before returning to the user.\n for (const key of Object.keys(msg.put[soul])) {\n const id = utils.rel.is(msg.put[soul][key])\n if (id) {\n const data = await new Promise(res => {\n const _ctxid = utils.text.random()\n allctx.set(_ctxid, {chain: [{item: null, soul: id}]})\n api(_ctxid).next(null, res)\n })\n msg.put[soul][key] = data\n }\n }\n ack(msg.put[soul])\n } else {\n // No data callback.\n ack(null)\n }\n })\n }\n\n const graph = async (soul, data, cb) => {\n if (!cb) cb = console.log\n\n if (!user.is) {\n if (opt.secure) {\n cb(`error putting data on ${soul}: user required in secure mode`)\n return null\n }\n\n return utils.graph(soul, data)\n }\n\n if (!user.is) {\n cb(`error putting data on ${soul}: user not authenticated`)\n return null\n }\n\n const signed = await SEA.sign(data, user.is)\n return utils.graph(soul, signed.m, signed.s, user.is.pub)\n }\n\n const done = data => {\n const ctx = allctx.get(ctxid)\n if (ctx && typeof ctx.cb !== \"undefined\") ctx.cb(data)\n else if (data) console.log(data)\n // A context updated by \"on\" should only be removed by \"off\".\n if (ctx && !ctx.on) allctx.delete(ctxid)\n }\n\n const resolve = (request, cb) => {\n const get = request && typeof request.get !== \"undefined\"\n const put = request && typeof request.put !== \"undefined\"\n const on = request && typeof request.on !== \"undefined\"\n const off = request && typeof request.off !== \"undefined\"\n\n let found = false\n const ctx = allctx.get(ctxid)\n for (var i = 1; i < ctx.chain.length; i++) {\n if (ctx.chain[i].soul !== null) continue\n\n found = true\n break\n }\n\n if (found) {\n // Found a soul that needs resolving, need the previous context\n // (ie the parent node) to find a soul relation for it.\n const {item, soul} = ctx.chain[i - 1]\n wire.get({\"#\": soul, \".\": item}, async msg => {\n if (msg.err) {\n console.log(`error getting ${item} on ${soul}: ${msg.err}`)\n if (cb) cb(null)\n return\n }\n\n const node = msg.put && msg.put[soul]\n if (node && typeof node[item] !== \"undefined\") {\n let id = utils.rel.is(node[item])\n if (id) {\n ctx.chain[i].soul = id\n // Not sure why the map needs to be set rather than just ctx?\n allctx.set(ctxid, {chain: ctx.chain, cb: ctx.cb})\n // Call api again using the updated context.\n if (get) api(ctxid).next(null, request.get, cb)\n else if (put) api(ctxid).put(request.put, cb)\n else if (on) api(ctxid).on(request.on, cb)\n else if (off) api(ctxid).off(cb)\n } else if (get) {\n // Request was not for a node, return a property on the current\n // soul.\n cb(node[item])\n } else if (put) {\n // Request was chained before put, so rel doesn't exist yet.\n id = utils.text.random()\n const rel = {[item]: utils.rel.ify(id)}\n const g = await graph(soul, rel, cb)\n if (g === null) return\n\n wire.put(g, err => {\n if (err) {\n cb(`error putting ${item} on ${soul}: ${err}`)\n return\n }\n\n ctx.chain[i].soul = id\n api(ctxid).put(request.put, cb)\n })\n } else if (on) {\n console.log(`error resolving on for ${item} on ${soul}`)\n cb(null)\n } else if (off) {\n console.log(`error resolving off for ${item} on ${soul}`)\n if (cb) cb(null)\n }\n } else if (put) {\n cb(`error ${item} not found on ${soul}`)\n } else {\n console.log(`error ${item} not found on ${soul}`)\n if (cb) cb(null)\n }\n })\n // Callback has been passed to next soul lookup or called above, so\n // return false as the calling code should not continue.\n return false\n }\n\n if (get && ctx.chain[ctx.chain.length - 1].item !== null) {\n // The context has been resolved but it does not include the requested\n // node, which requires one more lookup.\n ctx.chain.push({item: null, soul: null})\n api(ctxid).next(null, request.get, cb)\n return false\n }\n\n // Return the last context, ie the soul required by the calling code.\n return ctx.chain[ctx.chain.length - 1]\n }\n\n return {\n get: (key, lex, cb) => {\n if (typeof lex === \"function\") {\n cb = lex\n lex = null\n }\n if (key === null || key === \"\" || key === \"_\") {\n if (cb) cb(null)\n return\n }\n\n // lex requires a callback as it's not included in the chain below.\n if (lex && !cb) {\n console.log(\"lex requires a callback function\")\n return\n }\n\n // Top level keys are added to a root node so their values don't need\n // to be objects, the user's public key is used as the root node when\n // user.ctx is set.\n const root = user.ctx ? user.ctx : \"root\"\n\n ctxid = utils.text.random()\n allctx.set(ctxid, {chain: [{item: key, soul: root}], cb: cb})\n if (!cb) return api(ctxid)\n\n // When there's a callback need to resolve the context first.\n const {soul} = resolve({get: lex}, done)\n if (soul) get(lex, soul, done)\n },\n next: (key, lex, cb) => {\n const ack = data => {\n cb ? cb(data) : done(data)\n }\n\n if (typeof lex === \"function\") {\n cb = lex\n lex = null\n }\n if (!ctxid) {\n console.log(\"please provide a key using get(key)\")\n ack(null)\n return\n }\n\n if (key === \"\" || key === \"_\") {\n ack(null)\n return\n }\n\n // lex requires a callback as it's not included in the chain below.\n if (lex && !cb) {\n console.log(\"lex requires a callback function\")\n return\n }\n\n const ctx = allctx.get(ctxid)\n // ctx already removed by another chained callback is ok?\n if (!ctx) return\n\n if (cb && typeof ctx.cb === \"undefined\") {\n // This (and ack) allows nested objects to set their own callbacks.\n ctx.cb = cb\n cb = null\n }\n\n // Push the key to the context as it needs a soul lookup.\n // (null is used to call the api with updated context)\n if (key !== null) ctx.chain.push({item: key, soul: null})\n if (!ctx.cb) return api(ctxid)\n\n // When there's a callback need to resolve the context first.\n const {soul} = resolve({get: lex}, ack)\n if (soul) get(lex, soul, ack)\n },\n put: (data, cb) => {\n const ack = err => {\n cb ? cb(err) : done(err)\n }\n\n if (!ctxid) {\n ack(\"please provide a key using get(key)\")\n return\n }\n\n const ctx = allctx.get(ctxid)\n // ctx already removed by another chained callback is ok?\n if (!ctx) return\n\n if (!ctx.cb) {\n if (!cb) return\n\n // This (and ack) allows nested objects to set their own callbacks.\n ctx.cb = cb\n cb = null\n }\n\n const result = check(data)\n if (typeof result === \"string\") {\n // All strings returned from check are errors, cannot continue.\n ack(result)\n return\n }\n\n // Resolve the current context before putting data.\n const {item, soul} = resolve({put: data}, ack)\n if (!soul) return\n\n if (result === true) {\n // When result is true data is a property to put on the current soul.\n // Need to check if item is a rel and also set the node to null. (This\n // applies for any update from a rel to a property, not just null.)\n wire.get({\"#\": soul, \".\": item}, async msg => {\n if (msg.err) {\n console.log(`error getting ${soul}: ${msg.err}`)\n return\n }\n\n const current = msg.put && msg.put[soul] && msg.put[soul][item]\n const id = utils.rel.is(current)\n if (!id) {\n // Not a rel, can just put the data.\n const g = await graph(soul, {[item]: data}, ack)\n if (g === null) return\n\n wire.put(g, ack)\n return\n }\n\n wire.get({\"#\": id}, async msg => {\n if (msg.err) {\n console.log(`error getting ${id}: ${msg.err}`)\n return\n }\n\n if (!msg.put || !msg.put[id]) {\n console.log(`error ${id} not found`)\n return\n }\n\n delete msg.put[id]._\n // null each of the properties on the node before putting data.\n for (const key of Object.keys(msg.put[id])) {\n if (key === utils.userPublicKey) continue\n\n const err = await new Promise(res => {\n const _ctxid = utils.text.random()\n allctx.set(_ctxid, {chain: [{item: key, soul: id}]})\n api(_ctxid).put(null, res)\n })\n if (err) {\n ack(err)\n return\n }\n }\n const g = await graph(soul, {[item]: data}, ack)\n if (g === null) return\n\n wire.put(g, ack)\n })\n })\n return\n }\n\n // Otherwise put the data using the keys returned in result.\n // Need to check if a rel has already been added on the current node.\n wire.get({\"#\": soul, \".\": item}, async msg => {\n if (msg.err) {\n ack(`error getting ${soul}.${item}: ${msg.err}`)\n return\n }\n\n const current = msg.put && msg.put[soul] && msg.put[soul][item]\n const id = utils.rel.is(current)\n if (!id) {\n // The current rel doesn't exist, so add it first.\n const rel = {[item]: utils.rel.ify(utils.text.random())}\n const g = await graph(soul, rel, ack)\n if (g === null) return\n\n wire.put(g, err => {\n if (err) {\n ack(`error putting ${item} on ${soul}: ${err}`)\n } else {\n const _ctxid = utils.text.random()\n const chain = [{item: item, soul: soul}]\n // Pass the previous context's callback on here.\n allctx.set(_ctxid, {chain: chain, cb: ctx.cb})\n api(_ctxid).put(data)\n }\n })\n return\n }\n\n let put = false\n const update = {}\n for (const key of result) {\n const err = await new Promise(res => {\n if (utils.obj.is(data[key])) {\n // Use the current rel as the context for nested objects.\n const _ctxid = utils.text.random()\n allctx.set(_ctxid, {chain: [{item: key, soul: id}]})\n api(_ctxid).put(data[key], res)\n } else {\n put = true\n // Group other properties into one update.\n update[key] = data[key]\n res(null)\n }\n })\n if (err) {\n ack(err)\n return\n }\n }\n if (put) {\n const g = await graph(id, update, ack)\n if (g === null) return\n\n wire.put(g, ack)\n } else {\n // Callback on behalf of nested objects.\n ack(null)\n }\n })\n },\n on: (lex, cb) => {\n if (typeof lex === \"function\") {\n cb = lex\n lex = null\n }\n if (!cb) return\n\n if (!ctxid) {\n console.log(\"please provide a key using get(key)\")\n cb(null)\n return\n }\n\n // Resolve the current context before adding event listener.\n const {item, soul} = resolve({on: lex}, cb)\n if (!soul) return\n\n // Flag that this context is set from on and shouldn't be removed.\n allctx.set(ctxid, {chain: [{item: item, soul: soul}], on: true})\n // Map the user's callback because it can also be passed to off,\n // so need a reference to it to compare them.\n map.set(cb, () => api(ctxid).next(null, cb))\n // Check if item is a rel and add event listener for the node.\n wire.get({\"#\": soul, \".\": item}, msg => {\n if (msg.err) {\n console.log(`error getting ${soul}.${item}: ${msg.err}`)\n return\n }\n\n const current = msg.put && msg.put[soul] && msg.put[soul][item]\n const id = utils.rel.is(current)\n if (id) {\n if (lex) lex = utils.obj.put(lex, \"#\", id)\n else lex = {\"#\": id, \".\": null}\n } else {\n if (lex) lex = utils.obj.put(lex, \"#\", soul)\n else lex = {\"#\": soul, \".\": item}\n }\n wire.on(lex, map.get(cb))\n })\n },\n off: cb => {\n if (!ctxid) {\n console.log(\"please provide a key using get(key)\")\n if (cb) cb(null)\n return\n }\n\n // Resolve the current context before removing event listener.\n const {item, soul} = resolve({off: true}, cb)\n if (!soul) return\n\n // Check if item is a rel and remove event listener for the node.\n wire.get({\"#\": soul, \".\": item}, msg => {\n if (msg.err) {\n console.log(`error getting ${soul}.${item}: ${msg.err}`)\n return\n }\n\n const current = msg.put && msg.put[soul] && msg.put[soul][item]\n const id = utils.rel.is(current)\n if (id) wire.off({\"#\": id}, map.get(cb))\n else wire.off({\"#\": soul}, map.get(cb))\n map.delete(cb)\n allctx.delete(ctxid)\n })\n },\n user: pub => {\n // Return the combined Holster and User APIs. Passing in a public key\n // will set the user context to that key, otherwise user.ctx is set when\n // a user logs in so that their public key will be used as the root node\n // in get(), also put() will sign all graph updates for verification.\n if (pub) user.ctx = \"~\" + pub\n return Object.assign(user, api())\n },\n // Allow the wire spec to be used via holster.\n wire: wire,\n // Allow SEA functions to be used via holster.\n SEA: SEA,\n }\n }\n return api()\n}\n\nexport default Holster\n"],
5
+ "mappings": "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",
6
+ "names": ["num", "n", "obj", "o", "list", "cb", "keys", "i", "result", "key", "value", "map_soul", "soul", "rel", "userPublicKey", "graph", "data", "sig", "pub", "g", "match", "lex", "prefix", "gt", "lt", "text", "length", "s", "c", "Dup", "maxAge", "dup", "id", "now", "dup_default", "Get", "lex", "graph", "soul", "key", "node", "value", "get_default", "data", "SeaArray", "enc", "start", "end", "length", "buf", "i", "_", "array_default", "SafeBuffer", "props", "input", "buf", "enc", "bytes", "byte", "array_default", "length", "words", "_", "i", "dec", "fill", "arr", "ret", "item", "buffer_default", "isNode", "crypto", "subtle", "stringify", "data", "parse", "text", "random", "length", "array", "buffer_default", "jwk", "pub", "priv", "x", "y", "sha256", "hash", "aeskey", "key", "salt", "combined", "keyToJwk", "SEA", "cb", "ecdsa", "subtle", "keys", "pub", "ecdh", "pair", "data", "rand", "random", "ct", "aeskey", "aes", "stringify", "enc", "buffer_default", "dec", "parse", "signed", "key", "jwk", "msg", "k", "userPublicKey", "hash", "sha256", "sig", "alg", "verified", "salt", "work", "to", "from", "pubKey", "priv", "derived", "derivedBits", "derivedKey", "sea_default", "Ham", "state", "currentState", "value", "currentValue", "change", "graph", "secure", "listen", "machine", "now", "defer", "wait", "soul", "node", "updated", "alias", "nodeWait", "pub", "verify", "sea_default", "key", "rel", "skew", "l", "match", "ham_default", "group", "record", "Radix", "radix", "keys", "value", "tree", "i", "tmp", "key", "max", "noValue", "found", "obj", "hasValue", "hasKey", "j", "matchingKey", "replace", "map", "cb", "opt", "pre", "u", "radix_default", "etx", "enq", "unit", "Radisk", "opt", "u", "cache", "radisk", "key", "value", "cb", "radix_default", "batch", "i", "err", "rad", "save", "tree", "file", "start", "end", "disk", "write", "k", "pre", "enc", "name", "soul", "read", "parse", "data", "tmp", "c", "o", "state", "current", "text", "rel", "num", "obj", "previous", "radisk_default", "isNode", "fs", "enq", "unit", "root", "fileSystem", "opt", "dir", "file", "cb", "err", "data", "random", "tmp", "files", "db", "o", "event", "req", "Store", "obj", "radisk", "radisk_default", "lex", "soul", "key", "node", "each", "value", "match", "graph", "radix_default", "count", "ack", "state", "store_default", "isNode", "wsModule", "Wire", "opt", "obj", "dup", "dup_default", "store", "store_default", "graph", "queue", "listen", "check", "data", "send", "cb", "soul", "msg", "res", "getWithCallback", "node", "pub", "key", "userPublicKey", "get", "ack", "get_default", "text", "err", "put", "update", "ham_default", "lex", "track", "id", "api", "found", "l", "wss", "clients", "isBinary", "client", "ws", "start", "e", "m", "wire_default", "User", "opt", "wire", "wire_default", "pubs", "creating", "authing", "retries", "auth", "username", "password", "newPassword", "ack", "retry", "done", "err", "next", "pub", "msg", "data", "work", "sea_default", "dec", "user", "salt", "text", "enc", "signed", "graph", "soul", "cb", "pair", "priv", "rel", "localStorage", "is", "user_default", "Holster", "opt", "wire", "wire_default", "user", "user_default", "map", "allctx", "ok", "data", "rel", "num", "check", "obj", "keys", "key", "value", "api", "ctxid", "get", "lex", "soul", "ack", "msg", "userPublicKey", "id", "res", "_ctxid", "text", "graph", "cb", "signed", "sea_default", "done", "ctx", "resolve", "request", "put", "on", "off", "found", "i", "item", "node", "g", "err", "root", "result", "current", "chain", "update", "pub", "holster_default"]
7
+ }
@@ -0,0 +1,33 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Holster - test examples</title>
6
+ </head>
7
+ <body>
8
+ <h2>Holster - test examples</h2>
9
+ <p>
10
+ This file loads <code>index.js</code> which contains examples that use the
11
+ Holster API. See the console log for test output.
12
+ </p>
13
+ <p>
14
+ The tests make two updates to the same data, but they occur in random
15
+ order. The "species" field is then logged and should match the update that
16
+ happened last.
17
+ </p>
18
+ <p>
19
+ The <code>index.js</code> file is loaded as a module, which allows it to
20
+ import the development build of Holster. You can switch to the production
21
+ build by changing the import path at the top of the file.
22
+ </p>
23
+ <p>
24
+ See <a href="/examples/user.html">user.html</a> for examples that test the
25
+ Holster.user API.
26
+ </p>
27
+ <p>
28
+ See <a href="/examples/wire.html">wire.html</a> for examples that test the
29
+ Holster.wire API.
30
+ </p>
31
+ <script type="module" src="/examples/index.js"></script>
32
+ </body>
33
+ </html>
@@ -0,0 +1,49 @@
1
+ // Switch src to build for the production version.
2
+ import Holster from "../src/holster.js"
3
+
4
+ // Set readFromDisk to true to force reading from disk.
5
+ // (Restart the server so that graph is not in memory.)
6
+ const readFromDisk = false
7
+
8
+ const holster = Holster({indexedDB: !readFromDisk})
9
+ globalThis.holster = holster
10
+
11
+ if (readFromDisk) {
12
+ // Wait for the websocket to connect.
13
+ setTimeout(() => {
14
+ holster.get("mark").next("boss", {".": "species"}, data => {
15
+ console.log("read from disk:", data)
16
+ })
17
+ }, 1000)
18
+ } else {
19
+ // Create two updates that could happen in either order.
20
+ setTimeout(() => {
21
+ const update1 = {
22
+ name: "Mark Nadal",
23
+ boss: {
24
+ name: "Fluffy",
25
+ species: "a kitty",
26
+ },
27
+ }
28
+ holster.get("mark").put(update1, err => console.log("update1:", err))
29
+ }, 1000 * Math.random())
30
+
31
+ setTimeout(() => {
32
+ const update2 = {
33
+ name: "Mark",
34
+ boss: {
35
+ species: "felis silvestris",
36
+ color: "ginger",
37
+ },
38
+ }
39
+ holster.get("mark").put(update2, err => console.log("update2:", err))
40
+ }, 1000 * Math.random())
41
+
42
+ // The API sets the state on properties to the current time, so the result
43
+ // here depends on which update was called first.
44
+ setTimeout(() => {
45
+ holster.get("mark").next("boss", {".": "species"}, data => {
46
+ console.log("get:", data)
47
+ })
48
+ }, 2000)
49
+ }