{"_id":"dat-sdk","_rev":"39-240546ccba046c704bf269c54f9f062e","name":"dat-sdk","dist-tags":{"latest":"2.8.1","next":"2.0.0-8"},"versions":{"0.1.0":{"name":"dat-sdk","version":"0.1.0","description":"The official Dat SDK (WIP)","main":"index.js","scripts":{"test":"node test","build-test":"browserify -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.0.0","hyperdrive":"^9.15.0","universal-dat-storage":"^1.2.1"},"devDependencies":{"browserify":"^16.2.3","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"3adb006316c8b7a387276a7db652ce033db4c4d8","_id":"dat-sdk@0.1.0","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-M1XophrXvJCmTsoLY/pqVdfIJutLpFIWP/xWuRgaPGlS5mWJPhV8w3dfOc/j2XvdSKBXT856qfy63Q4gPyGA0Q==","shasum":"df3cbcf57dba3a6307405e1856d076db9dd0ccf2","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.1.0.tgz","fileCount":9,"unpackedSize":19385,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdJjrZCRA9TVsSAnZWagAA04wP/RmKIsi9Xng4Kd46nL3d\nxYS2VTGdR8taULel0ia0uF9HPJLSPgNSzH8hl/dJDfqDCXGqgqQMlRQf3IbG\ngavtO03fT8P24LpGWt7FePD1zKs1SWyW5qoKorpK8FhfSxew3Mv6oL2vO+7H\nTtY6U+TSR+Hmdm+QBd1+SEcVf3WLi4+XCvAZakVqVk9N2QY7gBxJunbVsZDJ\nfaw8d4apcwLpvQojOG52LxhJ9IZ1gvIO0Z7w60YtO6eejREipcf7ubqlYOZd\n8DXN/LaV1sfsMSd9K7RLx8dgqrVGZptR22lcO+K8SRiC6LaSird1rM4w4QHz\nrbU+4SWtAWs29bpi/mLe9H6OZt6mmCUAJVfLhvD85y3Hyyn6O4MHZU43qC0X\n7EEEPl/79YleHIiXCM70GGMeWS9KFRgP64feLL8sdFIv9Bzm0OrQ1Odsor6w\nBRaB/TyoU6lYvf4v7ztkrpGbtwMaK76xz1TwLmX1ViQlMuaMckjUrAApaQrZ\ns3FbN7cvBD6Ys+mf/p5h5BXMuWcBDJ2l0roGh8n+K9AuIvtjDms7e8Ts/2uJ\nthwQX4uQRkZJSmq+qpbpNa/3KvGQA7qeGTemBfO5Ww/tlcv0CtUEbTNzN5un\npBRwNL9oOdoGdlVWiQSFDIeiIH92GTmaXnfWfhVBOccgV9nXlw8wfF0LgU/G\nt1d8\r\n=0E4j\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDwPGC3S/MPz0tAN7AJLKJZi9HHeMsc/BFomVgarH80lAiEAkh25y6wqKA6GQ3SKkMgjzgiJznhz9jqlnzswlhtQyug="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.1.0_1562786521194_0.8800816761925474"},"_hasShrinkwrap":false},"0.2.0":{"name":"dat-sdk","version":"0.2.0","description":"The official Dat SDK (WIP)","main":"index.js","scripts":{"test":"node test","build-test":"browserify -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.0.0","hyperdrive":"^9.16.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"62b624c8e44a12fb983d7a96bc67e9e58c40eda3","_id":"dat-sdk@0.2.0","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-H+CSDLlPLbYMOQc5Wk65QBhvXPnoBSja8tJ4Yd+67rZTF7UIZ5VOw9VLEDEKYJV1rpvZYfOLjMLOAQQlDWq2xw==","shasum":"a2362699ce2c03ba2d1e30692e3fcb4bd1ea8003","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.2.0.tgz","fileCount":10,"unpackedSize":26463,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdTH2RCRA9TVsSAnZWagAAsvEP/jC8UAiDvpOy82zqX/w8\nqbawnF3U3cfzozDw7881feG8fuQbU28c661VGwks+Dp2XCx2Bu7zvvieCu4Q\nY87F9oAdNyFD/FU6K6wSpLU+A6JEE+VzlIKvAeKWV1ob+bNVYg22fLpQsdFQ\nyud2VkcRfQs2BzH4fB2n9C5/Lpz8tVq9gOgNk2ZOsx+S4vTQQjY+fMG9nObe\nnJ7ZHCUbpkia4vOqwXQ/zG7zYV2aQ5pVDmeOKDUQV+q12DUAwV2lEFjyzvLq\nJE0+DzWspnxfXoi2EQfgUz47cFffhtmZ0HZ/RUg52PpxcPLZdTp9RBu5F5ie\nsR/6Izyg1A4ih+1WowbKlwaUwLSSNnRTQb6yKK6PFu+Ke2Av7XnP1WWXtZyJ\nOcyvIgj6c68unkszYgL+h9Je8jankuD8MX/3X87AiPmdhNXfaG3x1+pRRp0p\nZIAngvqBJlvkg8XkTiENEAFd+M2QUEYbiMkAOEahNzya1gO3I2idaUMiIcOI\nHYUmQWpNFEhUdwY8VTjifkdA5mgD5LVXE9LqJUFeF1PvP+T0lDGLY0zYrPBF\nJuR416bYbzFLLvTrRQ47rRNob5rG63I0jnsCkzWNcn9lnAjUYWf5Q7oqRnlR\ndViDqHn0zMYFcMnT8MQNP32K6Kz629wBlSHHouVoYRAeCLhT4jNRsnnM5riv\nhBaf\r\n=KCBJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCce1xjyS+QdHXEugmN+j0S0QklnE3CbVaJK3m14JfQdAIhAMli7PZpFFrKNYW2kxs4Z7WF76VyLIs1axaz3cE50Lf5"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.2.0_1565293968593_0.7842200764965834"},"_hasShrinkwrap":false},"0.2.1":{"name":"dat-sdk","version":"0.2.1","description":"The official Dat SDK (WIP)","main":"index.js","scripts":{"test":"node test","build-test":"browserify -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.0.0","hyperdrive":"^9.16.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"f20777f9d4ca4bdcb1a2ad6a6528ac9cebfdbd0d","_id":"dat-sdk@0.2.1","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-2UEkBMIPLH3M5Pb7tLw3z3E3PkRPYRu65n8p3d1yTdCZtALtRHHdbY6XA2xM+om7So4lwP5VbzgBcD9FrAAIgA==","shasum":"53926276a35da0db6db0e95e298271a5896a00ef","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.2.1.tgz","fileCount":10,"unpackedSize":26675,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdVt/2CRA9TVsSAnZWagAAY7sP/3sBw77BOy56znsvURS/\nF/HtIjKhfUlc5gTen2vaRNLIEvoRMjrBVMooCc3Ei1MpEKeyTTvyf2GqeaUN\n1F7EMv/BwreOvj+WggmbK/EdvBdRvFFQVadOXNE7wQGS4Gf/UpzXm+qTpW3E\nT2+ZtNL5yuBGbLOft8i3KZUGr++7uxGEsy9jWDL3kVuNq4bFyWPbmooTttYf\nwhKrG9ORLBq7DQ/+8eRJfeDPym/VwUPXTwa+RWN95TpW686aPjl74829jBXs\npo8rQZSFFSL/448nm54xX35J0VpQPZHzoXQEhuFR/3juD0QvfTPU1yYdBfcR\nkyNhmoCk8Jn9PUodnTMbQJbCFS9enOCAnfuwDb1icJbhDJ6EaMuXc1gF5RjV\nJWZP43iKRBBBRUOpnrpDZFVqZTy7Ib2e3GSSyVmo1jW2o3TX+i7b+zrzzpuD\nR+2hnAWYqYA3asfeXDtOQ1dLJ0DDubKD476TCG5KlQ4pBaJgj1ppXt7m3/tr\n/FKRJBmb6PfOHOm0X+lODFaCioHXqwAgxnHafQvXCiDjexqodDXyNmF+10cp\nEXS39jCyoplaMwRN+SDJFyd0iavUJU4F9uqaEcXStOUy0ExTeketKc1gFIny\nYX4zieLqYJEBNpmc9+Jttb7oDus4JZQtC+NtQ0A1FfUB5jt6rUjFrLeIXMQK\nH3TE\r\n=pOVO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCWG/2Az3rr6/CHQfyvKaZrsA2s9cLQPVhzUCaQfjzPUwIhAIVzqLH+gFnSTVK0OpMWBg1MBRKiLmj+tk6mLsxOpzKJ"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.2.1_1565974517286_0.598629774056215"},"_hasShrinkwrap":false},"0.2.2":{"name":"dat-sdk","version":"0.2.2","description":"The official Dat SDK (WIP)","main":"index.js","scripts":{"test":"node test","build-test":"browserify -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.0.0","hyperdrive":"^9.16.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"a1dd1134405890060c51376bdfc1e5b90f30a749","_id":"dat-sdk@0.2.2","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-kgcUz7AvNaUCuTmiM3JhppjXxJFlNSSb8musbfn91AkWikblJKzN940yiFuQOZVo7mNi9f7HDyJsQMbCp7Aacg==","shasum":"43ddb5605c269fad25bb6146f93254a20422d17f","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.2.2.tgz","fileCount":10,"unpackedSize":26862,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdWvmWCRA9TVsSAnZWagAAwlwQAJ198Bq4eZCVz2Mkh4/z\naLEKvv+cr0cBnOUb+UQI6JUEOCPf+Oslf2QU6LWwiBzwrhWpxmFqqtQhxPII\ntlJQ6f3V04BR2DbiZCXh0pkYjnUjdzrwXqO82nlaTmWoXgou4drwjYAuZUIm\nMyz4rGjK7B4nMpAS2kzic73SrKwC0p1sOTXhcuHnbUztxy0tAESQf8HMDUn9\nHWW24IzzWjzAk6AvfJJ/6sf9w4JTyqu4bJrAQCbt20ig9WN7GHsQDDHcxqp+\noTQ4+5KGCOqhug/X00wlHYZyvqKzBtvQJAq4DHIDnvwo3cT7uyIyEJU65Ln8\nv10WifQ6iUUn+Sh99/uXUVfG0JfbMoZjUa+JW/4e229hkhtfaImIy8QIKXcs\nmS8mWnmnHfls3pi4/W3ps7yfMYHOBjL3rrDLlxczKrHw2kpuEyGiP1YvMOpH\n6x7g76DSbNFtfOyntuRqD5WxjgQTU07iv6t/7RFZQb1ka+7dEMM6aSSX3jUc\nsiCheaEaE8Due03aBh6BvjZMH/E4ZEokvwCPOmagKXy2CSOa/5li3S0xEQqb\n5AxiBvHz9IHZsOmM3dpcqaoZmRNR3QGSzsGU9Bnx0egsjh7H35INnJyaex3i\nbSAb1HEoUyR7WRNSqmUZWibSi59S1QSlG7zwBOp+YuS9xpojO63+hUaFT4+y\nDfkP\r\n=MEpK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEgA4Mx0NgjJ55wC3fPaOShx0GwJySMBFn5k8rf12e8XAiBGMMSfIwDw+7NCyWut2+OPxUFU84JriH+YwGKMF4iLyw=="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.2.2_1566243221613_0.3049857425899791"},"_hasShrinkwrap":false},"0.3.0":{"name":"dat-sdk","version":"0.3.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.0.0","hyperdrive":"^9.16.0","node-dat-archive":"^2.2.0","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"cf157ce1aba7545754a7c92895ede7d7721a7438","_id":"dat-sdk@0.3.0","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-JHdmTG3Z3GlYbljU4LGQQ52mzswrbvKQpJzgu273nY5u+OHNwk2Z5UJR5ddxecQVx2uMfAgQBi8GzXm/iFq01A==","shasum":"37cf7bfc8c22da87f4d873b606ecd1cd2744fae5","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.3.0.tgz","fileCount":13,"unpackedSize":45333,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdZZQnCRA9TVsSAnZWagAAmvoP+wRWHK9J3vISEUy46WJs\nzyXIMlXxqLZLtVTJ4iFstbHfV2zoC1LqBuw0uraPypsmzFqRPEq5Mp1SATnp\nQ7FpElXbCHLFh2Gr20XIFMlKUSZ2J2C481DZTuvRuf5MtrtU3861AT26+jV+\nusu7MCo+VPDIIc0/AkoZyZ0kXSHZveTAoAa+oi7C0LonZ+MXomMAxSFfuY//\nlt2cSwpwobUdfZakj9gSDJCFID1dwLPJYuCeeVWPsXe1omggcGAovFzsAFkR\nR1Kj92jjeiR8uyVlEA7OYipq5MNV0l7zEnV9PFaMaZvq8cA+9CX0A7XB56oU\n9R+edTqmD3gOZ5FewVXkyqi93xelut7hfX1ScshB4WNZyHqC0uZo/oyggdXz\nTK/LREXnVIMxsaReQDOLnviQIlunOKVFQ2zkrsKr2JeTps/GV2+muuuKwtDn\nP4cAT2h9uAxe+lkpu8j91RnDeLCtC1hqP0OtfQZ7glwGsAfb73w7+tjz3R5k\nCxtAWm6K14+yo++iXymJYFIJ5reP01vrx0v/XcPi4MT6kfQckwwey1b3X4gD\nl4tfDcsdCnn1H+fUKmnS0X2+8Gan+ixnUt416FBsrKsmQFMRx+gbYPBm1izE\n9yc1vyZtFbKD4t2WXCP/20HidRfNX7h4VNIvq3CIhtO8Sc7zlpvNo+REwzC4\nOsXY\r\n=SSQ/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGBRBTL9ximb1XjYv2cqKUY4Q7EpdXvHTTLw3iGZZKiPAiEA6iavOcfrCthxyamDsXHkSYUD1R0bzD/fbFH/RzPD24Q="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.3.0_1566938151084_0.9309359481909993"},"_hasShrinkwrap":false},"0.3.1":{"name":"dat-sdk","version":"0.3.1","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.0.0","hyperdrive":"^9.16.0","node-dat-archive":"^2.2.0","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"cc630a925f47c63a70aa823ae00d3096fbcd2589","_id":"dat-sdk@0.3.1","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-SSBdCxJT0x9lNZMsTzXGLJbJcezOAQ6lY7+pPwWJhextEMQwTGIaPRKp0NlEDl+AEbqCNYMJ9WfqRDYFFud/fw==","shasum":"825150d183231a0fa2f3034f796a440574ad697f","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.3.1.tgz","fileCount":13,"unpackedSize":45494,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdae7PCRA9TVsSAnZWagAAdGcP/3K0yNL2Ns+9btvayz2w\nW/js+ozX5SYQVDkzS5yHMXP5kLbXtTd/+OuzV8emdZwd1xKeoHdaM3sdmvaY\nCoVJ3BoQlkl9VQwfP/somk9akiQLI+IMNgsbEOU0gB7+ksVF90yTE+mwzTAl\nRkv05dMxM4AsjBnlr1b9vvEgmWPNttGvXxQw7gMtYoMWe4kh6HGy/81f17mX\nDXO8zzkVkARJLtsk1FRS3uwocG5b1gqtv89/nykZ+P0v22P2GDuG1i7D6/CA\n99B8fUoytY6/I6NVO95A3FGe5+K2dMpVWpP4W/FT+s8abuEaKpQrTslcVW6F\nwHOikw+yN+EmwSUkIMjWmACXjOi+ya9gK7jZgRYvHxgh2UEzjjI7UMtpyIh+\n+UQPab9RUIpvrMxPGKZKmPswihuswvggT9WGVlqrVEoeGtPN/0KQgQU39XKI\nhU+3bNKaD007v4qcXIIR6hk5vlNqDPLPni1KOsd288mObAQrOQcPECJZufOO\nhvfeb9iQHpEPUKlVB8kquu9D05T2z7hFhWyeBd2kjJE43OYmiZVfB47+/l3z\n7vyrqSAe+bllxLya1JcCMYwP9Mm7e+kQdLVrFch3ApAgrHoPktlmp5J4JZOm\nBMfFfYYdXqtk/IUW6vC4ASA/ylnG91gGivNAEmJHk3QVXh4bwJ4QEIltCHFC\nTQHk\r\n=UzdU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAMGipphf/tYuV2DL9plHmgAJH26y1/zcxKIBAllSgPyAiEA3U2RlHP/KPURCMl2dgEYo8lCADxTx9ykW6MUs4p95BQ="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.3.1_1567223502825_0.39845646397105905"},"_hasShrinkwrap":false},"0.3.2":{"name":"dat-sdk","version":"0.3.2","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.0.0","hyperdrive":"^9.16.0","node-dat-archive":"^2.2.0","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"e5d316889b7a27f1afe8671066126a7fc2ceb061","_id":"dat-sdk@0.3.2","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-vyK0r93VlCOl2+rURVLm7b435EXC2C/VVBz6Ya8CKbqTvB6yWQuP+DnDE49tACuwOVrlFhjPozATD9YIXWYA6w==","shasum":"28ed9e0deddd636f1099552884ede2a1c387f8fe","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.3.2.tgz","fileCount":13,"unpackedSize":45574,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJde9sSCRA9TVsSAnZWagAAU7YP/A2tJlDi10cPOL4xmZIS\nDB0F2xw5I17QQNj4D53nZlRD6Qds0B0S8Ltg8SxraPXzJaNi6xLTqdQuXzqx\n+kkn11qben6txTXLBl7XChFU7CDlbD+rAWjVPt9nS9Ph2seN/BdjXT3fAQua\nnv9hn1ZNOJZWVyTlm0yeL3pB/s8TM7Eu0NaOuVHMQhirZfIFQzqRmizV5Y7F\nymmBLDZTyj2dCkHRul6/jwvo/W7hKheVBIAyNAzNMPMMeNl9RDr7WzNjVhLE\naoNr/aGXNKQEpnSeXJcPOy46XjmreChgpLBWeOwgiM9pZ/N8kCyUe+MN2N+E\n6WMCRl/4evInjk1kZYU+nsUoB4R9KHNU1WfvT4TPU0NDg/z/hYfIvaH5HdvO\ndxM3DDuYyeGG5xkk/c4iy3T/eZcQVLei7hSfFcXAJ+ceLty8j1AnKuw1TNfb\nYTb3GjubEtMKW3QPqM6nxBi9LKBg1kp7yqIyTqJSMQcYq67qZNaEwTsJSdyi\nn5yx1ure5ZperuXL0pf4bnp0yPi9UVL7OEhbZs5ZoKstpFaXFPjHlGTeveQv\nB9BotIyugkFuFL0MxkNANrx3fCfG/z06PWxr7RqGfUWVQcfnc4nISOsRAtyR\nZFLhaATHsDwHg/OSc44zRaIFQakn7emZc5g/R++Q+5gWjyyLCj4vatZ+WhUd\nhAAV\r\n=Z5kh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDKCHBTKQvJkb2p4aprl+907aP/bJo1+lvpXrHbxYgkkgIhAM3RT+sXgi1ftGx7VPLAQ2BXNPe0rLlL6YLlrzlVO+nC"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.3.2_1568398097554_0.6612068010393788"},"_hasShrinkwrap":false},"0.3.3":{"name":"dat-sdk","version":"0.3.3","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.0.0","hyperdrive":"^9.16.0","node-dat-archive":"^2.2.0","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"fecc6e20c04254d9b007859c39d6bc44e29e11a3","_id":"dat-sdk@0.3.3","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-VBoJ9CJtLzOauGekjlpy7nMbAwxppFWS4GYVpa5+JM84nScBijKGqPrgsUai5AkU+eMoOxKiePH/4vmHnAuLUg==","shasum":"8a64882cff0dbf3ea5dcf630f47626845b00c778","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.3.3.tgz","fileCount":13,"unpackedSize":46127,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdm1oGCRA9TVsSAnZWagAAHysP/2pr/ca+NciTBW8txQP4\n/L3UVdQpYAmv7dG4TLWmhRlVRxJrbje4rlHCng2R1uBdKkdiKF0GhR4127iE\n14VIy84OUU9fQCVJJ86CbG85s+AhhesTwt4Y6r6xJmSTQichlzZyq9mLiiXG\ncl+xgUKI/ImCIHU+/ABa6QtpiSsrGXBja5Ou4iNKopaYkL32D1FaQh+N5wpP\nCpsX044XKa+DDwrzuNSHA/R3/kOqY0HBLULndb68fiFS/bGZYx3WCt++kWoU\nQF3K8Xp0BgZAxGadXQMrxwp/ocKsqv+3WRQWmcOElZjjaI6KLlUz1tYxlqjg\nnjNiwWRdlHIdbtSGZn3QFZScYgAtLhXK/GVh/+4xVSSjVpjc+LJXNSmoqREE\nW7Dr/8pAB4MBqnwG8n2hwGX8GQIxkMwwM8kpvrOWOyGIlv9GdQtyPWu+cfv/\nJK7cxxVswgg1NzQeIrtQRV1fcbpDgIe+9MkuiJoT7h7mK4z8sdTjhVLs/wlX\nUZgyf5Cq/ono3z95QJUu9LccP+Gvjebwhpr49txPOBPZNHyLhe0VMN0xZywc\nghopXDnqqbMCEHwEo3t3uG0sOKp2Db9zVulNwNFjr3l8SK3SYAWVcMx1ZJhD\nBKYQJoKkpj1DwNfmRuzzTgHtvKd6uvV7xw4zCgM6MBAPZrt5bsM7Wo1BEJlL\nnPYM\r\n=KI9K\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD4UkHEu3UrE3bbZ6l7SSVNKsZP0mhd1akmpjOZGxXHuAIhAPOapUJy3iDCsnNoEmEg8gKFmty4iN/AcFq4iULEUiNZ"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.3.3_1570462213458_0.8984802814413413"},"_hasShrinkwrap":false},"0.3.4":{"name":"dat-sdk","version":"0.3.4","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.0.0","hyperdrive":"^9.16.0","node-dat-archive":"^2.2.0","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"d552855a948048481b19785001259cc89d9f2d7a","_id":"dat-sdk@0.3.4","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-tnDBob3G0bCoMimadvT2cO0JQkn2WtJ6Q5yfLpXyUqTN6NsuVrZJQMoORnKUN0Jm7MhoK/a2FI4KYzVtSO5ExQ==","shasum":"af4da3434981825ba65886cecb0065d91a44520c","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.3.4.tgz","fileCount":13,"unpackedSize":46529,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdn19ECRA9TVsSAnZWagAArBEQAISgkEOLMRdiLgbtUVLE\nF2nQ05Q7kT5zR829Bj1qYSLtEsXT7BmaqQFlzKpv1MVvs99i3VZQ1xP/821D\nAhMF/M+HNOwltRYoY5FhqjP29dK5RVBxJY8I/mCm88OQsaHNyKDBxRBpcGKr\n261hSnrua/bXsLWfPAtOlgUbEgswazPDM69g0IFnxpM74gx1e52tXV2XaIh7\nq3j9m7i8KADtpPF0CgaP09ot0g03tGUoaBR+CAKNzx6FjOwD6oOQr1qMI8Kf\nM7E7F4xWEEWTNl4QjJmE2TGVnfsXXLMsJrMUuSGlOGYK7PSWow0gAl3pXicu\nRuXfCXOBDxmZepIG9GmkAQIOWJsX8n9Aco9PD1zJWB8xUFxmwgecJkbfRj5z\nLFPe3Qhu1RXpa2kflqTdUqPqZ4KkGDF6RlaeprVz+z/CHw01LklX7N7WeNTd\nGuGA/5h748icE1XkoGJAPYj6W85pu2PD6ICHXava0zObLnqbmOnQj/LcC3SJ\nLBGdTGvGvxHA4/cLNa21AoERawcSYPljRZ0Y+YU0OcPj1AWUnxyFg+taOwoN\nD2vBJ9PFtu5Pa+9yUwVkp6Z7WTaRVaGTrSX1sFGw5Fo/w3ymhQavdEbu5wLk\nEEU21hzUGcek35HgaC9LFmGhOuYnu7WsKUhZ0uYZ4IL7eEDblJ6UdWQ+jwvP\nssz2\r\n=VJ5N\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCDWWLdPQaA9g5nOBggdlL+Dn/i2qVHL0vadA1ePM6GSwIgGJCcZv+Z5LqpcSuFmn4npZB275VKCOIVXukrTziHBTw="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.3.4_1570725700354_0.3827782823424144"},"_hasShrinkwrap":false},"0.3.5":{"name":"dat-sdk","version":"0.3.5","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.0.0","hyperdrive":"^9.16.0","node-dat-archive":"^2.2.0","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"649a8da28c9f4f571cd45a12dabac436842c42d1","_id":"dat-sdk@0.3.5","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-vR/XCIhtgNCyagZeD3EF8bzgW0n6jUFWVEy+2i4RENPuymJ3ETu+xU5HDGP4fa28ZK59DeQEK3GeuGXcR2DJ7g==","shasum":"e23cea0cd3902cf092caecee4b38782a0f742c07","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.3.5.tgz","fileCount":13,"unpackedSize":46800,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdvaxUCRA9TVsSAnZWagAAL3kP/3m9YCNOQU4dtmtiygRm\ne5eKak7GFyJHlsR6sBlut8mNMcqLDENgKkxgDQcTTyeDlyqSNH5chRenfKZz\nhuXmDS55z78d8op9YZ91BJysWDlrVDzLjNYEnjO4aUqNG6KQUw5YFueommPh\nu2EVh8tWXmsbV6olprfhNN8b06KdQFNAiAqXnaorQlCH8f87hFGLuBEjm2nS\nOSOIqaUAkHor6kMUYiXSYhSVhiCdw8vrJUwhD6PHVwOLTzl/F1AS3KyRvB8o\ntGB0DVVzK3qLMD2ud89Prf+7F6XqxL12cO3rwTx3YJ4Khd/PjAiAKxQclJji\nqJ6TC2y6gu8afWZQ8nKYAO9vvRVhF2wXixseoEvQWWqWztskVO9+Yjlxbjou\nkSA7/FOfaZDQmChXpItxmCWozCnqiGIj/kx0umkDqcvRT6/GJ5sRs1USZ2n9\nWPt4HsBMwYd0OJspUlOTciA8EG5eFoQeP79B5dIVC+5+UVzphyhyafooPYUY\ncpFKSut+rXty+ERFhsHP9Nbg8aHX6b0UdL1CRHVwzvIhBtm5F6K4zWntlhxk\nhXB+NMpbEBnjNTP/IJ6pvyxuwYHpsnflIt6Gb+GIhIS/VOdZGrZ3D0CAbXpN\nU9BUxlYCv1Ma1H72VvjhQyue3g1Kq4VsVAoTTOZjuo3o0egUlv46VGdzmav9\nSRYK\r\n=i/2m\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBnwwqA1LQ+jBUGA8XYARD1hjSj0u+Os8MGCtA6dQQkjAiA7D/kB4XV0IgLeD7DFx9X+maJSwnHBYGE9fE0ZiAZRfw=="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.3.5_1572711507561_0.6949672397361577"},"_hasShrinkwrap":false},"0.3.6":{"name":"dat-sdk","version":"0.3.6","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.2.0","hyperdrive":"^9.16.0","node-dat-archive":"^2.2.0","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"ca2496499b7abc17644a3b8ddbe22ebd69ff7727","_id":"dat-sdk@0.3.6","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-A+wztztRT95UkHQlX4zNqJ5bchvO62seQbv5CKlMatMCvGfzskGwaGpGC2sm3jNgdSLLNQVvJ40/DnGJv6dDvw==","shasum":"a51b194622f88b15a219b2c33a0ac848489fcafe","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-0.3.6.tgz","fileCount":13,"unpackedSize":46800,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdwy5vCRA9TVsSAnZWagAAa0MP/RCb4bLugr4w2NDadh42\ndBKBE/QWFTuNzzjKmJtQoTs0mNuKyY8h9mzqGZ9/GwXQYUGvZy0tf1Wy1el4\nE+6ecHySxETdj1RW1OUMtk8OXbvYSQFZWJkMX+c/obFqYAqQFG0DrSRUPCwe\nSSiFxbu0+S+5RSrcHrp/RVjq5nEELvybz7niBc1EAs4VqqkiArxRijeqjdJk\nsd7KT4wVwqFrEOpNqUpuLYMaqj3C1CL1ifPN/1g+Jv/zc93iYmUa4fQk6VnA\nT92QYMw/S02UG9oiGJ0zJuzxxMgYWrJiJT+PsfrNxqSIv3bCI3CIUxz8zmAO\nUOECzkfVmfebXsIRC1I/w8t4nlTSl4czRTl88/mx9bYrEhA3sWofOwA9upRW\nWeHVRuZm0w2Khig4Ryjt3GBno1NRY/Q983xqhz8yqF6D+0NrIDhWFTfSM7lC\nlGJyueJBEmAB0/9o3tjQuYScShb5QoDkBKVBA8wyDn0uMFOqTQ3JtJ1g4Uv9\nTaP/3VHmJYSZ+BI6vCBsb+6yZ6vmgofyH9sSFjL13l28uSYaBz0/efQC0EQ8\n/Bf0dSAU1rMUy4bG3BNYXLODCZBctY0QrfKHugAPliGdq42472BWQ6GxrCJU\nX7XMu/putW8RXw8RY+F3Nk8YO7o7P8xr1StT/3RhBNBd0DKJUU+p5zGTrRUG\nnwz0\r\n=grur\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFhQb5R+MKV2qnWPV3FoXB8NC4XI8CZSRoS+0ppjgSOSAiEAspo3lO3NzkfkUe414xefA29k32QQnNsIgJhg+rXEMws="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_0.3.6_1573072494546_0.2886338406213014"},"_hasShrinkwrap":false},"1.0.0":{"name":"dat-sdk","version":"1.0.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","./localstorage":"./localstorage-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.2.0","hyperdrive":"^9.16.0","node-dat-archive":"^2.2.0","node-localstorage":"^2.1.5","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"9fe6348ab120b07f37d0de1d456355774c351a9b","_id":"dat-sdk@1.0.0","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-A7xCIFJBenx0iU2DghMy2Zp1gB+qKqXbrhhFw2dXMlx81iRxkel0/QnzZ+Q+GLHKD91hI1vjMNwveRUEUZZIZw==","shasum":"6d8912917ca634ab0b25a371d47df03d407b7d4a","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-1.0.0.tgz","fileCount":15,"unpackedSize":76560,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeLfkYCRA9TVsSAnZWagAAxtUP/RTyY7yJdQNPcleDfgtg\niL2fWGeCpVfmxj8GmznQoNfar7zh2YxBp3D8CInm62tdnCWJm0FkFrn9vbct\n+zV1SNisqwUap+vqtcNCBm8yEo7CLrxAFoLDuPfANsgGi796VqlBqF9/K1v2\nssSTx5YlzQMGMQ2xoZtCRuNr6Lfra+16EAZHG5lXz6Bj0o0QM+6G3StR5TTf\nM3ISpiIrhXgCfGgMJiZFfHCFi0j5tgju8hIXCzShO9vbGBsNyexhAr5vIDOF\nzPrgD46dc6i5740w5vKmxYCWdov6G1OVLe2otw8i4O1rfQiYAsPgWRVcHrA0\nTxYAVgj77GEMnWNfBZu+3d8Z443J+lGwUZMjHaYr/EqdgZ6V4+p58MqgUGkO\nRhRmBSn5Ev07D5+T07NzWDmYisGwNcf1abYCmGPLxtdWnu9rnN83tODi+qoA\npvZK08nOlilblU5w/0m9Qx+Gs+rFYkFiLvMvcED5vxfFbkhWJe/9aua7Y16j\nMHj3pr3kzcJSZvCL4/1cNOHOhh3Ay7RW4Oa2i5oVbwonyAa2W5Aekcw1H8MD\nwmSJsqZ2y4h3aptp0zrMJKMf1CUx1vFF+Un8L0KQdzgdRQKGST7d1UmVQb30\nBGsI/lzfeL+9M27XJyy6L7dzXpR2epXBQn976AvPiuqCun+tAHsBSQ1gbDM8\nnOyo\r\n=a+y2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCdgJz987YMbNPlJPwX0VoLYArJVyQ34kT6cpv8gA+nlgIgZcd21MRQ3J1LGEDM9ga2zxkA7g9YvG6U3PlRd2kB8ww="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_1.0.0_1580071192157_0.9938312779876706"},"_hasShrinkwrap":false},"1.0.1":{"name":"dat-sdk","version":"1.0.1","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","./localstorage":"./localstorage-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.2.0","hyperdrive":"^9.16.0","node-dat-archive":"^2.2.0","node-localstorage":"^2.1.5","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"d52d845f4ac2c1892306137ccef7886356bc3455","_id":"dat-sdk@1.0.1","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-wPStIkPtIXcx6vs5tCk1/YGYAQ8yps8RGTrkK2Mc305lU18N38DhfpsgCmixoSMrjwbu6tc1AaCYRK/TpVp+ZQ==","shasum":"ecf27d3c75d5d72f2906d1068fbdf8dfe101abce","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-1.0.1.tgz","fileCount":15,"unpackedSize":77979,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeMJneCRA9TVsSAnZWagAAiwwQAJ5ty9JLMR2JQUcMTuMw\nmanySlN/pdbe8d5ZKQLjZgO1RLi0GmfyHNhJLqvs8ZHVpGm2KeGbDi8Al//y\ni5zcc/0hXhrpoeq/ELyKUPEvbksS0dDNDSriljRTINB3eIbN1zbMVV0KRsmb\n4PUT4dn85nWV9uad+JyVx4zAXae8zACk6Am65253NDei/U8wDWdb4nejuj9s\nCxP+SiGtLqFxBGV26m0UyNwSXPGcfZIkF3yGEhvdmK8iy1ooJf0zVG2469yy\n3CqlCpbOaTMImSJBDI+0qHT0CXlEBRRFcVsygym6Fr3BZYbg6hNGGWvCvYAL\no3Xxrl+y29R+M/Mlr+Q9XYI0J1Twa8j1co6jbrinT7yDG9VFVZylCjQoouf/\nGAtY0SuTurmzn7gOPYb6wOVQ/dHpR1y+/2/HeiaW6e3vA6vgXIiWUBEw7Hwo\ngGj6RTyk3h1lZD41rlyUd+Q4am1aM8A8tGRyiUc91RvD+rvPnh8gbzDS6eSy\neMnVtX65sXzgBxUJAAv5bQfvB5sJ018qxKVJlk6y/0uDStqWJBtD9lQu1tJ7\nmWJlQcTbS1d/dxScCpEaZAKNVgab5FaXxMFntEIyL+zyo5fe2CpUI8qDHFq+\nlYuhUg/FCW/6VX4cCjIjNG+62X2DQfHjj3JjM4MixwE+11/Ou4CnSpZ3ulnu\nRekN\r\n=qFi4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGkGNmOLJR9UfI0mm9b62b7iy7ccQspO/2r9f6nPUPQOAiA/r5pTqFT1Z7hJkOGocLx0f9MN1JoJDma+Cgqbih7QSw=="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_1.0.1_1580243421889_0.21848823701622933"},"_hasShrinkwrap":false},"1.0.2":{"name":"dat-sdk","version":"1.0.2","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","./localstorage":"./localstorage-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.2.0","hyperdrive":"github:mafintosh/hyperdrive#v9","node-dat-archive":"^2.2.0","node-localstorage":"^2.1.5","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"80893e5fd40bbf5e89ab4f0356bea6bfb3edd7de","_id":"dat-sdk@1.0.2","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-YiwdCcELHH+GFjhJVU+OmVz3YpTL3aAtYvFHN8wrbM83INau6NXd2eF2eB4y6Pw35ZwRNVtlxwoA/M29EoF0ww==","shasum":"0e5cfd9087f1aa23741a886cb9418d67aeaa3a28","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-1.0.2.tgz","fileCount":15,"unpackedSize":78002,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJePGfUCRA9TVsSAnZWagAAPfUP/jdQRp6tNWSgH7f7LL9s\nPxohQo6xWuFPXd6iPN4EkSvW86RV+s9v/V/BPrjLROCzBppBVmse/5mkByGn\nCH/Wm/tHDu7yaWvv8h9xmGd/v90FXJKFnkgKf6Jt3FA9vA06J59dqNy6aJHx\noZgCMLiFK6ppJwzYjfmo7ivPMCIJ/qUngrMS1iAUsDgFC4gCr2iMUhY9plNb\nL/vMFfJKi/iaaWo+ztvXM6d+eJPxZSai9HWI6FYo726kgpWHkQUmWMZZK4k1\nmLYCOH0/4GByqSTrTMiPB9ikb/8/lDEyfpW8kEkRB1LOjbgtWJWroBrCaXi5\nu/xaXOzt0bT8+3q9LtRdrNCDOdQ/HA8iBuUvN+1EEICI+JMQ28ZE2NKgMD//\nhcw1lDwnAQ4HfASVkmC13xK4BeiCMmZ6ilvVGD92yi8gJv8EgUpaAQC+qHDI\nN4VNBWHzfPT+a8t62gzU6ePMPFpQFQCSmMHhnvoVDxXGyMLaO4XeWWEBGKw5\n6Ba58U5+r+n+EaI9MRlBB86KnDeqaSHh859h99phmpBD/zWAU8GU7w3Cj2m5\novmVoz1UKh0tpS1w8CL7z4JH0RMdDDUZmoJwhScUle9qt3gHfk9rEbSDvO0V\nUVYIoDBI70oXcV4V3YSQoOZy4cQWsF9FNufi0nsbqbHVrOcP98XL2TthAKgr\nVG3r\r\n=VN01\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDtA07WS6BEloRmNORR7yb95/3AIUV9oIPxj7fjNKRKjAIhANNiXZTxpSakNrjWc0/da8qWdmnZf2FxODGVTB8tHQa6"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_1.0.2_1581017043906_0.525221605653021"},"_hasShrinkwrap":false},"2.0.0-0":{"name":"dat-sdk","version":"2.0.0-0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","./localstorage":"./localstorage-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","corestore":"^5.0.8","corestore-swarm-networking":"^4.0.3","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^8.7.0","hypercore-crypto":"^1.0.0","hypercore-protocol":"^7.10.0","hyperdrive":"^10.8.10","hyperswarm-web":"^1.0.1","node-localstorage":"^2.1.5","random-access-application":"^1.0.0","random-access-memory":"^3.1.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"540b251629f12a59e829527f0e169e15218fa898","readme":"# sdk\nThe official Dat SDK\n\n[<img src=\"https://datproject.github.io/design/downloads/dat-logo.png\" align=\"right\" width=\"140\">][Dat Project]\n\n## Why use this?\n\nDat consists of a bunch of low level building blocks for working with data in distributed applications. Although this modularity makes it easy to mix and match pieces, it adds complexity when it comes to actually building something.\n\nThe Dat SDK combines the lower level pieces of the Dat ecosystem into high level APIs that you can use across platforms so that you can focus on your application rather than the gritty details of how it works.\n\n## Goals\n\n- High level API\n- Cross-platform with same codebase\n  - ✔ Node\n  - ✔ Web (non-beaker)\n  - ✔ Beaker (Promise API acts as polyfill for Beaker)\n  - React-Native?\n  - Electron?\n\n\n## Installing\n\n[Node.js](https://nodejs.org/) / [Browserify](http://browserify.org/) workflows:\n\n```shell\nnpm install --save dat-sdk\n```\n\n```js\nconst SDK = require('dat-sdk')\nconst SDKPromise = require('dat-sdk/promise')\nconst {DatArchive} = require('dat-sdk/auto')\n```\n\nOr Web Browsers\n\n```html\n<script src=\"https://bundle.run/dat-sdk@1\"></script>\n<script src=\"https://bundle.run/dat-sdk@1/promise.js\"></script>\n<script src=\"https://bundle.run/dat-sdk@1/auto.js\"></script>\n<script>\n  const SDK = window.datSDK\n  // Look at the examples from here\n</script>\n```\n\n## Examples (browserify)\n\nYou can bundle your code with [browserify](http://browserify.org/) using the following command:\n\n```\nbrowserify index.js > bundle.js\n```\n\nThen you can include `bundle.js` in your HTML page.\n\n## Examples (webpack.config.js)\n\nTo bundle with webpack instead of browserify, resolve the `fs` module with the `graceful-fs` module.\n\n```js\nconst path = require('path')\n\nmodule.exports = {\n  entry: './index.js',\n  target: 'web',\n  resolve: {\n    alias: {\n      fs: 'graceful-fs'\n    }\n  },\n  output: {\n    filename: 'bundle.js',\n    path: path.resolve(__dirname, 'dist')\n  }\n}\n```\n\nThen you can include `./dist/bundle.js` in your HTML page.\n\n## Examples (Promise)\n\n```js\n// Auto-detects sane defaults based on your environment\n// Uses Beaker's APIs if they are if they are available\n// DatArchive is the same as Beaker\n// https://beakerbrowser.com/docs/apis/dat\nconst {DatArchive} = require('dat-sdk/auto')\n\nconst archive = await DatArchive.load('dat://dat.foundation')\n\nconst someData = await archive.readFile('/dat.json', 'utf8')\n\nconsole.log('Dat foundation dat.json:', someData)\n\nconst myArchive = await DatArchive.create({\n  title: 'My Archive'\n})\n\nawait myArchive.writeFile('/example.txt', 'Hello World!')\n\n// Log the secret key in case you want to save it for later\nconsole.log(await myArchive.getSecretKey())\n\n// Use a saved secret key\nawait DatArchive.load(someKey, {\n  secretKey: someSecretKey\n})\n```\n\n## API/Examples (Callbacks)\n\n```js\nconst SDK = require('dat-sdk')\nconst { Hypercore, Hyperdrive, resolveName, deleteStorage, destroy } = SDK()\n\nconst archive = Hyperdrive(null, {\n  // This archive will disappear after the process exits\n  // This is here so that running the example doesn't clog up your history\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  //storage: RAI\n})\n\narchive.ready(() => {\n  const url = `dat://${archive.key.toString('hex')}`\n\n  // TODO: Save this for later!\n  console.log(`Here's your URL: ${url}`)\n\n  // Check out the hyperdrive docs for what you can do with it\n  // https://www.npmjs.com/package/hyperdrive#api\n  archive.writeFile('/example.txt', 'Hello World!', () => {\n    console.log('Written example file!')\n  })\n})\n\nresolveName('dat://beakerbrowser.com', (err, url) => {\n  if (err) throw err\n  const archive = Hyperdrive(url)\n\n  archive.readFile('/dat.json', 'utf8', (err, data) => {\n    if (err) throw err\n    console.log(`Beaker's dat.json is ${data}`)\n\n    archive.close((err) => {\n      if (err) throw err\n      deleteStorage(archive.key, (e) => {\n        if (e) throw e\n        console.log('Deleted beaker storage')\n      })\n    })\n  })\n})\n\nconst SOME_URL = 'dat://0a9e202b8055721bd2bc93b3c9bbc03efdbda9cfee91f01a123fdeaadeba303e/'\n\nconst someArchive = Hyperdrive(SOME_URL)\n\nreallyReady(someArchive, () => {\n  someArchive.readdir('/', console.log)\n})\n\n// This make sure you sync up with peers before trying to do anything with the archive\nfunction reallyReady (archive, cb) {\n  if (archive.metadata.peers.length) {\n    archive.metadata.update({ ifAvailable: true }, cb)\n  } else {\n    archive.metadata.once('peer-add', () => {\n      archive.metadata.update({ ifAvailable: true }, cb)\n    })\n  }\n}\n\n// Create a hypercore\n// Check out the hypercore docs for what you can do with it\n// https://github.com/mafintosh/hypercore\nconst myCore = Hypercore(null, {\n  valueEncoding: 'json',\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  // storage: RAI\n})\n\n// Add some data to it\nmyCore.append(JSON.stringify({\n  name: 'Alice'\n}), () => {\n  // Use extension messages for sending extra data over the p2p connection\n  const discoveryCoreKey = 'dat://bee80ff3a4ee5e727dc44197cb9d25bf8f19d50b0f3ad2984cfe5b7d14e75de7'\n  const discoveryCore = new Hypercore(discoveryCoreKey, {\n    extensions: ['discovery']\n  })\n\n  // When you find a new peer, tell them about your core\n  discoveryCore.on('peer-add', (peer) => {\n    console.log('Got a peer!')\n    peer.extension('discovery', myCore.key)\n  })\n\n  // When a peer tells you about their core, load it\n  discoveryCore.on('extension', (type, message) => {\n    console.log('Got extension message', type, message)\n    if (type !== 'discovery') return\n    discoveryCore.close()\n\n    const otherCore = new Hypercore(message, {\n      valueEncoding: 'json',\n      persist: false\n    })\n\n    // Render the peer's data from their core\n    otherCore.get(0, console.log)\n  })\n})\n\nconst hypertrie = require('hypertrie')\n\n// Pass in hypercores from the SDK into other dat data structures\n// Check out what you can do with hypertrie from there:\n// https://github.com/mafintosh/hypertrie\nconst trie = hypertrie(null, {\n  feed: new Hypercore(null, {\n    persist: false\n  })\n})\n\ntrie.put('key', 'value', () => {\n  trie.get('key', (err, node) => {\n    console.log('Got key: ', node.key)\n    console.log('Loaded value from trie: ', node.value)\n  })\n})\n\n```\n\n## API (Promise)\n\n### `const {DatArchive, destroy} = SDK({ storageOpts, swarmOpts, driveOpts, coreOpts, dnsOpts })`\n\nThis initializes the Dat SDK.\n\n\n- `storageOpts`: This lets you configure how the SDK will store data. Used by the [universal-dat-storage](https://github.com/RangerMauve/universal-dat-storage) module.\n  - `application: 'dat'`: The name of the application using the SDK if you want to have the data stored separately. Used by [env-paths](https://github.com/sindresorhus/env-paths#pathsdata) to generate the storageLocation\n  - `storageLocation: null`: A location (on disk) to store the archives in.\n- `swarmOpts`: This lets you configure [discovery-swarm](https://www.npmjs.com/package/discovery-swarm) and [discovery-swarm-web](https://www.npmjs.com/package/discovery-swarm-web)\n  - `id`: The ID to use when doing p2p traffic\n  - `maxConnections`: The maximum number of connections to keep for this swarm.\n  - `extensions: []`: The set of extension messages to use when replicating with peers\n  - `utp: true`: Whether to use utp in discovery-swarm\n  - `tcp: true`: Whether to use tcp in discovery-swarm\n  - `bootstrap: ['signal.mauve.moe']`: The WebRTC bootstrap server list used by discovery-swarm-web\n  - `discovery: 'discoveryswarm.mauve.moe'`: The proxy server used by discovery-swarm-web\n- `driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n- `coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `await destroy()`\n\nRelease all resources being used by the SDK so you can safely stop your process.\n\n### `const archive = await DatArchive.load(location, opts)`\n\nThis loads up a Dat Archive for the given URL / Key / File path.\n\n- `location`: This is either the `dat://` URL (which might have a domain), a dat key, or a file path for your archive.\n- `opts`: These are options for configuring this archive\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n\n### `const archive = await DatArchive.create(opts)`\n\nThis creates a new Dat Archive.\n\n- `opts` These are the options for the archive's metadata and it's properties\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n  - `title`: The title of the archive\n  - `description`: A brief description of what the archive contains\n  - `type`: An array of strings for the type of archive this is. See the [manifest](https://beakerbrowser.com/docs/apis/manifest.html#type) docs for more info.\n\n### `const archive = await DatArchive.fork(url, opts)`\n\nCreate a new archive based on the data within another archive\n\n- `url` The URL of the archive to fork off of\n- `opts` These options will be used in the new archive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n  - `title`: The title of the archive\n  - `description`: A brief description of what the archive contains\n  - `type`: An array of strings for the type of archive this is. See the [manifest](https://beakerbrowser.com/docs/apis/manifest.html#type) docs for more info.\n\n### `await DatArchive.unlink(url)`\n\nDelete the storage for an archive.\n\n- `url`: The URL of the archive to delete\n\n### `const archive = await DatArchive.selectArchive()`\n\nPrompt the user to select an archive from the ones they have created locally. The implementation is super hacky, so use with caution.\n\n### `const url = await DatArchive.resolveName(url)`\n\nResolve a URL that uses dat-dns to the raw `dat://` url.\n\n- `url`: The `dat://` URL with a domain to resolve\n\n#### `const url = archive.url`\n\nGet the URL for the given archive.\n\n#### `const info = await archive.getInfo()`\n\nGet metadata about the archive\n\n- `info`: The metadata related to the archive.\n  - `key`: string (the archive public key)\n  - `url`: string (the archive URL)\n  - `isOwner`: boolean (is the user the owner of this archive?)\n  - `version`: number (the archive's current revision number)\n  - `peers`: number (the number of active connections for the archive)\n  - `mtime`: number (the walltime of the last received update; is reliable)\n  - `size`: number (bytes, the size-on-disk of the archive)\n  - `title`: string (the archive title)\n  - `description`: string (the archive description)\n  - `type`: array of strings (the archive's type identifiers)\n  - `links`: object (top-level links to other resources)\n\n#### `await archive.configure(configuration)`\n\nUpdate the metadata about the archive.\n\n- `configuration`: The metadata to update\n  - `title` String. The title of the archive.\n  - `description` String. The description of the archive.\n  - `type` Array<String>. The archive’s type identifiers. Learn more.\n  - `links` Object. Top-level links to other resources. Learn more.\n  - `web_root` String. Path of the folder from which all web requests should be served.\n  - `fallback_page` String. Path to a fallback page to serve instead of the default 404 page.\n\n#### `const stat = await archive.stat(path)`\n\n- `path`: The path to get stats about from the archive\n- `stat.isDirectory()`: Check if the path is a directory\n- `stat.isFile()`: Check if the path is a file\n- `stat.size`: number (bytes)\n- `stat.blocks`: number (number of data blocks in the metadata)\n- `stat.downloaded`: number (number of blocks downloaded, if a remote archive)\n- `stat.mtime`: Date (last modified time; not reliable)\n- `stat.ctime`: Date (creation time; not reliable)`\n\n#### `const data = await archive.readFile(path, opts)`\n\n- `path` The path to the file you wish to read\n- `opts.encoding`: The encoding to read the file with, can be one of `utf8`, `base64`, `hex`, and `binary`\n- `data`: The entire contents of the file, either as a string, or an ArrayBuffer if you used the `binary` encoding.\n\n#### `const list = await archive.readdir(path, opts)`\n\nLists the files and folders within a directory.\n\n- `path`: The path to the directory you wish to read\n- `opts`\n  - `recursive`: Set to `true` to list subdirectories, too\n  - `stat`: Get the `Stat` objects instead of names.\n- `list`: Either a list of the file/folder names or a list of the Stat object for those items.\n\n#### `await archive.writeFile(path, data, opts)`\n\nWrite a file to your archive.\n\n- `path`: The location to write your file to.\n- `data`: Either a string or ArrayBuffer for the data you wish to save\n- `opts.encoding`: The encoding to use when writing. Must be one of `utf8`, `base64`, `hex`, or `binary`. Encoding will default to `utf8` for strings, and `binary` for ArrayBuffers.\n\n#### `await archive.mkdir(path)`\n\nCreate a directory at the given path. Will fail if the parent directory doesn't exist.\n\n- `path`: The path to the directory\n\n#### `await archive.unlink(path)`\n\nDelete the file at the given path.\n\n- `path`: The path to the file\n\n#### `await rmdir(path, opts)`\n\nDeletes the directory at the given path.\n\n- `path`: The path to the directory\n- `opts.recursive`: Whether to delete subfolders / files.\n\n#### `await archive.copy(path, dstPath)`\n\nCopy a file from one location to another.\n\n- `path`: The path to the file / directory to copy from.\n- `dstPath`: The location the file/directory should be copied to\n\n#### `await archive.rename(oldPath, newPath)`\n\nRename / move a file or directory.\n\n- `oldPath`: The path of the file/directory to rename\n- `newPath`: What the file/directory should be renamed to.\n\n#### `const history = await archive.history({opts})`\n\nList the history of all the changes in this archive.\n\n- `opts`: The options for how to fetch the history of the archive\n  - `start`: Where in the history to start reading\n  - `end`: Where in the history to stop reading\n  - `reverse`: Set to `true` to iterate through the history backwards\n- `history`: An array of history items representing changes\n  - `path`: Which file / directory got modified.\n  - `version`: The version number the archive was at for this item\n  - `type`: Either `put` for additions or `del` for deletions\n\n#### `const olderArchive = archive.checkout(version)`\n\nGet a view of the archive as it was at an earlier version.\n\n- `version`: The integer representing the version you whish to look at. This correlates to the version in the history.\n\n#### `await archive.download(path)`\n\nDownload the file or folder at the given path from the network. Use `/` to download the entire archive.\n\n#### `const events = archive.watch(pattern, onInvalidated)`\n\n```js\nconst events = archive.watch(['**/*.md'])\nevents.addEventListener('changed', ({path}) => console.log(path, 'changed!'))\n\nevents.close() // Stop listening for changes\n```\n\nWatch for changes in the archive.\n\n- `pattern`: This can either be omitted to view all changes, or have an [anymatch](https://www.npmjs.com/package/anymatch) pattern to filter out just the changes you want.\n- `onInvalidated`: You can optionally pass in this function to listen for changes instead of using an event listener.\n\n#### `archive.addEventListener('network-changed', ({peers}) => void 0)`\n\nListen for changes in the number of peers connected to for the archive.\n\n- `peers`: The number of connected peers\n\n#### `archive.addEventListener('download', ({feed, block, bytes}) => void 0)`\n\nListen for download progress from the archive\n\n- `feed`: The data feed the block was part of. Either `metadata` or `content`\n- `block`: The index of the block downloaded\n- `bytes`: The size of the block in bytes\n\n#### `archive.addEventListener('upload', ({feed, block, bytes}) => void 0)`\n\nListen for upload progress from the archive.\n\n- `feed`: The data feed the block was part of. Either `metadata` or `content`\n- `block`: The index of the block uploaded\n- `bytes`: The size of the block in bytes\n\n#### `archive.addEventListener('sync', ({feed}) => void 0)`\n\nEmitted when all known data has been downloaded\n\n## API (Callbacks)\n\n### `const {Hypercore, Hyperdrive, resolveName, deleteStorage, destroy} = SDK({ storageOpts, swarmOpts, driveOpts, coreOpts, dnsOpts })`\n\nCreates an instance of the Dat SDK based on the options.\n\n- `storageOpts`: This lets you configure how the SDK will store data. Used by the [universal-dat-storage](https://github.com/RangerMauve/universal-dat-storage) module.\n  - `application: 'dat'`: The name of the application using the SDK if you want to have the data stored separately. Used by [env-paths](https://github.com/sindresorhus/env-paths#pathsdata) to generate the storageLocation\n  - `storageLocation: null`: A location (on disk) to store the archives in.\n- `swarmOpts`: This lets you configure [discovery-swarm](https://www.npmjs.com/package/discovery-swarm) and [discovery-swarm-web](https://www.npmjs.com/package/discovery-swarm-web)\n  - `id`: The ID to use when doing p2p traffic\n  - `maxConnections`: The maximum number of connections to keep for this swarm.\n  - `extensions: []`: The set of extension messages to use when replicating with peers\n  - `utp: true`: Whether to use utp in discovery-swarm\n  - `tcp: true`: Whether to use tcp in discovery-swarm\n  - `bootstrap: ['signal.mauve.moe']`: The WebRTC bootstrap server list used by discovery-swarm-web\n  - `discovery: 'discoveryswarm.mauve.moe'`: The proxy server used by discovery-swarm-web\n- `driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n- `coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `destroy(cb)`\n\nThis closes all resources used by the SDK so you can safely end your process. `cb` will be invoked once resources are closed or if there's an error.\n\n### `resolveName(url, cb(err, key))`\n\nResolve a DNS name to a Dat key.\n\n  - `url` is a Dat URL like `dat://dat.foundation`\n  - `cb` will get invoked with the result of the resolve\n  - `key` will be the Dat key that you can pass to `hyperdrive`\n  - `err` will be any errors that happen during resolution\n\n### `deleteStorage(key, cb)`\n\nDelete the storage for a given archive or hypercore key.\n\n- `key` should be the key for the hypercore or hyperdrive that should be deleted\n- `cb` will be invoked after the deletion is over.\n\n### `const archive = Hyperdrive(location, opts)`\n\nThis initializes a Hyperdrive (aka a Dat archive), the SDK will begin finding peers for it and will de-duplicate calls to initializing the same archive more than once.\n\n- `location`: This **must** be provided. It's either a path for where the archive should be stored, or a Dat URL / key. If this is null, a new key will be generated.\n- `opts`: These are the options for configuring the hyperdrive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n  - `secretKey`: A secret key for granting write access. This can be useful when restoring backups.\n\nThe rest of the Hyperdrive docs were taken from the [Hyperdrive README](https://github.com/mafintosh/hyperdrive/blob/v9/README.md)\n\n#### `archive.version`\n\nGet the current version of the archive (incrementing number).\n\n#### `archive.key`\n\nThe public key identifying the archive.\n\n#### `archive.discoveryKey`\n\nA key derived from the public key that can be used to discovery other peers sharing this archive.\n\n#### `archive.writable`\n\nA boolean indicating whether the archive is writable.\n\n#### `archive.on('ready')`\n\nEmitted when the archive is fully ready and all properties has been populated.\n\n#### `archive.on('update')`\n\nEmitted when the archive has got a new change.\n\n#### `archive.on('error', err)`\n\nEmitted when a critical error during load happened.\n\n#### `archive.on('close')`\n\nEmitted when the archive has been closed\n\n#### `archive.on('extension', name, message, peer)`\n\nEmitted when a peer sends you an extension message with `archive.extension()`.\nYou can respond with `peer.extension(name, message)`.\n\n#### `var oldDrive = archive.checkout(version, [opts])`\n\nCheckout a readonly copy of the archive at an old version. Options are used to configure the `oldDrive`:\n\n```js\n{\n  metadataStorageCacheSize: 65536 // how many entries to use in the metadata hypercore's LRU cache\n  contentStorageCacheSize: 65536 // how many entries to use in the content hypercore's LRU cache\n  treeCacheSize: 65536 // how many entries to use in the append-tree's LRU cache\n}\n```\n\n#### `archive.download([path], [callback])`\n\nDownload all files in path of current version.\nIf no path is specified this will download all files.\n\nYou can use this with `.checkout(version)` to download a specific version of the archive.\n\n``` js\narchive.checkout(version).download()\n```\n\n#### `var stream = archive.history([options])`\n\nGet a stream of all changes and their versions from this archive.\n\n#### `archive.extension(name, message)`\n\nSend an extension message to connected peers. [Read more in the hypercore docs](https://github.com/mafintosh/hypercore#feedextensionname-message).\n\n#### `var stream = archive.createReadStream(name, [options])`\n\nRead a file out as a stream. Similar to fs.createReadStream.\n\nOptions include:\n\n``` js\n{\n  start: optionalByteOffset, // similar to fs\n  end: optionalInclusiveByteEndOffset, // similar to fs\n  length: optionalByteLength\n}\n```\n\n#### `archive.readFile(name, [options], callback)`\n\nRead an entire file into memory. Similar to fs.readFile.\n\nOptions can either be an object or a string\n\nOptions include:\n```js\n{\n  encoding: string\n  cached: true|false // default: false\n}\n```\nor a string can be passed as options to simply set the encoding - similar to fs.\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `var stream = archive.createDiffStream(version, [options])`\n\nDiff this archive with another version. `version` can both be a version number of a checkout instance of the archive. The `data` objects looks like this\n\n``` js\n{\n  type: 'put' | 'del',\n  name: '/some/path/name.txt',\n  value: {\n    // the stat object\n  }\n}\n```\n\n#### `var stream = archive.createWriteStream(name, [options])`\n\nWrite a file as a stream. Similar to fs.createWriteStream.\nIf `options.cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `archive.writeFile(name, buffer, [options], [callback])`\n\nWrite a file from a single buffer. Similar to fs.writeFile.\n\n#### `archive.unlink(name, [callback])`\n\nUnlinks (deletes) a file. Similar to fs.unlink.\n\n#### `archive.mkdir(name, [options], [callback])`\n\nExplictly create an directory. Similar to fs.mkdir\n\n#### `archive.rmdir(name, [callback])`\n\nDelete an empty directory. Similar to fs.rmdir.\n\n#### `archive.readdir(name, [options], [callback])`\n\nLists a directory. Similar to fs.readdir.\n\nOptions include:\n\n``` js\n{\n    cached: true|false, // default: false\n}\n```\n\nIf `cached` is set to `true`, this function returns results from the local version of the archive’s append-tree. Default behavior is to fetch the latest remote version of the archive before returning list of directories.\n\n#### `archive.stat(name, [options], callback)`\n\nStat an entry. Similar to fs.stat. Sample output:\n\n```\nStat {\n  dev: 0,\n  nlink: 1,\n  rdev: 0,\n  blksize: 0,\n  ino: 0,\n  mode: 16877,\n  uid: 0,\n  gid: 0,\n  size: 0,\n  offset: 0,\n  blocks: 0,\n  atime: 2017-04-10T18:59:00.147Z,\n  mtime: 2017-04-10T18:59:00.147Z,\n  ctime: 2017-04-10T18:59:00.147Z,\n  linkname: undefined }\n```\n\nThe output object includes methods similar to fs.stat:\n\n``` js\nvar stat = archive.stat('/hello.txt')\nstat.isDirectory()\nstat.isFile()\n```\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.lstat(name, [options], callback)`\n\nStat an entry but do not follow symlinks. Similar to fs.lstat.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.access(name, [options], callback)`\n\nSimilar to fs.access.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.open(name, flags, [mode], callback)`\n\nOpen a file and get a file descriptor back. Similar to fs.open.\n\nNote that currently only read mode is supported in this API.\n\n#### `archive.read(fd, buf, offset, len, position, callback)`\n\nRead from a file descriptor into a buffer. Similar to fs.read.\n\n#### `archive.close(fd, [callback])`\n\nClose a file. Similar to fs.close.\n\n#### `archive.close([callback])`\n\nCloses all open resources used by the archive.\nThe archive should no longer be used after calling this.\n\n### `const feed = Hypercore(key, opts)`\n\nInitializes a Hypercore (aka Feed) and begins replicating it.\n\n- `key`: This is the dat key for the feed, you can omit it if you want to create a new hypercore instance\n- `opts`: The options for configuring this feed\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n  - `secretKey`: The secret key to use for the feed. Useful for restoring from backups.\n\n#### `feed.append(data, [callback])`\n\nAppend a block of data to the feed.\n\nCallback is called with `(err, seq)` when all data has been written at the returned `seq` or an error occurred.\n\n#### `feed.get(index, [options], callback)`\n\nGet a block of data.\nIf the data is not available locally this method will prioritize and wait for the data to be downloaded before calling the callback.\n\nOptions include\n\n``` js\n{\n  wait: true, // wait for index to be downloaded\n  timeout: 0, // wait at max some milliseconds (0 means no timeout)\n  valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the feed's valueEncoding\n}\n```\n\nCallback is called with `(err, data)`\n\n#### `feed.getBatch(start, end, [options], callback)`\n\nGet a range of blocks efficiently. Options include\n\n``` js\n{\n  wait: sameAsAbove,\n  timeout: sameAsAbove,\n  valueEncoding: sameAsAbove\n}\n```\n\n#### `feed.head([options], callback)`\n\nGet the block of data at the tip of the feed. This will be the most recently\nappended block.\n\nAccepts the same `options` as `feed.get()`.\n\n#### `feed.download([range], [callback])`\n\nDownload a range of data. Callback is called when all data has been downloaded.\nA range can have the following properties:\n\n``` js\n{\n  start: startIndex,\n  end: nonInclusiveEndIndex,\n  linear: false // download range linearly and not randomly\n}\n```\n\nIf you do not mark a range the entire feed will be marked for download.\n\nIf you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire\nfeed will be marked for download for you when the feed is created.\n\n#### `feed.undownload(range)`\n\nCancel a previous download request.\n\n#### `feed.signature([index], callback)`\n\nGet a signature proving the correctness of the block at index, or the whole stream.\n\nCallback is called with `(err, signature)`.\nThe signature has the following properties:\n``` js\n{\n  index: lastSignedBlock,\n  signature: Buffer\n}\n```\n\n#### `feed.verify(index, signature, callback)`\n\nVerify a signature is correct for the data up to index, which must be the last signed\nblock associated with the signature.\n\nCallback is called with `(err, success)` where success is true only if the signature is\ncorrect.\n\n#### `feed.rootHashes(index, callback)`\n\nRetrieve the root *hashes* for given `index`.\n\nCallback is called with `(err, roots)`; `roots` is an *Array* of *Node* objects:\n```\nNode {\n  index: location in the merkle tree of this root\n  size: total bytes in children of this root\n  hash: hash of the children of this root (32-byte buffer)\n}\n```\n\n\n#### `var number = feed.downloaded([start], [end])`\n\nReturns total number of downloaded blocks within range.\nIf `end` is not specified it will default to the total number of blocks.\nIf `start` is not specified it will default to 0.\n\n#### `var bool = feed.has(index)`\n\nReturn true if a data block is available locally.\nFalse otherwise.\n\n#### `var bool = feed.has(start, end)`\nReturn true if all data blocks within a range are available locally.\nFalse otherwise.\n\n#### `feed.clear(start, [end], [callback])`\n\nClear a range of data from the local cache.\nWill clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.\n\n`end` defaults to `start + 1`.\n\n#### `feed.seek(byteOffset, callback)`\n\nSeek to a byte offset.\n\nCalls the callback with `(err, index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is\nthe relative byte offset in the data block.\n\n#### `feed.update([minLength], [callback])`\n\nWait for the feed to contain at least `minLength` elements.\nIf you do not provide `minLength` it will be set to current length + 1.\n\nDoes not download any data from peers except for a proof of the new feed length.\n\n``` js\nconsole.log('length is', feed.length)\nfeed.update(function () {\n  console.log('length has increased', feed.length)\n})\n```\n\n#### `var stream = feed.createReadStream([options])`\n\nCreate a readable stream of data.\n\nOptions include:\n\n``` js\n{\n  start: 0, // read from this index\n  end: feed.length, // read until this index\n  snapshot: true, // if set to false it will update `end` to `feed.length` on every read\n  tail: false, // sets `start` to `feed.length`\n  live: false, // set to true to keep reading forever\n  timeout: 0, // timeout for each data event (0 means no timeout)\n  wait: true // wait for data to be downloaded\n}\n```\n\n#### `var stream = feed.createWriteStream()`\n\nCreate a writable stream.\n\n#### `feed.close([callback])`\n\nFully close this feed.\n\nCalls the callback with `(err)` when all storage has been closed.\n\n#### `feed.audit([callback])`\n\nAudit all data in the feed. Will check that all current data stored\nmatches the hashes in the merkle tree and clear the bitfield if not.\n\nWhen done a report is passed to the callback that looks like this:\n\n```js\n{\n  valid: 10, // how many data blocks matches the hashes\n  invalid: 0, // how many did not\n}\n```\n\nIf a block does not match the hash it is cleared from the data bitfield.\n\n#### `feed.writable`\n\nCan we append to this feed?\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.readable`\n\nCan we read from this feed? After closing a feed this will be false.\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.key`\n\nBuffer containing the public key identifying this feed.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.discoveryKey`\n\nBuffer containing a key derived from the feed.key.\nIn contrast to `feed.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same feed, without leaking the feed key.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.length`\n\nHow many blocks of data are available on this feed?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.byteLength`\n\nHow much data is available on this feed in bytes?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.stats`\n\nReturn per-peer and total upload/download counts.\n\nThe returned object is of the form:\n```js\n{\n  totals: {\n    uploadedBytes: 100,\n    uploadedBlocks: 1,\n    downloadedBytes: 0,\n    downloadedBlocks: 0\n  },\n  peers: [\n    {\n      uploadedBytes: 100,\n      uploadedBlocks: 1,\n      downloadedBytes: 0,\n      downloadedBlocks: 0\n    },\n    ...\n  ]\n}\n```\n\nStats will be collected by default, but this can be disabled by setting `opts.stats` to false.\n\n#### `feed.on('ready')`\n\nEmitted when the feed is ready and all properties have been populated.\n\n#### `feed.on('error', err)`\n\nEmitted when the feed experiences a critical error.\n\n#### `feed.on('download', index, data)`\n\nEmitted when a data block has been downloaded.\n\n#### `feed.on('upload', index, data)`\n\nEmitted when a data block is uploaded.\n\n#### `feed.on('append')`\n\nEmitted when the feed has been appended to (i.e. has a new length / byteLength)\n\n#### `feed.on('sync')`\n\nEmitted every time ALL data from `0` to `feed.length` has been downloaded.\n\n#### `feed.on('close')`\n\nEmitted when the feed has been fully closed\n\n---\n\n[Dat Project]: https://dat.foundation\n","readmeFilename":"README.md","_id":"dat-sdk@2.0.0-0","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-JZf+/pmGaNIc9Uuv0yIZHIgkdG16qw/gUfZZF1m19DlVMnMlhdMafLkXp+PdLQB1YwgdET3aIjStegzg0/pGHQ==","shasum":"3f8c619d6ea4fec356f34bb18a098aeb7472cc94","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.0.0-0.tgz","fileCount":14,"unpackedSize":62925,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeQgBMCRA9TVsSAnZWagAAP48P/0RsWnRvB4Rtv0X2u9sN\n7zZwiiPjwjLnMyKWKrwOk4sYNbpkvvAHEmBUCRFBiW1tcVjG3DAFTNNTtdQb\nE9tlDdIxILiQuPccXEL02Tj33qNl/5WtEBMtHyKDm3YrdRjxfA4yeezhyJhs\nJsqQRCS0wYlnOMpm1FbWAbxhHAZfswXHp1lx74nNj0Nw6WodRgYkbIYHobTz\nM9ktb1EHoSMrSVygyEi2CvVydRD+UL90UEV3iGFWJPW/rnqsFoAiIbYPeovG\nIsEFXQ6namOvGty3Vzkrr8rvmFSB7PNyXQkpi8Zg67MiLsztzNsf//RlK0HP\nH8v5Sc2Mrmc6SkD5WLkzHTiKkoWwc0cQvBsyNsg50v0fYMGZl+CunbY6Kncz\nZJ5dc15MAn5NfbT3vhOmIVde+7Ifrxhp2w5DwaJubW43aacOQDmoOfcMPedk\nwMerAlALJNQYOc1vPmvy+dWYaDXY3XFMyAN+zs84osalDz02FET+dOT2TseN\nKV3PnCoLJDRV3UKn77Zq5vASsm/yOkrk+KEUNmSqoAVtzyPglm93m+9OTc55\nE7CnNyoUE9YEIPpO+7XQV4amUPGKQfQalkcwmkdvdsFmPQzhwqwyuuk8hg9q\nNhutkmJ+GM4DknQceYyt+y7TlUG8g+vuUaCxw0eW/NH08WrDxnFn4L3FiCh5\nnIkh\r\n=kUbn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDrTqzgvau4GtVvp1qbF70ymUYX1B6uZoBRnXcqpkeGHwIhAOi7jdSJcMbYBQlKcMYqNiYRDNZlbfskVvnMjqmzh3ho"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.0.0-0_1581383755562_0.3138399136485568"},"_hasShrinkwrap":false},"2.0.0-1":{"name":"dat-sdk","version":"2.0.0-1","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","./localstorage":"./localstorage-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^1.1.0","@geut/hyperdrive-promise":"^3.0.0","concat-stream":"^2.0.0","corestore":"^5.0.8","corestore-swarm-networking":"^4.0.3","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^8.7.0","hypercore-crypto":"^1.0.0","hypercore-protocol":"^7.10.0","hyperdrive":"^10.8.10","hyperswarm-web":"^1.0.1","node-localstorage":"^2.1.5","random-access-application":"^1.0.0","random-access-memory":"^3.1.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"1158f80cd0f901a687ce307b8c3252ccd906845b","readme":"# sdk\nThe official Dat SDK\n\n[<img src=\"https://datproject.github.io/design/downloads/dat-logo.png\" align=\"right\" width=\"140\">][Dat Project]\n\n## Why use this?\n\nDat consists of a bunch of low level building blocks for working with data in distributed applications. Although this modularity makes it easy to mix and match pieces, it adds complexity when it comes to actually building something.\n\nThe Dat SDK combines the lower level pieces of the Dat ecosystem into high level APIs that you can use across platforms so that you can focus on your application rather than the gritty details of how it works.\n\n## Goals\n\n- High level API\n- Cross-platform with same codebase\n  - ✔ Node\n  - ✔ Web (non-beaker)\n  - ✔ Beaker (Promise API acts as polyfill for Beaker)\n  - React-Native?\n  - Electron?\n\n\n## Installing\n\n[Node.js](https://nodejs.org/) / [Browserify](http://browserify.org/) workflows:\n\n```shell\nnpm install --save dat-sdk\n```\n\n```js\nconst SDK = require('dat-sdk')\nconst SDKPromise = require('dat-sdk/promise')\nconst {DatArchive} = require('dat-sdk/auto')\n```\n\nOr Web Browsers\n\n```html\n<script src=\"https://bundle.run/dat-sdk@1\"></script>\n<script src=\"https://bundle.run/dat-sdk@1/promise.js\"></script>\n<script src=\"https://bundle.run/dat-sdk@1/auto.js\"></script>\n<script>\n  const SDK = window.datSDK\n  // Look at the examples from here\n</script>\n```\n\n## Examples (browserify)\n\nYou can bundle your code with [browserify](http://browserify.org/) using the following command:\n\n```\nbrowserify index.js > bundle.js\n```\n\nThen you can include `bundle.js` in your HTML page.\n\n## Examples (webpack.config.js)\n\nTo bundle with webpack instead of browserify, resolve the `fs` module with the `graceful-fs` module.\n\n```js\nconst path = require('path')\n\nmodule.exports = {\n  entry: './index.js',\n  target: 'web',\n  resolve: {\n    alias: {\n      fs: 'graceful-fs'\n    }\n  },\n  output: {\n    filename: 'bundle.js',\n    path: path.resolve(__dirname, 'dist')\n  }\n}\n```\n\nThen you can include `./dist/bundle.js` in your HTML page.\n\n## Examples (Promise)\n\n```js\n// Auto-detects sane defaults based on your environment\n// Uses Beaker's APIs if they are if they are available\n// DatArchive is the same as Beaker\n// https://beakerbrowser.com/docs/apis/dat\nconst {DatArchive} = require('dat-sdk/auto')\n\nconst archive = await DatArchive.load('dat://dat.foundation')\n\nconst someData = await archive.readFile('/dat.json', 'utf8')\n\nconsole.log('Dat foundation dat.json:', someData)\n\nconst myArchive = await DatArchive.create({\n  title: 'My Archive'\n})\n\nawait myArchive.writeFile('/example.txt', 'Hello World!')\n\n// Log the secret key in case you want to save it for later\nconsole.log(await myArchive.getSecretKey())\n\n// Use a saved secret key\nawait DatArchive.load(someKey, {\n  secretKey: someSecretKey\n})\n```\n\n## API/Examples (Callbacks)\n\n```js\nconst SDK = require('dat-sdk')\nconst { Hypercore, Hyperdrive, resolveName, deleteStorage, destroy } = SDK()\n\nconst archive = Hyperdrive(null, {\n  // This archive will disappear after the process exits\n  // This is here so that running the example doesn't clog up your history\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  //storage: RAI\n})\n\narchive.ready(() => {\n  const url = `dat://${archive.key.toString('hex')}`\n\n  // TODO: Save this for later!\n  console.log(`Here's your URL: ${url}`)\n\n  // Check out the hyperdrive docs for what you can do with it\n  // https://www.npmjs.com/package/hyperdrive#api\n  archive.writeFile('/example.txt', 'Hello World!', () => {\n    console.log('Written example file!')\n  })\n})\n\nresolveName('dat://beakerbrowser.com', (err, url) => {\n  if (err) throw err\n  const archive = Hyperdrive(url)\n\n  archive.readFile('/dat.json', 'utf8', (err, data) => {\n    if (err) throw err\n    console.log(`Beaker's dat.json is ${data}`)\n\n    archive.close((err) => {\n      if (err) throw err\n      deleteStorage(archive.key, (e) => {\n        if (e) throw e\n        console.log('Deleted beaker storage')\n      })\n    })\n  })\n})\n\nconst SOME_URL = 'dat://0a9e202b8055721bd2bc93b3c9bbc03efdbda9cfee91f01a123fdeaadeba303e/'\n\nconst someArchive = Hyperdrive(SOME_URL)\n\nreallyReady(someArchive, () => {\n  someArchive.readdir('/', console.log)\n})\n\n// This make sure you sync up with peers before trying to do anything with the archive\nfunction reallyReady (archive, cb) {\n  if (archive.metadata.peers.length) {\n    archive.metadata.update({ ifAvailable: true }, cb)\n  } else {\n    archive.metadata.once('peer-add', () => {\n      archive.metadata.update({ ifAvailable: true }, cb)\n    })\n  }\n}\n\n// Create a hypercore\n// Check out the hypercore docs for what you can do with it\n// https://github.com/mafintosh/hypercore\nconst myCore = Hypercore(null, {\n  valueEncoding: 'json',\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  // storage: RAI\n})\n\n// Add some data to it\nmyCore.append(JSON.stringify({\n  name: 'Alice'\n}), () => {\n  // Use extension messages for sending extra data over the p2p connection\n  const discoveryCoreKey = 'dat://bee80ff3a4ee5e727dc44197cb9d25bf8f19d50b0f3ad2984cfe5b7d14e75de7'\n  const discoveryCore = new Hypercore(discoveryCoreKey, {\n    extensions: ['discovery']\n  })\n\n  // When you find a new peer, tell them about your core\n  discoveryCore.on('peer-add', (peer) => {\n    console.log('Got a peer!')\n    peer.extension('discovery', myCore.key)\n  })\n\n  // When a peer tells you about their core, load it\n  discoveryCore.on('extension', (type, message) => {\n    console.log('Got extension message', type, message)\n    if (type !== 'discovery') return\n    discoveryCore.close()\n\n    const otherCore = new Hypercore(message, {\n      valueEncoding: 'json',\n      persist: false\n    })\n\n    // Render the peer's data from their core\n    otherCore.get(0, console.log)\n  })\n})\n\nconst hypertrie = require('hypertrie')\n\n// Pass in hypercores from the SDK into other dat data structures\n// Check out what you can do with hypertrie from there:\n// https://github.com/mafintosh/hypertrie\nconst trie = hypertrie(null, {\n  feed: new Hypercore(null, {\n    persist: false\n  })\n})\n\ntrie.put('key', 'value', () => {\n  trie.get('key', (err, node) => {\n    console.log('Got key: ', node.key)\n    console.log('Loaded value from trie: ', node.value)\n  })\n})\n\n```\n\n## API (Promise)\n\n### `const {DatArchive, destroy} = SDK({ storageOpts, swarmOpts, driveOpts, coreOpts, dnsOpts })`\n\nThis initializes the Dat SDK.\n\n\n- `storageOpts`: This lets you configure how the SDK will store data. Used by the [universal-dat-storage](https://github.com/RangerMauve/universal-dat-storage) module.\n  - `application: 'dat'`: The name of the application using the SDK if you want to have the data stored separately. Used by [env-paths](https://github.com/sindresorhus/env-paths#pathsdata) to generate the storageLocation\n  - `storageLocation: null`: A location (on disk) to store the archives in.\n- `swarmOpts`: This lets you configure [discovery-swarm](https://www.npmjs.com/package/discovery-swarm) and [discovery-swarm-web](https://www.npmjs.com/package/discovery-swarm-web)\n  - `id`: The ID to use when doing p2p traffic\n  - `maxConnections`: The maximum number of connections to keep for this swarm.\n  - `extensions: []`: The set of extension messages to use when replicating with peers\n  - `utp: true`: Whether to use utp in discovery-swarm\n  - `tcp: true`: Whether to use tcp in discovery-swarm\n  - `bootstrap: ['signal.mauve.moe']`: The WebRTC bootstrap server list used by discovery-swarm-web\n  - `discovery: 'discoveryswarm.mauve.moe'`: The proxy server used by discovery-swarm-web\n- `driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n- `coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `await destroy()`\n\nRelease all resources being used by the SDK so you can safely stop your process.\n\n### `const archive = await DatArchive.load(location, opts)`\n\nThis loads up a Dat Archive for the given URL / Key / File path.\n\n- `location`: This is either the `dat://` URL (which might have a domain), a dat key, or a file path for your archive.\n- `opts`: These are options for configuring this archive\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n\n### `const archive = await DatArchive.create(opts)`\n\nThis creates a new Dat Archive.\n\n- `opts` These are the options for the archive's metadata and it's properties\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n  - `title`: The title of the archive\n  - `description`: A brief description of what the archive contains\n  - `type`: An array of strings for the type of archive this is. See the [manifest](https://beakerbrowser.com/docs/apis/manifest.html#type) docs for more info.\n\n### `const archive = await DatArchive.fork(url, opts)`\n\nCreate a new archive based on the data within another archive\n\n- `url` The URL of the archive to fork off of\n- `opts` These options will be used in the new archive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n  - `title`: The title of the archive\n  - `description`: A brief description of what the archive contains\n  - `type`: An array of strings for the type of archive this is. See the [manifest](https://beakerbrowser.com/docs/apis/manifest.html#type) docs for more info.\n\n### `await DatArchive.unlink(url)`\n\nDelete the storage for an archive.\n\n- `url`: The URL of the archive to delete\n\n### `const archive = await DatArchive.selectArchive()`\n\nPrompt the user to select an archive from the ones they have created locally. The implementation is super hacky, so use with caution.\n\n### `const url = await DatArchive.resolveName(url)`\n\nResolve a URL that uses dat-dns to the raw `dat://` url.\n\n- `url`: The `dat://` URL with a domain to resolve\n\n#### `const url = archive.url`\n\nGet the URL for the given archive.\n\n#### `const info = await archive.getInfo()`\n\nGet metadata about the archive\n\n- `info`: The metadata related to the archive.\n  - `key`: string (the archive public key)\n  - `url`: string (the archive URL)\n  - `isOwner`: boolean (is the user the owner of this archive?)\n  - `version`: number (the archive's current revision number)\n  - `peers`: number (the number of active connections for the archive)\n  - `mtime`: number (the walltime of the last received update; is reliable)\n  - `size`: number (bytes, the size-on-disk of the archive)\n  - `title`: string (the archive title)\n  - `description`: string (the archive description)\n  - `type`: array of strings (the archive's type identifiers)\n  - `links`: object (top-level links to other resources)\n\n#### `await archive.configure(configuration)`\n\nUpdate the metadata about the archive.\n\n- `configuration`: The metadata to update\n  - `title` String. The title of the archive.\n  - `description` String. The description of the archive.\n  - `type` Array<String>. The archive’s type identifiers. Learn more.\n  - `links` Object. Top-level links to other resources. Learn more.\n  - `web_root` String. Path of the folder from which all web requests should be served.\n  - `fallback_page` String. Path to a fallback page to serve instead of the default 404 page.\n\n#### `const stat = await archive.stat(path)`\n\n- `path`: The path to get stats about from the archive\n- `stat.isDirectory()`: Check if the path is a directory\n- `stat.isFile()`: Check if the path is a file\n- `stat.size`: number (bytes)\n- `stat.blocks`: number (number of data blocks in the metadata)\n- `stat.downloaded`: number (number of blocks downloaded, if a remote archive)\n- `stat.mtime`: Date (last modified time; not reliable)\n- `stat.ctime`: Date (creation time; not reliable)`\n\n#### `const data = await archive.readFile(path, opts)`\n\n- `path` The path to the file you wish to read\n- `opts.encoding`: The encoding to read the file with, can be one of `utf8`, `base64`, `hex`, and `binary`\n- `data`: The entire contents of the file, either as a string, or an ArrayBuffer if you used the `binary` encoding.\n\n#### `const list = await archive.readdir(path, opts)`\n\nLists the files and folders within a directory.\n\n- `path`: The path to the directory you wish to read\n- `opts`\n  - `recursive`: Set to `true` to list subdirectories, too\n  - `stat`: Get the `Stat` objects instead of names.\n- `list`: Either a list of the file/folder names or a list of the Stat object for those items.\n\n#### `await archive.writeFile(path, data, opts)`\n\nWrite a file to your archive.\n\n- `path`: The location to write your file to.\n- `data`: Either a string or ArrayBuffer for the data you wish to save\n- `opts.encoding`: The encoding to use when writing. Must be one of `utf8`, `base64`, `hex`, or `binary`. Encoding will default to `utf8` for strings, and `binary` for ArrayBuffers.\n\n#### `await archive.mkdir(path)`\n\nCreate a directory at the given path. Will fail if the parent directory doesn't exist.\n\n- `path`: The path to the directory\n\n#### `await archive.unlink(path)`\n\nDelete the file at the given path.\n\n- `path`: The path to the file\n\n#### `await rmdir(path, opts)`\n\nDeletes the directory at the given path.\n\n- `path`: The path to the directory\n- `opts.recursive`: Whether to delete subfolders / files.\n\n#### `await archive.copy(path, dstPath)`\n\nCopy a file from one location to another.\n\n- `path`: The path to the file / directory to copy from.\n- `dstPath`: The location the file/directory should be copied to\n\n#### `await archive.rename(oldPath, newPath)`\n\nRename / move a file or directory.\n\n- `oldPath`: The path of the file/directory to rename\n- `newPath`: What the file/directory should be renamed to.\n\n#### `const history = await archive.history({opts})`\n\nList the history of all the changes in this archive.\n\n- `opts`: The options for how to fetch the history of the archive\n  - `start`: Where in the history to start reading\n  - `end`: Where in the history to stop reading\n  - `reverse`: Set to `true` to iterate through the history backwards\n- `history`: An array of history items representing changes\n  - `path`: Which file / directory got modified.\n  - `version`: The version number the archive was at for this item\n  - `type`: Either `put` for additions or `del` for deletions\n\n#### `const olderArchive = archive.checkout(version)`\n\nGet a view of the archive as it was at an earlier version.\n\n- `version`: The integer representing the version you whish to look at. This correlates to the version in the history.\n\n#### `await archive.download(path)`\n\nDownload the file or folder at the given path from the network. Use `/` to download the entire archive.\n\n#### `const events = archive.watch(pattern, onInvalidated)`\n\n```js\nconst events = archive.watch(['**/*.md'])\nevents.addEventListener('changed', ({path}) => console.log(path, 'changed!'))\n\nevents.close() // Stop listening for changes\n```\n\nWatch for changes in the archive.\n\n- `pattern`: This can either be omitted to view all changes, or have an [anymatch](https://www.npmjs.com/package/anymatch) pattern to filter out just the changes you want.\n- `onInvalidated`: You can optionally pass in this function to listen for changes instead of using an event listener.\n\n#### `archive.addEventListener('network-changed', ({peers}) => void 0)`\n\nListen for changes in the number of peers connected to for the archive.\n\n- `peers`: The number of connected peers\n\n#### `archive.addEventListener('download', ({feed, block, bytes}) => void 0)`\n\nListen for download progress from the archive\n\n- `feed`: The data feed the block was part of. Either `metadata` or `content`\n- `block`: The index of the block downloaded\n- `bytes`: The size of the block in bytes\n\n#### `archive.addEventListener('upload', ({feed, block, bytes}) => void 0)`\n\nListen for upload progress from the archive.\n\n- `feed`: The data feed the block was part of. Either `metadata` or `content`\n- `block`: The index of the block uploaded\n- `bytes`: The size of the block in bytes\n\n#### `archive.addEventListener('sync', ({feed}) => void 0)`\n\nEmitted when all known data has been downloaded\n\n## API (Callbacks)\n\n### `const {Hypercore, Hyperdrive, resolveName, deleteStorage, destroy} = SDK({ storageOpts, swarmOpts, driveOpts, coreOpts, dnsOpts })`\n\nCreates an instance of the Dat SDK based on the options.\n\n- `storageOpts`: This lets you configure how the SDK will store data. Used by the [universal-dat-storage](https://github.com/RangerMauve/universal-dat-storage) module.\n  - `application: 'dat'`: The name of the application using the SDK if you want to have the data stored separately. Used by [env-paths](https://github.com/sindresorhus/env-paths#pathsdata) to generate the storageLocation\n  - `storageLocation: null`: A location (on disk) to store the archives in.\n- `swarmOpts`: This lets you configure [discovery-swarm](https://www.npmjs.com/package/discovery-swarm) and [discovery-swarm-web](https://www.npmjs.com/package/discovery-swarm-web)\n  - `id`: The ID to use when doing p2p traffic\n  - `maxConnections`: The maximum number of connections to keep for this swarm.\n  - `extensions: []`: The set of extension messages to use when replicating with peers\n  - `utp: true`: Whether to use utp in discovery-swarm\n  - `tcp: true`: Whether to use tcp in discovery-swarm\n  - `bootstrap: ['signal.mauve.moe']`: The WebRTC bootstrap server list used by discovery-swarm-web\n  - `discovery: 'discoveryswarm.mauve.moe'`: The proxy server used by discovery-swarm-web\n- `driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n- `coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `destroy(cb)`\n\nThis closes all resources used by the SDK so you can safely end your process. `cb` will be invoked once resources are closed or if there's an error.\n\n### `resolveName(url, cb(err, key))`\n\nResolve a DNS name to a Dat key.\n\n  - `url` is a Dat URL like `dat://dat.foundation`\n  - `cb` will get invoked with the result of the resolve\n  - `key` will be the Dat key that you can pass to `hyperdrive`\n  - `err` will be any errors that happen during resolution\n\n### `deleteStorage(key, cb)`\n\nDelete the storage for a given archive or hypercore key.\n\n- `key` should be the key for the hypercore or hyperdrive that should be deleted\n- `cb` will be invoked after the deletion is over.\n\n### `const archive = Hyperdrive(location, opts)`\n\nThis initializes a Hyperdrive (aka a Dat archive), the SDK will begin finding peers for it and will de-duplicate calls to initializing the same archive more than once.\n\n- `location`: This **must** be provided. It's either a path for where the archive should be stored, or a Dat URL / key. If this is null, a new key will be generated.\n- `opts`: These are the options for configuring the hyperdrive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n  - `secretKey`: A secret key for granting write access. This can be useful when restoring backups.\n\nThe rest of the Hyperdrive docs were taken from the [Hyperdrive README](https://github.com/mafintosh/hyperdrive/blob/v9/README.md)\n\n#### `archive.version`\n\nGet the current version of the archive (incrementing number).\n\n#### `archive.key`\n\nThe public key identifying the archive.\n\n#### `archive.discoveryKey`\n\nA key derived from the public key that can be used to discovery other peers sharing this archive.\n\n#### `archive.writable`\n\nA boolean indicating whether the archive is writable.\n\n#### `archive.on('ready')`\n\nEmitted when the archive is fully ready and all properties has been populated.\n\n#### `archive.on('update')`\n\nEmitted when the archive has got a new change.\n\n#### `archive.on('error', err)`\n\nEmitted when a critical error during load happened.\n\n#### `archive.on('close')`\n\nEmitted when the archive has been closed\n\n#### `archive.on('extension', name, message, peer)`\n\nEmitted when a peer sends you an extension message with `archive.extension()`.\nYou can respond with `peer.extension(name, message)`.\n\n#### `var oldDrive = archive.checkout(version, [opts])`\n\nCheckout a readonly copy of the archive at an old version. Options are used to configure the `oldDrive`:\n\n```js\n{\n  metadataStorageCacheSize: 65536 // how many entries to use in the metadata hypercore's LRU cache\n  contentStorageCacheSize: 65536 // how many entries to use in the content hypercore's LRU cache\n  treeCacheSize: 65536 // how many entries to use in the append-tree's LRU cache\n}\n```\n\n#### `archive.download([path], [callback])`\n\nDownload all files in path of current version.\nIf no path is specified this will download all files.\n\nYou can use this with `.checkout(version)` to download a specific version of the archive.\n\n``` js\narchive.checkout(version).download()\n```\n\n#### `var stream = archive.history([options])`\n\nGet a stream of all changes and their versions from this archive.\n\n#### `archive.extension(name, message)`\n\nSend an extension message to connected peers. [Read more in the hypercore docs](https://github.com/mafintosh/hypercore#feedextensionname-message).\n\n#### `var stream = archive.createReadStream(name, [options])`\n\nRead a file out as a stream. Similar to fs.createReadStream.\n\nOptions include:\n\n``` js\n{\n  start: optionalByteOffset, // similar to fs\n  end: optionalInclusiveByteEndOffset, // similar to fs\n  length: optionalByteLength\n}\n```\n\n#### `archive.readFile(name, [options], callback)`\n\nRead an entire file into memory. Similar to fs.readFile.\n\nOptions can either be an object or a string\n\nOptions include:\n```js\n{\n  encoding: string\n  cached: true|false // default: false\n}\n```\nor a string can be passed as options to simply set the encoding - similar to fs.\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `var stream = archive.createDiffStream(version, [options])`\n\nDiff this archive with another version. `version` can both be a version number of a checkout instance of the archive. The `data` objects looks like this\n\n``` js\n{\n  type: 'put' | 'del',\n  name: '/some/path/name.txt',\n  value: {\n    // the stat object\n  }\n}\n```\n\n#### `var stream = archive.createWriteStream(name, [options])`\n\nWrite a file as a stream. Similar to fs.createWriteStream.\nIf `options.cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `archive.writeFile(name, buffer, [options], [callback])`\n\nWrite a file from a single buffer. Similar to fs.writeFile.\n\n#### `archive.unlink(name, [callback])`\n\nUnlinks (deletes) a file. Similar to fs.unlink.\n\n#### `archive.mkdir(name, [options], [callback])`\n\nExplictly create an directory. Similar to fs.mkdir\n\n#### `archive.rmdir(name, [callback])`\n\nDelete an empty directory. Similar to fs.rmdir.\n\n#### `archive.readdir(name, [options], [callback])`\n\nLists a directory. Similar to fs.readdir.\n\nOptions include:\n\n``` js\n{\n    cached: true|false, // default: false\n}\n```\n\nIf `cached` is set to `true`, this function returns results from the local version of the archive’s append-tree. Default behavior is to fetch the latest remote version of the archive before returning list of directories.\n\n#### `archive.stat(name, [options], callback)`\n\nStat an entry. Similar to fs.stat. Sample output:\n\n```\nStat {\n  dev: 0,\n  nlink: 1,\n  rdev: 0,\n  blksize: 0,\n  ino: 0,\n  mode: 16877,\n  uid: 0,\n  gid: 0,\n  size: 0,\n  offset: 0,\n  blocks: 0,\n  atime: 2017-04-10T18:59:00.147Z,\n  mtime: 2017-04-10T18:59:00.147Z,\n  ctime: 2017-04-10T18:59:00.147Z,\n  linkname: undefined }\n```\n\nThe output object includes methods similar to fs.stat:\n\n``` js\nvar stat = archive.stat('/hello.txt')\nstat.isDirectory()\nstat.isFile()\n```\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.lstat(name, [options], callback)`\n\nStat an entry but do not follow symlinks. Similar to fs.lstat.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.access(name, [options], callback)`\n\nSimilar to fs.access.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.open(name, flags, [mode], callback)`\n\nOpen a file and get a file descriptor back. Similar to fs.open.\n\nNote that currently only read mode is supported in this API.\n\n#### `archive.read(fd, buf, offset, len, position, callback)`\n\nRead from a file descriptor into a buffer. Similar to fs.read.\n\n#### `archive.close(fd, [callback])`\n\nClose a file. Similar to fs.close.\n\n#### `archive.close([callback])`\n\nCloses all open resources used by the archive.\nThe archive should no longer be used after calling this.\n\n### `const feed = Hypercore(key, opts)`\n\nInitializes a Hypercore (aka Feed) and begins replicating it.\n\n- `key`: This is the dat key for the feed, you can omit it if you want to create a new hypercore instance\n- `opts`: The options for configuring this feed\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n  - `secretKey`: The secret key to use for the feed. Useful for restoring from backups.\n\n#### `feed.append(data, [callback])`\n\nAppend a block of data to the feed.\n\nCallback is called with `(err, seq)` when all data has been written at the returned `seq` or an error occurred.\n\n#### `feed.get(index, [options], callback)`\n\nGet a block of data.\nIf the data is not available locally this method will prioritize and wait for the data to be downloaded before calling the callback.\n\nOptions include\n\n``` js\n{\n  wait: true, // wait for index to be downloaded\n  timeout: 0, // wait at max some milliseconds (0 means no timeout)\n  valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the feed's valueEncoding\n}\n```\n\nCallback is called with `(err, data)`\n\n#### `feed.getBatch(start, end, [options], callback)`\n\nGet a range of blocks efficiently. Options include\n\n``` js\n{\n  wait: sameAsAbove,\n  timeout: sameAsAbove,\n  valueEncoding: sameAsAbove\n}\n```\n\n#### `feed.head([options], callback)`\n\nGet the block of data at the tip of the feed. This will be the most recently\nappended block.\n\nAccepts the same `options` as `feed.get()`.\n\n#### `feed.download([range], [callback])`\n\nDownload a range of data. Callback is called when all data has been downloaded.\nA range can have the following properties:\n\n``` js\n{\n  start: startIndex,\n  end: nonInclusiveEndIndex,\n  linear: false // download range linearly and not randomly\n}\n```\n\nIf you do not mark a range the entire feed will be marked for download.\n\nIf you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire\nfeed will be marked for download for you when the feed is created.\n\n#### `feed.undownload(range)`\n\nCancel a previous download request.\n\n#### `feed.signature([index], callback)`\n\nGet a signature proving the correctness of the block at index, or the whole stream.\n\nCallback is called with `(err, signature)`.\nThe signature has the following properties:\n``` js\n{\n  index: lastSignedBlock,\n  signature: Buffer\n}\n```\n\n#### `feed.verify(index, signature, callback)`\n\nVerify a signature is correct for the data up to index, which must be the last signed\nblock associated with the signature.\n\nCallback is called with `(err, success)` where success is true only if the signature is\ncorrect.\n\n#### `feed.rootHashes(index, callback)`\n\nRetrieve the root *hashes* for given `index`.\n\nCallback is called with `(err, roots)`; `roots` is an *Array* of *Node* objects:\n```\nNode {\n  index: location in the merkle tree of this root\n  size: total bytes in children of this root\n  hash: hash of the children of this root (32-byte buffer)\n}\n```\n\n\n#### `var number = feed.downloaded([start], [end])`\n\nReturns total number of downloaded blocks within range.\nIf `end` is not specified it will default to the total number of blocks.\nIf `start` is not specified it will default to 0.\n\n#### `var bool = feed.has(index)`\n\nReturn true if a data block is available locally.\nFalse otherwise.\n\n#### `var bool = feed.has(start, end)`\nReturn true if all data blocks within a range are available locally.\nFalse otherwise.\n\n#### `feed.clear(start, [end], [callback])`\n\nClear a range of data from the local cache.\nWill clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.\n\n`end` defaults to `start + 1`.\n\n#### `feed.seek(byteOffset, callback)`\n\nSeek to a byte offset.\n\nCalls the callback with `(err, index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is\nthe relative byte offset in the data block.\n\n#### `feed.update([minLength], [callback])`\n\nWait for the feed to contain at least `minLength` elements.\nIf you do not provide `minLength` it will be set to current length + 1.\n\nDoes not download any data from peers except for a proof of the new feed length.\n\n``` js\nconsole.log('length is', feed.length)\nfeed.update(function () {\n  console.log('length has increased', feed.length)\n})\n```\n\n#### `var stream = feed.createReadStream([options])`\n\nCreate a readable stream of data.\n\nOptions include:\n\n``` js\n{\n  start: 0, // read from this index\n  end: feed.length, // read until this index\n  snapshot: true, // if set to false it will update `end` to `feed.length` on every read\n  tail: false, // sets `start` to `feed.length`\n  live: false, // set to true to keep reading forever\n  timeout: 0, // timeout for each data event (0 means no timeout)\n  wait: true // wait for data to be downloaded\n}\n```\n\n#### `var stream = feed.createWriteStream()`\n\nCreate a writable stream.\n\n#### `feed.close([callback])`\n\nFully close this feed.\n\nCalls the callback with `(err)` when all storage has been closed.\n\n#### `feed.audit([callback])`\n\nAudit all data in the feed. Will check that all current data stored\nmatches the hashes in the merkle tree and clear the bitfield if not.\n\nWhen done a report is passed to the callback that looks like this:\n\n```js\n{\n  valid: 10, // how many data blocks matches the hashes\n  invalid: 0, // how many did not\n}\n```\n\nIf a block does not match the hash it is cleared from the data bitfield.\n\n#### `feed.writable`\n\nCan we append to this feed?\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.readable`\n\nCan we read from this feed? After closing a feed this will be false.\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.key`\n\nBuffer containing the public key identifying this feed.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.discoveryKey`\n\nBuffer containing a key derived from the feed.key.\nIn contrast to `feed.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same feed, without leaking the feed key.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.length`\n\nHow many blocks of data are available on this feed?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.byteLength`\n\nHow much data is available on this feed in bytes?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.stats`\n\nReturn per-peer and total upload/download counts.\n\nThe returned object is of the form:\n```js\n{\n  totals: {\n    uploadedBytes: 100,\n    uploadedBlocks: 1,\n    downloadedBytes: 0,\n    downloadedBlocks: 0\n  },\n  peers: [\n    {\n      uploadedBytes: 100,\n      uploadedBlocks: 1,\n      downloadedBytes: 0,\n      downloadedBlocks: 0\n    },\n    ...\n  ]\n}\n```\n\nStats will be collected by default, but this can be disabled by setting `opts.stats` to false.\n\n#### `feed.on('ready')`\n\nEmitted when the feed is ready and all properties have been populated.\n\n#### `feed.on('error', err)`\n\nEmitted when the feed experiences a critical error.\n\n#### `feed.on('download', index, data)`\n\nEmitted when a data block has been downloaded.\n\n#### `feed.on('upload', index, data)`\n\nEmitted when a data block is uploaded.\n\n#### `feed.on('append')`\n\nEmitted when the feed has been appended to (i.e. has a new length / byteLength)\n\n#### `feed.on('sync')`\n\nEmitted every time ALL data from `0` to `feed.length` has been downloaded.\n\n#### `feed.on('close')`\n\nEmitted when the feed has been fully closed\n\n---\n\n[Dat Project]: https://dat.foundation\n","readmeFilename":"README.md","_id":"dat-sdk@2.0.0-1","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-8urrkJOu5jWUcF721RjcQlHnrNtGMpROGgxZzUM2urYqB1kTNo6/TC/ZxEf4/rorIj4GIAHoqeBzHJd/3+Oxwg==","shasum":"484a16cec72c93b2adac9098d27e2b1f4bdb211c","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.0.0-1.tgz","fileCount":14,"unpackedSize":63226,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeQvTZCRA9TVsSAnZWagAAKOUP+wUIiAxPP/dJ/XmU54pm\nZWaUfKa8aThTfDgDsvVEldAjIcvZII1xe0g7CuIcb4ZUQrsQOB58ar0rtKt/\nG6dsNG/8EG01gk71e+QSiP8VflrBew18HcAYzDXi+NVMpvPX70EH8N6B/0R2\nYwSYOi7++IEJGuGOSmgk5Vby+qCLIkjvrN1bNW6pljDdCiHrV8+vfcOiddie\n6R02lmASnTkmZ5f42ETzWdU+icODX+q+Z+Wl3Emr0XiodxrPq0wbgePdAHBw\nlQ1VhhcwWTbmZdfmermMQyGk4RymBnIdE1TodKyirm8EwuoJxTs8DuBEGOQi\nOjKVjYXDYIn9w3UrUYq8VrlVXXroMaVNrTjCo0SgVl34gxGKsIdY1E6YVBle\nK0zCAP5U9Bw+VJqDNBdHEktiaGJxwTXP8yAO3srD5npWOOdrqLmvPM1STDnG\n9r6FlzZfE+La+EzLQvag0X7lSJrCLwBp/nnsn5K1Yk/60bRaHH+rx6YZrNNz\n7SPagjKsZpDF2vgneYHlBGdjMLW0gKmj7/7xFLMaZ8konstxcv+bzH9Ib+yO\nmWxoYvpOsW1HDCcWUOZADMfdLB2EN6+TRXcQGTm4m7W0l+UMrVUEm+jHeiP+\ncXDLN4CqvqseXx10qJPHi2qCK6UnxArPnewbiqXu1j1lsnycNT4HiFUsQimn\n5MKq\r\n=lqBj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCfnUmDL8Qn/LPWcPSRAkINgoKKApGcRn8X21WW1viZiwIhALtLEK/e2YvpmWT6Pptu2FA5ak1u2p2g96c1VWt6Rrf+"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.0.0-1_1581446360672_0.5574414452126568"},"_hasShrinkwrap":false},"2.0.0-2":{"name":"dat-sdk","version":"2.0.0-2","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","./localstorage":"./localstorage-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^1.1.0","@geut/hyperdrive-promise":"^3.0.0","concat-stream":"^2.0.0","corestore":"^5.0.8","corestore-swarm-networking":"^4.0.3","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^8.7.0","hypercore-crypto":"^1.0.0","hypercore-protocol":"^7.10.0","hyperdrive":"^10.8.10","hyperswarm-web":"^1.0.1","node-localstorage":"^2.1.5","random-access-application":"^1.0.0","random-access-memory":"^3.1.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"1ae482be2f571810f5568ec8ea8de602cc7144a6","readme":"# sdk\nThe official Dat SDK\n\n[<img src=\"https://datproject.github.io/design/downloads/dat-logo.png\" align=\"right\" width=\"140\">][Dat Project]\n\n## Why use this?\n\nDat consists of a bunch of low level building blocks for working with data in distributed applications. Although this modularity makes it easy to mix and match pieces, it adds complexity when it comes to actually building something.\n\nThe Dat SDK combines the lower level pieces of the Dat ecosystem into high level APIs that you can use across platforms so that you can focus on your application rather than the gritty details of how it works.\n\n## Goals\n\n- High level API\n- Cross-platform with same codebase\n  - ✔ Node\n  - ✔ Web (non-beaker)\n  - ✔ Beaker (Promise API acts as polyfill for Beaker)\n  - React-Native?\n  - Electron?\n\n\n## Installing\n\n[Node.js](https://nodejs.org/) / [Browserify](http://browserify.org/) workflows:\n\n```shell\nnpm install --save dat-sdk\n```\n\n```js\nconst SDK = require('dat-sdk')\nconst SDKPromise = require('dat-sdk/promise')\nconst {DatArchive} = require('dat-sdk/auto')\n```\n\nOr Web Browsers\n\n```html\n<script src=\"https://bundle.run/dat-sdk@1\"></script>\n<script src=\"https://bundle.run/dat-sdk@1/promise.js\"></script>\n<script src=\"https://bundle.run/dat-sdk@1/auto.js\"></script>\n<script>\n  const SDK = window.datSDK\n  // Look at the examples from here\n</script>\n```\n\n## Examples (browserify)\n\nYou can bundle your code with [browserify](http://browserify.org/) using the following command:\n\n```\nbrowserify index.js > bundle.js\n```\n\nThen you can include `bundle.js` in your HTML page.\n\n## Examples (webpack.config.js)\n\nTo bundle with webpack instead of browserify, resolve the `fs` module with the `graceful-fs` module.\n\n```js\nconst path = require('path')\n\nmodule.exports = {\n  entry: './index.js',\n  target: 'web',\n  resolve: {\n    alias: {\n      fs: 'graceful-fs'\n    }\n  },\n  output: {\n    filename: 'bundle.js',\n    path: path.resolve(__dirname, 'dist')\n  }\n}\n```\n\nThen you can include `./dist/bundle.js` in your HTML page.\n\n## Examples (Promise)\n\n```js\n// Auto-detects sane defaults based on your environment\n// Uses Beaker's APIs if they are if they are available\n// DatArchive is the same as Beaker\n// https://beakerbrowser.com/docs/apis/dat\nconst {DatArchive} = require('dat-sdk/auto')\n\nconst archive = await DatArchive.load('dat://dat.foundation')\n\nconst someData = await archive.readFile('/dat.json', 'utf8')\n\nconsole.log('Dat foundation dat.json:', someData)\n\nconst myArchive = await DatArchive.create({\n  title: 'My Archive'\n})\n\nawait myArchive.writeFile('/example.txt', 'Hello World!')\n\n// Log the secret key in case you want to save it for later\nconsole.log(await myArchive.getSecretKey())\n\n// Use a saved secret key\nawait DatArchive.load(someKey, {\n  secretKey: someSecretKey\n})\n```\n\n## API/Examples (Callbacks)\n\n```js\nconst SDK = require('dat-sdk')\nconst { Hypercore, Hyperdrive, resolveName, deleteStorage, destroy } = SDK()\n\nconst archive = Hyperdrive(null, {\n  // This archive will disappear after the process exits\n  // This is here so that running the example doesn't clog up your history\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  //storage: RAI\n})\n\narchive.ready(() => {\n  const url = `dat://${archive.key.toString('hex')}`\n\n  // TODO: Save this for later!\n  console.log(`Here's your URL: ${url}`)\n\n  // Check out the hyperdrive docs for what you can do with it\n  // https://www.npmjs.com/package/hyperdrive#api\n  archive.writeFile('/example.txt', 'Hello World!', () => {\n    console.log('Written example file!')\n  })\n})\n\nresolveName('dat://beakerbrowser.com', (err, url) => {\n  if (err) throw err\n  const archive = Hyperdrive(url)\n\n  archive.readFile('/dat.json', 'utf8', (err, data) => {\n    if (err) throw err\n    console.log(`Beaker's dat.json is ${data}`)\n\n    archive.close((err) => {\n      if (err) throw err\n      deleteStorage(archive.key, (e) => {\n        if (e) throw e\n        console.log('Deleted beaker storage')\n      })\n    })\n  })\n})\n\nconst SOME_URL = 'dat://0a9e202b8055721bd2bc93b3c9bbc03efdbda9cfee91f01a123fdeaadeba303e/'\n\nconst someArchive = Hyperdrive(SOME_URL)\n\nreallyReady(someArchive, () => {\n  someArchive.readdir('/', console.log)\n})\n\n// This make sure you sync up with peers before trying to do anything with the archive\nfunction reallyReady (archive, cb) {\n  if (archive.metadata.peers.length) {\n    archive.metadata.update({ ifAvailable: true }, cb)\n  } else {\n    archive.metadata.once('peer-add', () => {\n      archive.metadata.update({ ifAvailable: true }, cb)\n    })\n  }\n}\n\n// Create a hypercore\n// Check out the hypercore docs for what you can do with it\n// https://github.com/mafintosh/hypercore\nconst myCore = Hypercore(null, {\n  valueEncoding: 'json',\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  // storage: RAI\n})\n\n// Add some data to it\nmyCore.append(JSON.stringify({\n  name: 'Alice'\n}), () => {\n  // Use extension messages for sending extra data over the p2p connection\n  const discoveryCoreKey = 'dat://bee80ff3a4ee5e727dc44197cb9d25bf8f19d50b0f3ad2984cfe5b7d14e75de7'\n  const discoveryCore = new Hypercore(discoveryCoreKey, {\n    extensions: ['discovery']\n  })\n\n  // When you find a new peer, tell them about your core\n  discoveryCore.on('peer-add', (peer) => {\n    console.log('Got a peer!')\n    peer.extension('discovery', myCore.key)\n  })\n\n  // When a peer tells you about their core, load it\n  discoveryCore.on('extension', (type, message) => {\n    console.log('Got extension message', type, message)\n    if (type !== 'discovery') return\n    discoveryCore.close()\n\n    const otherCore = new Hypercore(message, {\n      valueEncoding: 'json',\n      persist: false\n    })\n\n    // Render the peer's data from their core\n    otherCore.get(0, console.log)\n  })\n})\n\nconst hypertrie = require('hypertrie')\n\n// Pass in hypercores from the SDK into other dat data structures\n// Check out what you can do with hypertrie from there:\n// https://github.com/mafintosh/hypertrie\nconst trie = hypertrie(null, {\n  feed: new Hypercore(null, {\n    persist: false\n  })\n})\n\ntrie.put('key', 'value', () => {\n  trie.get('key', (err, node) => {\n    console.log('Got key: ', node.key)\n    console.log('Loaded value from trie: ', node.value)\n  })\n})\n\n```\n\n## API (Promise)\n\n### `const {DatArchive, destroy} = SDK({ storageOpts, swarmOpts, driveOpts, coreOpts, dnsOpts })`\n\nThis initializes the Dat SDK.\n\n\n- `storageOpts`: This lets you configure how the SDK will store data. Used by the [universal-dat-storage](https://github.com/RangerMauve/universal-dat-storage) module.\n  - `application: 'dat'`: The name of the application using the SDK if you want to have the data stored separately. Used by [env-paths](https://github.com/sindresorhus/env-paths#pathsdata) to generate the storageLocation\n  - `storageLocation: null`: A location (on disk) to store the archives in.\n- `swarmOpts`: This lets you configure [discovery-swarm](https://www.npmjs.com/package/discovery-swarm) and [discovery-swarm-web](https://www.npmjs.com/package/discovery-swarm-web)\n  - `id`: The ID to use when doing p2p traffic\n  - `maxConnections`: The maximum number of connections to keep for this swarm.\n  - `extensions: []`: The set of extension messages to use when replicating with peers\n  - `utp: true`: Whether to use utp in discovery-swarm\n  - `tcp: true`: Whether to use tcp in discovery-swarm\n  - `bootstrap: ['signal.mauve.moe']`: The WebRTC bootstrap server list used by discovery-swarm-web\n  - `discovery: 'discoveryswarm.mauve.moe'`: The proxy server used by discovery-swarm-web\n- `driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n- `coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `await destroy()`\n\nRelease all resources being used by the SDK so you can safely stop your process.\n\n### `const archive = await DatArchive.load(location, opts)`\n\nThis loads up a Dat Archive for the given URL / Key / File path.\n\n- `location`: This is either the `dat://` URL (which might have a domain), a dat key, or a file path for your archive.\n- `opts`: These are options for configuring this archive\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n\n### `const archive = await DatArchive.create(opts)`\n\nThis creates a new Dat Archive.\n\n- `opts` These are the options for the archive's metadata and it's properties\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n  - `title`: The title of the archive\n  - `description`: A brief description of what the archive contains\n  - `type`: An array of strings for the type of archive this is. See the [manifest](https://beakerbrowser.com/docs/apis/manifest.html#type) docs for more info.\n\n### `const archive = await DatArchive.fork(url, opts)`\n\nCreate a new archive based on the data within another archive\n\n- `url` The URL of the archive to fork off of\n- `opts` These options will be used in the new archive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n  - `title`: The title of the archive\n  - `description`: A brief description of what the archive contains\n  - `type`: An array of strings for the type of archive this is. See the [manifest](https://beakerbrowser.com/docs/apis/manifest.html#type) docs for more info.\n\n### `await DatArchive.unlink(url)`\n\nDelete the storage for an archive.\n\n- `url`: The URL of the archive to delete\n\n### `const archive = await DatArchive.selectArchive()`\n\nPrompt the user to select an archive from the ones they have created locally. The implementation is super hacky, so use with caution.\n\n### `const url = await DatArchive.resolveName(url)`\n\nResolve a URL that uses dat-dns to the raw `dat://` url.\n\n- `url`: The `dat://` URL with a domain to resolve\n\n#### `const url = archive.url`\n\nGet the URL for the given archive.\n\n#### `const info = await archive.getInfo()`\n\nGet metadata about the archive\n\n- `info`: The metadata related to the archive.\n  - `key`: string (the archive public key)\n  - `url`: string (the archive URL)\n  - `isOwner`: boolean (is the user the owner of this archive?)\n  - `version`: number (the archive's current revision number)\n  - `peers`: number (the number of active connections for the archive)\n  - `mtime`: number (the walltime of the last received update; is reliable)\n  - `size`: number (bytes, the size-on-disk of the archive)\n  - `title`: string (the archive title)\n  - `description`: string (the archive description)\n  - `type`: array of strings (the archive's type identifiers)\n  - `links`: object (top-level links to other resources)\n\n#### `await archive.configure(configuration)`\n\nUpdate the metadata about the archive.\n\n- `configuration`: The metadata to update\n  - `title` String. The title of the archive.\n  - `description` String. The description of the archive.\n  - `type` Array<String>. The archive’s type identifiers. Learn more.\n  - `links` Object. Top-level links to other resources. Learn more.\n  - `web_root` String. Path of the folder from which all web requests should be served.\n  - `fallback_page` String. Path to a fallback page to serve instead of the default 404 page.\n\n#### `const stat = await archive.stat(path)`\n\n- `path`: The path to get stats about from the archive\n- `stat.isDirectory()`: Check if the path is a directory\n- `stat.isFile()`: Check if the path is a file\n- `stat.size`: number (bytes)\n- `stat.blocks`: number (number of data blocks in the metadata)\n- `stat.downloaded`: number (number of blocks downloaded, if a remote archive)\n- `stat.mtime`: Date (last modified time; not reliable)\n- `stat.ctime`: Date (creation time; not reliable)`\n\n#### `const data = await archive.readFile(path, opts)`\n\n- `path` The path to the file you wish to read\n- `opts.encoding`: The encoding to read the file with, can be one of `utf8`, `base64`, `hex`, and `binary`\n- `data`: The entire contents of the file, either as a string, or an ArrayBuffer if you used the `binary` encoding.\n\n#### `const list = await archive.readdir(path, opts)`\n\nLists the files and folders within a directory.\n\n- `path`: The path to the directory you wish to read\n- `opts`\n  - `recursive`: Set to `true` to list subdirectories, too\n  - `stat`: Get the `Stat` objects instead of names.\n- `list`: Either a list of the file/folder names or a list of the Stat object for those items.\n\n#### `await archive.writeFile(path, data, opts)`\n\nWrite a file to your archive.\n\n- `path`: The location to write your file to.\n- `data`: Either a string or ArrayBuffer for the data you wish to save\n- `opts.encoding`: The encoding to use when writing. Must be one of `utf8`, `base64`, `hex`, or `binary`. Encoding will default to `utf8` for strings, and `binary` for ArrayBuffers.\n\n#### `await archive.mkdir(path)`\n\nCreate a directory at the given path. Will fail if the parent directory doesn't exist.\n\n- `path`: The path to the directory\n\n#### `await archive.unlink(path)`\n\nDelete the file at the given path.\n\n- `path`: The path to the file\n\n#### `await rmdir(path, opts)`\n\nDeletes the directory at the given path.\n\n- `path`: The path to the directory\n- `opts.recursive`: Whether to delete subfolders / files.\n\n#### `await archive.copy(path, dstPath)`\n\nCopy a file from one location to another.\n\n- `path`: The path to the file / directory to copy from.\n- `dstPath`: The location the file/directory should be copied to\n\n#### `await archive.rename(oldPath, newPath)`\n\nRename / move a file or directory.\n\n- `oldPath`: The path of the file/directory to rename\n- `newPath`: What the file/directory should be renamed to.\n\n#### `const history = await archive.history({opts})`\n\nList the history of all the changes in this archive.\n\n- `opts`: The options for how to fetch the history of the archive\n  - `start`: Where in the history to start reading\n  - `end`: Where in the history to stop reading\n  - `reverse`: Set to `true` to iterate through the history backwards\n- `history`: An array of history items representing changes\n  - `path`: Which file / directory got modified.\n  - `version`: The version number the archive was at for this item\n  - `type`: Either `put` for additions or `del` for deletions\n\n#### `const olderArchive = archive.checkout(version)`\n\nGet a view of the archive as it was at an earlier version.\n\n- `version`: The integer representing the version you whish to look at. This correlates to the version in the history.\n\n#### `await archive.download(path)`\n\nDownload the file or folder at the given path from the network. Use `/` to download the entire archive.\n\n#### `const events = archive.watch(pattern, onInvalidated)`\n\n```js\nconst events = archive.watch(['**/*.md'])\nevents.addEventListener('changed', ({path}) => console.log(path, 'changed!'))\n\nevents.close() // Stop listening for changes\n```\n\nWatch for changes in the archive.\n\n- `pattern`: This can either be omitted to view all changes, or have an [anymatch](https://www.npmjs.com/package/anymatch) pattern to filter out just the changes you want.\n- `onInvalidated`: You can optionally pass in this function to listen for changes instead of using an event listener.\n\n#### `archive.addEventListener('network-changed', ({peers}) => void 0)`\n\nListen for changes in the number of peers connected to for the archive.\n\n- `peers`: The number of connected peers\n\n#### `archive.addEventListener('download', ({feed, block, bytes}) => void 0)`\n\nListen for download progress from the archive\n\n- `feed`: The data feed the block was part of. Either `metadata` or `content`\n- `block`: The index of the block downloaded\n- `bytes`: The size of the block in bytes\n\n#### `archive.addEventListener('upload', ({feed, block, bytes}) => void 0)`\n\nListen for upload progress from the archive.\n\n- `feed`: The data feed the block was part of. Either `metadata` or `content`\n- `block`: The index of the block uploaded\n- `bytes`: The size of the block in bytes\n\n#### `archive.addEventListener('sync', ({feed}) => void 0)`\n\nEmitted when all known data has been downloaded\n\n## API (Callbacks)\n\n### `const {Hypercore, Hyperdrive, resolveName, deleteStorage, destroy} = SDK({ storageOpts, swarmOpts, driveOpts, coreOpts, dnsOpts })`\n\nCreates an instance of the Dat SDK based on the options.\n\n- `storageOpts`: This lets you configure how the SDK will store data. Used by the [universal-dat-storage](https://github.com/RangerMauve/universal-dat-storage) module.\n  - `application: 'dat'`: The name of the application using the SDK if you want to have the data stored separately. Used by [env-paths](https://github.com/sindresorhus/env-paths#pathsdata) to generate the storageLocation\n  - `storageLocation: null`: A location (on disk) to store the archives in.\n- `swarmOpts`: This lets you configure [discovery-swarm](https://www.npmjs.com/package/discovery-swarm) and [discovery-swarm-web](https://www.npmjs.com/package/discovery-swarm-web)\n  - `id`: The ID to use when doing p2p traffic\n  - `maxConnections`: The maximum number of connections to keep for this swarm.\n  - `extensions: []`: The set of extension messages to use when replicating with peers\n  - `utp: true`: Whether to use utp in discovery-swarm\n  - `tcp: true`: Whether to use tcp in discovery-swarm\n  - `bootstrap: ['signal.mauve.moe']`: The WebRTC bootstrap server list used by discovery-swarm-web\n  - `discovery: 'discoveryswarm.mauve.moe'`: The proxy server used by discovery-swarm-web\n- `driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n- `coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `destroy(cb)`\n\nThis closes all resources used by the SDK so you can safely end your process. `cb` will be invoked once resources are closed or if there's an error.\n\n### `resolveName(url, cb(err, key))`\n\nResolve a DNS name to a Dat key.\n\n  - `url` is a Dat URL like `dat://dat.foundation`\n  - `cb` will get invoked with the result of the resolve\n  - `key` will be the Dat key that you can pass to `hyperdrive`\n  - `err` will be any errors that happen during resolution\n\n### `deleteStorage(key, cb)`\n\nDelete the storage for a given archive or hypercore key.\n\n- `key` should be the key for the hypercore or hyperdrive that should be deleted\n- `cb` will be invoked after the deletion is over.\n\n### `const archive = Hyperdrive(location, opts)`\n\nThis initializes a Hyperdrive (aka a Dat archive), the SDK will begin finding peers for it and will de-duplicate calls to initializing the same archive more than once.\n\n- `location`: This **must** be provided. It's either a path for where the archive should be stored, or a Dat URL / key. If this is null, a new key will be generated.\n- `opts`: These are the options for configuring the hyperdrive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n  - `secretKey`: A secret key for granting write access. This can be useful when restoring backups.\n\nThe rest of the Hyperdrive docs were taken from the [Hyperdrive README](https://github.com/mafintosh/hyperdrive/blob/v9/README.md)\n\n#### `archive.version`\n\nGet the current version of the archive (incrementing number).\n\n#### `archive.key`\n\nThe public key identifying the archive.\n\n#### `archive.discoveryKey`\n\nA key derived from the public key that can be used to discovery other peers sharing this archive.\n\n#### `archive.writable`\n\nA boolean indicating whether the archive is writable.\n\n#### `archive.on('ready')`\n\nEmitted when the archive is fully ready and all properties has been populated.\n\n#### `archive.on('update')`\n\nEmitted when the archive has got a new change.\n\n#### `archive.on('error', err)`\n\nEmitted when a critical error during load happened.\n\n#### `archive.on('close')`\n\nEmitted when the archive has been closed\n\n#### `archive.on('extension', name, message, peer)`\n\nEmitted when a peer sends you an extension message with `archive.extension()`.\nYou can respond with `peer.extension(name, message)`.\n\n#### `var oldDrive = archive.checkout(version, [opts])`\n\nCheckout a readonly copy of the archive at an old version. Options are used to configure the `oldDrive`:\n\n```js\n{\n  metadataStorageCacheSize: 65536 // how many entries to use in the metadata hypercore's LRU cache\n  contentStorageCacheSize: 65536 // how many entries to use in the content hypercore's LRU cache\n  treeCacheSize: 65536 // how many entries to use in the append-tree's LRU cache\n}\n```\n\n#### `archive.download([path], [callback])`\n\nDownload all files in path of current version.\nIf no path is specified this will download all files.\n\nYou can use this with `.checkout(version)` to download a specific version of the archive.\n\n``` js\narchive.checkout(version).download()\n```\n\n#### `var stream = archive.history([options])`\n\nGet a stream of all changes and their versions from this archive.\n\n#### `archive.extension(name, message)`\n\nSend an extension message to connected peers. [Read more in the hypercore docs](https://github.com/mafintosh/hypercore#feedextensionname-message).\n\n#### `var stream = archive.createReadStream(name, [options])`\n\nRead a file out as a stream. Similar to fs.createReadStream.\n\nOptions include:\n\n``` js\n{\n  start: optionalByteOffset, // similar to fs\n  end: optionalInclusiveByteEndOffset, // similar to fs\n  length: optionalByteLength\n}\n```\n\n#### `archive.readFile(name, [options], callback)`\n\nRead an entire file into memory. Similar to fs.readFile.\n\nOptions can either be an object or a string\n\nOptions include:\n```js\n{\n  encoding: string\n  cached: true|false // default: false\n}\n```\nor a string can be passed as options to simply set the encoding - similar to fs.\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `var stream = archive.createDiffStream(version, [options])`\n\nDiff this archive with another version. `version` can both be a version number of a checkout instance of the archive. The `data` objects looks like this\n\n``` js\n{\n  type: 'put' | 'del',\n  name: '/some/path/name.txt',\n  value: {\n    // the stat object\n  }\n}\n```\n\n#### `var stream = archive.createWriteStream(name, [options])`\n\nWrite a file as a stream. Similar to fs.createWriteStream.\nIf `options.cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `archive.writeFile(name, buffer, [options], [callback])`\n\nWrite a file from a single buffer. Similar to fs.writeFile.\n\n#### `archive.unlink(name, [callback])`\n\nUnlinks (deletes) a file. Similar to fs.unlink.\n\n#### `archive.mkdir(name, [options], [callback])`\n\nExplictly create an directory. Similar to fs.mkdir\n\n#### `archive.rmdir(name, [callback])`\n\nDelete an empty directory. Similar to fs.rmdir.\n\n#### `archive.readdir(name, [options], [callback])`\n\nLists a directory. Similar to fs.readdir.\n\nOptions include:\n\n``` js\n{\n    cached: true|false, // default: false\n}\n```\n\nIf `cached` is set to `true`, this function returns results from the local version of the archive’s append-tree. Default behavior is to fetch the latest remote version of the archive before returning list of directories.\n\n#### `archive.stat(name, [options], callback)`\n\nStat an entry. Similar to fs.stat. Sample output:\n\n```\nStat {\n  dev: 0,\n  nlink: 1,\n  rdev: 0,\n  blksize: 0,\n  ino: 0,\n  mode: 16877,\n  uid: 0,\n  gid: 0,\n  size: 0,\n  offset: 0,\n  blocks: 0,\n  atime: 2017-04-10T18:59:00.147Z,\n  mtime: 2017-04-10T18:59:00.147Z,\n  ctime: 2017-04-10T18:59:00.147Z,\n  linkname: undefined }\n```\n\nThe output object includes methods similar to fs.stat:\n\n``` js\nvar stat = archive.stat('/hello.txt')\nstat.isDirectory()\nstat.isFile()\n```\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.lstat(name, [options], callback)`\n\nStat an entry but do not follow symlinks. Similar to fs.lstat.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.access(name, [options], callback)`\n\nSimilar to fs.access.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.open(name, flags, [mode], callback)`\n\nOpen a file and get a file descriptor back. Similar to fs.open.\n\nNote that currently only read mode is supported in this API.\n\n#### `archive.read(fd, buf, offset, len, position, callback)`\n\nRead from a file descriptor into a buffer. Similar to fs.read.\n\n#### `archive.close(fd, [callback])`\n\nClose a file. Similar to fs.close.\n\n#### `archive.close([callback])`\n\nCloses all open resources used by the archive.\nThe archive should no longer be used after calling this.\n\n### `const feed = Hypercore(key, opts)`\n\nInitializes a Hypercore (aka Feed) and begins replicating it.\n\n- `key`: This is the dat key for the feed, you can omit it if you want to create a new hypercore instance\n- `opts`: The options for configuring this feed\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n  - `secretKey`: The secret key to use for the feed. Useful for restoring from backups.\n\n#### `feed.append(data, [callback])`\n\nAppend a block of data to the feed.\n\nCallback is called with `(err, seq)` when all data has been written at the returned `seq` or an error occurred.\n\n#### `feed.get(index, [options], callback)`\n\nGet a block of data.\nIf the data is not available locally this method will prioritize and wait for the data to be downloaded before calling the callback.\n\nOptions include\n\n``` js\n{\n  wait: true, // wait for index to be downloaded\n  timeout: 0, // wait at max some milliseconds (0 means no timeout)\n  valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the feed's valueEncoding\n}\n```\n\nCallback is called with `(err, data)`\n\n#### `feed.getBatch(start, end, [options], callback)`\n\nGet a range of blocks efficiently. Options include\n\n``` js\n{\n  wait: sameAsAbove,\n  timeout: sameAsAbove,\n  valueEncoding: sameAsAbove\n}\n```\n\n#### `feed.head([options], callback)`\n\nGet the block of data at the tip of the feed. This will be the most recently\nappended block.\n\nAccepts the same `options` as `feed.get()`.\n\n#### `feed.download([range], [callback])`\n\nDownload a range of data. Callback is called when all data has been downloaded.\nA range can have the following properties:\n\n``` js\n{\n  start: startIndex,\n  end: nonInclusiveEndIndex,\n  linear: false // download range linearly and not randomly\n}\n```\n\nIf you do not mark a range the entire feed will be marked for download.\n\nIf you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire\nfeed will be marked for download for you when the feed is created.\n\n#### `feed.undownload(range)`\n\nCancel a previous download request.\n\n#### `feed.signature([index], callback)`\n\nGet a signature proving the correctness of the block at index, or the whole stream.\n\nCallback is called with `(err, signature)`.\nThe signature has the following properties:\n``` js\n{\n  index: lastSignedBlock,\n  signature: Buffer\n}\n```\n\n#### `feed.verify(index, signature, callback)`\n\nVerify a signature is correct for the data up to index, which must be the last signed\nblock associated with the signature.\n\nCallback is called with `(err, success)` where success is true only if the signature is\ncorrect.\n\n#### `feed.rootHashes(index, callback)`\n\nRetrieve the root *hashes* for given `index`.\n\nCallback is called with `(err, roots)`; `roots` is an *Array* of *Node* objects:\n```\nNode {\n  index: location in the merkle tree of this root\n  size: total bytes in children of this root\n  hash: hash of the children of this root (32-byte buffer)\n}\n```\n\n\n#### `var number = feed.downloaded([start], [end])`\n\nReturns total number of downloaded blocks within range.\nIf `end` is not specified it will default to the total number of blocks.\nIf `start` is not specified it will default to 0.\n\n#### `var bool = feed.has(index)`\n\nReturn true if a data block is available locally.\nFalse otherwise.\n\n#### `var bool = feed.has(start, end)`\nReturn true if all data blocks within a range are available locally.\nFalse otherwise.\n\n#### `feed.clear(start, [end], [callback])`\n\nClear a range of data from the local cache.\nWill clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.\n\n`end` defaults to `start + 1`.\n\n#### `feed.seek(byteOffset, callback)`\n\nSeek to a byte offset.\n\nCalls the callback with `(err, index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is\nthe relative byte offset in the data block.\n\n#### `feed.update([minLength], [callback])`\n\nWait for the feed to contain at least `minLength` elements.\nIf you do not provide `minLength` it will be set to current length + 1.\n\nDoes not download any data from peers except for a proof of the new feed length.\n\n``` js\nconsole.log('length is', feed.length)\nfeed.update(function () {\n  console.log('length has increased', feed.length)\n})\n```\n\n#### `var stream = feed.createReadStream([options])`\n\nCreate a readable stream of data.\n\nOptions include:\n\n``` js\n{\n  start: 0, // read from this index\n  end: feed.length, // read until this index\n  snapshot: true, // if set to false it will update `end` to `feed.length` on every read\n  tail: false, // sets `start` to `feed.length`\n  live: false, // set to true to keep reading forever\n  timeout: 0, // timeout for each data event (0 means no timeout)\n  wait: true // wait for data to be downloaded\n}\n```\n\n#### `var stream = feed.createWriteStream()`\n\nCreate a writable stream.\n\n#### `feed.close([callback])`\n\nFully close this feed.\n\nCalls the callback with `(err)` when all storage has been closed.\n\n#### `feed.audit([callback])`\n\nAudit all data in the feed. Will check that all current data stored\nmatches the hashes in the merkle tree and clear the bitfield if not.\n\nWhen done a report is passed to the callback that looks like this:\n\n```js\n{\n  valid: 10, // how many data blocks matches the hashes\n  invalid: 0, // how many did not\n}\n```\n\nIf a block does not match the hash it is cleared from the data bitfield.\n\n#### `feed.writable`\n\nCan we append to this feed?\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.readable`\n\nCan we read from this feed? After closing a feed this will be false.\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.key`\n\nBuffer containing the public key identifying this feed.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.discoveryKey`\n\nBuffer containing a key derived from the feed.key.\nIn contrast to `feed.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same feed, without leaking the feed key.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.length`\n\nHow many blocks of data are available on this feed?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.byteLength`\n\nHow much data is available on this feed in bytes?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.stats`\n\nReturn per-peer and total upload/download counts.\n\nThe returned object is of the form:\n```js\n{\n  totals: {\n    uploadedBytes: 100,\n    uploadedBlocks: 1,\n    downloadedBytes: 0,\n    downloadedBlocks: 0\n  },\n  peers: [\n    {\n      uploadedBytes: 100,\n      uploadedBlocks: 1,\n      downloadedBytes: 0,\n      downloadedBlocks: 0\n    },\n    ...\n  ]\n}\n```\n\nStats will be collected by default, but this can be disabled by setting `opts.stats` to false.\n\n#### `feed.on('ready')`\n\nEmitted when the feed is ready and all properties have been populated.\n\n#### `feed.on('error', err)`\n\nEmitted when the feed experiences a critical error.\n\n#### `feed.on('download', index, data)`\n\nEmitted when a data block has been downloaded.\n\n#### `feed.on('upload', index, data)`\n\nEmitted when a data block is uploaded.\n\n#### `feed.on('append')`\n\nEmitted when the feed has been appended to (i.e. has a new length / byteLength)\n\n#### `feed.on('sync')`\n\nEmitted every time ALL data from `0` to `feed.length` has been downloaded.\n\n#### `feed.on('close')`\n\nEmitted when the feed has been fully closed\n\n---\n\n[Dat Project]: https://dat.foundation\n","readmeFilename":"README.md","_id":"dat-sdk@2.0.0-2","_nodeVersion":"11.15.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-ExWw9sTIl2NaCwH7k6FdOBVF+2Tx+rngTJnOtgIBIDgEF4pzFjyXDV/3UA4NJjJLpns6jRkxvvBQpVTt3wTS2w==","shasum":"6149d8ca10b45b356ad5f1608852c54a1184b3f6","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.0.0-2.tgz","fileCount":14,"unpackedSize":63300,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeQwN7CRA9TVsSAnZWagAAuyQP/jgD2rTBD34rqTmkXvCm\nlKTV75KGVpuYWnlNkSmp4aEl0QCmd7Qi+fOilEbJ4JCyPbr/ns1OiA/Yg/k4\nWt5HnlOKcNWfqmstITkC6vTVEYgnda18aAFvt2COw43DzjfdNgHQCu+v3UVg\nkfAHKgu7U8lcl5t8nGSz4rbKXbRiXqdwPTGAuAOaldszHuS0upWzoD/rrvAc\nwD0zDd4WgWb0fX/8OXA8Qm2249sg+F5pdrpf27f9zNOJSnQPSgt5vDdv/f4Z\nrd0FPsG8IhZSGd/74VuN30cPMDWPHuRm9S1B3gndDjDupWphRRtoXNdUh5v8\ncInXRKXiKgjnqu/WpM+ah/2Hm0LPFkxBC/ES6M5X6bU/T8vov5HaOye9onmd\nXS0gQeubilX1P+dYy2osxSFWEcKCma/xk4sH+RP+eoC31JxNWJxoCU1aGQyb\ngRPqZM9f2TYX48+GJuAnfWehMg52DNNGvQhdx68YlA9pglV12X5JP5Mu9D/+\nvh04732F7c8GkS4aA2hcJ66DvtihJ0CMUabWGszgOXceQDwj9BWEzy3Ew/rK\nemGfIX1zVywFvB18UVwcVgqFzXdmUGV98x0KiF1n4uxAUzuBtOlBVpHgHkBg\n2pMy/xr+5T0XF1ViBW0gQSLFoi2a2Yw0px/T0nH2aVPh3gEve6O/jawXVU0+\nxa5n\r\n=QqNl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF4Tm+nNCmEjWS+fR8U9bcp3xs3hVFfrtC6pO2CyHIprAiEAzn7APJrdIq3Jgbi386Az/EncsG4EHp4EQjuNuGLr3fU="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.0.0-2_1581450107252_0.029383652594809684"},"_hasShrinkwrap":false},"2.0.0-3":{"name":"dat-sdk","version":"2.0.0-3","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","./localstorage":"./localstorage-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^1.1.0","@geut/hyperdrive-promise":"^3.0.0","concat-stream":"^2.0.0","corestore":"^5.0.9","corestore-swarm-networking":"^4.0.3","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^8.7.0","hypercore-crypto":"^1.0.0","hypercore-protocol":"^7.10.0","hyperdrive":"^10.8.10","hyperswarm-web":"^1.0.1","node-localstorage":"^2.1.5","random-access-application":"^1.0.0","random-access-memory":"^3.1.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"466e2bfc6f09a2c5bc87ada9e6a42c676d47e241","readme":"# sdk\nThe official Dat SDK\n\n[<img src=\"https://datproject.github.io/design/downloads/dat-logo.png\" align=\"right\" width=\"140\">][Dat Project]\n\n## Why use this?\n\nDat consists of a bunch of low level building blocks for working with data in distributed applications. Although this modularity makes it easy to mix and match pieces, it adds complexity when it comes to actually building something.\n\nThe Dat SDK combines the lower level pieces of the Dat ecosystem into high level APIs that you can use across platforms so that you can focus on your application rather than the gritty details of how it works.\n\n## Goals\n\n- High level API\n- Cross-platform with same codebase\n  - ✔ Node\n  - ✔ Web (non-beaker)\n  - ✔ Beaker (Promise API acts as polyfill for Beaker)\n  - React-Native?\n  - Electron?\n\n\n## Installing\n\n[Node.js](https://nodejs.org/) / [Browserify](http://browserify.org/) workflows:\n\n```shell\nnpm install --save dat-sdk\n```\n\n```js\nconst SDK = require('dat-sdk')\nconst SDKPromise = require('dat-sdk/promise')\nconst {DatArchive} = require('dat-sdk/auto')\n```\n\nOr Web Browsers\n\n```html\n<script src=\"https://bundle.run/dat-sdk@1\"></script>\n<script src=\"https://bundle.run/dat-sdk@1/promise.js\"></script>\n<script src=\"https://bundle.run/dat-sdk@1/auto.js\"></script>\n<script>\n  const SDK = window.datSDK\n  // Look at the examples from here\n</script>\n```\n\n## Examples (browserify)\n\nYou can bundle your code with [browserify](http://browserify.org/) using the following command:\n\n```\nbrowserify index.js > bundle.js\n```\n\nThen you can include `bundle.js` in your HTML page.\n\n## Examples (webpack.config.js)\n\nTo bundle with webpack instead of browserify, resolve the `fs` module with the `graceful-fs` module.\n\n```js\nconst path = require('path')\n\nmodule.exports = {\n  entry: './index.js',\n  target: 'web',\n  resolve: {\n    alias: {\n      fs: 'graceful-fs'\n    }\n  },\n  output: {\n    filename: 'bundle.js',\n    path: path.resolve(__dirname, 'dist')\n  }\n}\n```\n\nThen you can include `./dist/bundle.js` in your HTML page.\n\n## Examples (Promise)\n\n```js\n// Auto-detects sane defaults based on your environment\n// Uses Beaker's APIs if they are if they are available\n// DatArchive is the same as Beaker\n// https://beakerbrowser.com/docs/apis/dat\nconst {DatArchive} = require('dat-sdk/auto')\n\nconst archive = await DatArchive.load('dat://dat.foundation')\n\nconst someData = await archive.readFile('/dat.json', 'utf8')\n\nconsole.log('Dat foundation dat.json:', someData)\n\nconst myArchive = await DatArchive.create({\n  title: 'My Archive'\n})\n\nawait myArchive.writeFile('/example.txt', 'Hello World!')\n\n// Log the secret key in case you want to save it for later\nconsole.log(await myArchive.getSecretKey())\n\n// Use a saved secret key\nawait DatArchive.load(someKey, {\n  secretKey: someSecretKey\n})\n```\n\n## API/Examples (Callbacks)\n\n```js\nconst SDK = require('dat-sdk')\nconst { Hypercore, Hyperdrive, resolveName, deleteStorage, destroy } = SDK()\n\nconst archive = Hyperdrive(null, {\n  // This archive will disappear after the process exits\n  // This is here so that running the example doesn't clog up your history\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  //storage: RAI\n})\n\narchive.ready(() => {\n  const url = `dat://${archive.key.toString('hex')}`\n\n  // TODO: Save this for later!\n  console.log(`Here's your URL: ${url}`)\n\n  // Check out the hyperdrive docs for what you can do with it\n  // https://www.npmjs.com/package/hyperdrive#api\n  archive.writeFile('/example.txt', 'Hello World!', () => {\n    console.log('Written example file!')\n  })\n})\n\nresolveName('dat://beakerbrowser.com', (err, url) => {\n  if (err) throw err\n  const archive = Hyperdrive(url)\n\n  archive.readFile('/dat.json', 'utf8', (err, data) => {\n    if (err) throw err\n    console.log(`Beaker's dat.json is ${data}`)\n\n    archive.close((err) => {\n      if (err) throw err\n      deleteStorage(archive.key, (e) => {\n        if (e) throw e\n        console.log('Deleted beaker storage')\n      })\n    })\n  })\n})\n\nconst SOME_URL = 'dat://0a9e202b8055721bd2bc93b3c9bbc03efdbda9cfee91f01a123fdeaadeba303e/'\n\nconst someArchive = Hyperdrive(SOME_URL)\n\nreallyReady(someArchive, () => {\n  someArchive.readdir('/', console.log)\n})\n\n// This make sure you sync up with peers before trying to do anything with the archive\nfunction reallyReady (archive, cb) {\n  if (archive.metadata.peers.length) {\n    archive.metadata.update({ ifAvailable: true }, cb)\n  } else {\n    archive.metadata.once('peer-add', () => {\n      archive.metadata.update({ ifAvailable: true }, cb)\n    })\n  }\n}\n\n// Create a hypercore\n// Check out the hypercore docs for what you can do with it\n// https://github.com/mafintosh/hypercore\nconst myCore = Hypercore(null, {\n  valueEncoding: 'json',\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  // storage: RAI\n})\n\n// Add some data to it\nmyCore.append(JSON.stringify({\n  name: 'Alice'\n}), () => {\n  // Use extension messages for sending extra data over the p2p connection\n  const discoveryCoreKey = 'dat://bee80ff3a4ee5e727dc44197cb9d25bf8f19d50b0f3ad2984cfe5b7d14e75de7'\n  const discoveryCore = new Hypercore(discoveryCoreKey, {\n    extensions: ['discovery']\n  })\n\n  // When you find a new peer, tell them about your core\n  discoveryCore.on('peer-add', (peer) => {\n    console.log('Got a peer!')\n    peer.extension('discovery', myCore.key)\n  })\n\n  // When a peer tells you about their core, load it\n  discoveryCore.on('extension', (type, message) => {\n    console.log('Got extension message', type, message)\n    if (type !== 'discovery') return\n    discoveryCore.close()\n\n    const otherCore = new Hypercore(message, {\n      valueEncoding: 'json',\n      persist: false\n    })\n\n    // Render the peer's data from their core\n    otherCore.get(0, console.log)\n  })\n})\n\nconst hypertrie = require('hypertrie')\n\n// Pass in hypercores from the SDK into other dat data structures\n// Check out what you can do with hypertrie from there:\n// https://github.com/mafintosh/hypertrie\nconst trie = hypertrie(null, {\n  feed: new Hypercore(null, {\n    persist: false\n  })\n})\n\ntrie.put('key', 'value', () => {\n  trie.get('key', (err, node) => {\n    console.log('Got key: ', node.key)\n    console.log('Loaded value from trie: ', node.value)\n  })\n})\n\n```\n\n## API (Promise)\n\n### `const {DatArchive, destroy} = SDK({ storageOpts, swarmOpts, driveOpts, coreOpts, dnsOpts })`\n\nThis initializes the Dat SDK.\n\n\n- `storageOpts`: This lets you configure how the SDK will store data. Used by the [universal-dat-storage](https://github.com/RangerMauve/universal-dat-storage) module.\n  - `application: 'dat'`: The name of the application using the SDK if you want to have the data stored separately. Used by [env-paths](https://github.com/sindresorhus/env-paths#pathsdata) to generate the storageLocation\n  - `storageLocation: null`: A location (on disk) to store the archives in.\n- `swarmOpts`: This lets you configure [discovery-swarm](https://www.npmjs.com/package/discovery-swarm) and [discovery-swarm-web](https://www.npmjs.com/package/discovery-swarm-web)\n  - `id`: The ID to use when doing p2p traffic\n  - `maxConnections`: The maximum number of connections to keep for this swarm.\n  - `extensions: []`: The set of extension messages to use when replicating with peers\n  - `utp: true`: Whether to use utp in discovery-swarm\n  - `tcp: true`: Whether to use tcp in discovery-swarm\n  - `bootstrap: ['signal.mauve.moe']`: The WebRTC bootstrap server list used by discovery-swarm-web\n  - `discovery: 'discoveryswarm.mauve.moe'`: The proxy server used by discovery-swarm-web\n- `driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n- `coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `await destroy()`\n\nRelease all resources being used by the SDK so you can safely stop your process.\n\n### `const archive = await DatArchive.load(location, opts)`\n\nThis loads up a Dat Archive for the given URL / Key / File path.\n\n- `location`: This is either the `dat://` URL (which might have a domain), a dat key, or a file path for your archive.\n- `opts`: These are options for configuring this archive\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n\n### `const archive = await DatArchive.create(opts)`\n\nThis creates a new Dat Archive.\n\n- `opts` These are the options for the archive's metadata and it's properties\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n  - `title`: The title of the archive\n  - `description`: A brief description of what the archive contains\n  - `type`: An array of strings for the type of archive this is. See the [manifest](https://beakerbrowser.com/docs/apis/manifest.html#type) docs for more info.\n\n### `const archive = await DatArchive.fork(url, opts)`\n\nCreate a new archive based on the data within another archive\n\n- `url` The URL of the archive to fork off of\n- `opts` These options will be used in the new archive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n  - `title`: The title of the archive\n  - `description`: A brief description of what the archive contains\n  - `type`: An array of strings for the type of archive this is. See the [manifest](https://beakerbrowser.com/docs/apis/manifest.html#type) docs for more info.\n\n### `await DatArchive.unlink(url)`\n\nDelete the storage for an archive.\n\n- `url`: The URL of the archive to delete\n\n### `const archive = await DatArchive.selectArchive()`\n\nPrompt the user to select an archive from the ones they have created locally. The implementation is super hacky, so use with caution.\n\n### `const url = await DatArchive.resolveName(url)`\n\nResolve a URL that uses dat-dns to the raw `dat://` url.\n\n- `url`: The `dat://` URL with a domain to resolve\n\n#### `const url = archive.url`\n\nGet the URL for the given archive.\n\n#### `const info = await archive.getInfo()`\n\nGet metadata about the archive\n\n- `info`: The metadata related to the archive.\n  - `key`: string (the archive public key)\n  - `url`: string (the archive URL)\n  - `isOwner`: boolean (is the user the owner of this archive?)\n  - `version`: number (the archive's current revision number)\n  - `peers`: number (the number of active connections for the archive)\n  - `mtime`: number (the walltime of the last received update; is reliable)\n  - `size`: number (bytes, the size-on-disk of the archive)\n  - `title`: string (the archive title)\n  - `description`: string (the archive description)\n  - `type`: array of strings (the archive's type identifiers)\n  - `links`: object (top-level links to other resources)\n\n#### `await archive.configure(configuration)`\n\nUpdate the metadata about the archive.\n\n- `configuration`: The metadata to update\n  - `title` String. The title of the archive.\n  - `description` String. The description of the archive.\n  - `type` Array<String>. The archive’s type identifiers. Learn more.\n  - `links` Object. Top-level links to other resources. Learn more.\n  - `web_root` String. Path of the folder from which all web requests should be served.\n  - `fallback_page` String. Path to a fallback page to serve instead of the default 404 page.\n\n#### `const stat = await archive.stat(path)`\n\n- `path`: The path to get stats about from the archive\n- `stat.isDirectory()`: Check if the path is a directory\n- `stat.isFile()`: Check if the path is a file\n- `stat.size`: number (bytes)\n- `stat.blocks`: number (number of data blocks in the metadata)\n- `stat.downloaded`: number (number of blocks downloaded, if a remote archive)\n- `stat.mtime`: Date (last modified time; not reliable)\n- `stat.ctime`: Date (creation time; not reliable)`\n\n#### `const data = await archive.readFile(path, opts)`\n\n- `path` The path to the file you wish to read\n- `opts.encoding`: The encoding to read the file with, can be one of `utf8`, `base64`, `hex`, and `binary`\n- `data`: The entire contents of the file, either as a string, or an ArrayBuffer if you used the `binary` encoding.\n\n#### `const list = await archive.readdir(path, opts)`\n\nLists the files and folders within a directory.\n\n- `path`: The path to the directory you wish to read\n- `opts`\n  - `recursive`: Set to `true` to list subdirectories, too\n  - `stat`: Get the `Stat` objects instead of names.\n- `list`: Either a list of the file/folder names or a list of the Stat object for those items.\n\n#### `await archive.writeFile(path, data, opts)`\n\nWrite a file to your archive.\n\n- `path`: The location to write your file to.\n- `data`: Either a string or ArrayBuffer for the data you wish to save\n- `opts.encoding`: The encoding to use when writing. Must be one of `utf8`, `base64`, `hex`, or `binary`. Encoding will default to `utf8` for strings, and `binary` for ArrayBuffers.\n\n#### `await archive.mkdir(path)`\n\nCreate a directory at the given path. Will fail if the parent directory doesn't exist.\n\n- `path`: The path to the directory\n\n#### `await archive.unlink(path)`\n\nDelete the file at the given path.\n\n- `path`: The path to the file\n\n#### `await rmdir(path, opts)`\n\nDeletes the directory at the given path.\n\n- `path`: The path to the directory\n- `opts.recursive`: Whether to delete subfolders / files.\n\n#### `await archive.copy(path, dstPath)`\n\nCopy a file from one location to another.\n\n- `path`: The path to the file / directory to copy from.\n- `dstPath`: The location the file/directory should be copied to\n\n#### `await archive.rename(oldPath, newPath)`\n\nRename / move a file or directory.\n\n- `oldPath`: The path of the file/directory to rename\n- `newPath`: What the file/directory should be renamed to.\n\n#### `const history = await archive.history({opts})`\n\nList the history of all the changes in this archive.\n\n- `opts`: The options for how to fetch the history of the archive\n  - `start`: Where in the history to start reading\n  - `end`: Where in the history to stop reading\n  - `reverse`: Set to `true` to iterate through the history backwards\n- `history`: An array of history items representing changes\n  - `path`: Which file / directory got modified.\n  - `version`: The version number the archive was at for this item\n  - `type`: Either `put` for additions or `del` for deletions\n\n#### `const olderArchive = archive.checkout(version)`\n\nGet a view of the archive as it was at an earlier version.\n\n- `version`: The integer representing the version you whish to look at. This correlates to the version in the history.\n\n#### `await archive.download(path)`\n\nDownload the file or folder at the given path from the network. Use `/` to download the entire archive.\n\n#### `const events = archive.watch(pattern, onInvalidated)`\n\n```js\nconst events = archive.watch(['**/*.md'])\nevents.addEventListener('changed', ({path}) => console.log(path, 'changed!'))\n\nevents.close() // Stop listening for changes\n```\n\nWatch for changes in the archive.\n\n- `pattern`: This can either be omitted to view all changes, or have an [anymatch](https://www.npmjs.com/package/anymatch) pattern to filter out just the changes you want.\n- `onInvalidated`: You can optionally pass in this function to listen for changes instead of using an event listener.\n\n#### `archive.addEventListener('network-changed', ({peers}) => void 0)`\n\nListen for changes in the number of peers connected to for the archive.\n\n- `peers`: The number of connected peers\n\n#### `archive.addEventListener('download', ({feed, block, bytes}) => void 0)`\n\nListen for download progress from the archive\n\n- `feed`: The data feed the block was part of. Either `metadata` or `content`\n- `block`: The index of the block downloaded\n- `bytes`: The size of the block in bytes\n\n#### `archive.addEventListener('upload', ({feed, block, bytes}) => void 0)`\n\nListen for upload progress from the archive.\n\n- `feed`: The data feed the block was part of. Either `metadata` or `content`\n- `block`: The index of the block uploaded\n- `bytes`: The size of the block in bytes\n\n#### `archive.addEventListener('sync', ({feed}) => void 0)`\n\nEmitted when all known data has been downloaded\n\n## API (Callbacks)\n\n### `const {Hypercore, Hyperdrive, resolveName, deleteStorage, destroy} = SDK({ storageOpts, swarmOpts, driveOpts, coreOpts, dnsOpts })`\n\nCreates an instance of the Dat SDK based on the options.\n\n- `storageOpts`: This lets you configure how the SDK will store data. Used by the [universal-dat-storage](https://github.com/RangerMauve/universal-dat-storage) module.\n  - `application: 'dat'`: The name of the application using the SDK if you want to have the data stored separately. Used by [env-paths](https://github.com/sindresorhus/env-paths#pathsdata) to generate the storageLocation\n  - `storageLocation: null`: A location (on disk) to store the archives in.\n- `swarmOpts`: This lets you configure [discovery-swarm](https://www.npmjs.com/package/discovery-swarm) and [discovery-swarm-web](https://www.npmjs.com/package/discovery-swarm-web)\n  - `id`: The ID to use when doing p2p traffic\n  - `maxConnections`: The maximum number of connections to keep for this swarm.\n  - `extensions: []`: The set of extension messages to use when replicating with peers\n  - `utp: true`: Whether to use utp in discovery-swarm\n  - `tcp: true`: Whether to use tcp in discovery-swarm\n  - `bootstrap: ['signal.mauve.moe']`: The WebRTC bootstrap server list used by discovery-swarm-web\n  - `discovery: 'discoveryswarm.mauve.moe'`: The proxy server used by discovery-swarm-web\n- `driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n- `coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `destroy(cb)`\n\nThis closes all resources used by the SDK so you can safely end your process. `cb` will be invoked once resources are closed or if there's an error.\n\n### `resolveName(url, cb(err, key))`\n\nResolve a DNS name to a Dat key.\n\n  - `url` is a Dat URL like `dat://dat.foundation`\n  - `cb` will get invoked with the result of the resolve\n  - `key` will be the Dat key that you can pass to `hyperdrive`\n  - `err` will be any errors that happen during resolution\n\n### `deleteStorage(key, cb)`\n\nDelete the storage for a given archive or hypercore key.\n\n- `key` should be the key for the hypercore or hyperdrive that should be deleted\n- `cb` will be invoked after the deletion is over.\n\n### `const archive = Hyperdrive(location, opts)`\n\nThis initializes a Hyperdrive (aka a Dat archive), the SDK will begin finding peers for it and will de-duplicate calls to initializing the same archive more than once.\n\n- `location`: This **must** be provided. It's either a path for where the archive should be stored, or a Dat URL / key. If this is null, a new key will be generated.\n- `opts`: These are the options for configuring the hyperdrive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n  - `secretKey`: A secret key for granting write access. This can be useful when restoring backups.\n\nThe rest of the Hyperdrive docs were taken from the [Hyperdrive README](https://github.com/mafintosh/hyperdrive/blob/v9/README.md)\n\n#### `archive.version`\n\nGet the current version of the archive (incrementing number).\n\n#### `archive.key`\n\nThe public key identifying the archive.\n\n#### `archive.discoveryKey`\n\nA key derived from the public key that can be used to discovery other peers sharing this archive.\n\n#### `archive.writable`\n\nA boolean indicating whether the archive is writable.\n\n#### `archive.on('ready')`\n\nEmitted when the archive is fully ready and all properties has been populated.\n\n#### `archive.on('update')`\n\nEmitted when the archive has got a new change.\n\n#### `archive.on('error', err)`\n\nEmitted when a critical error during load happened.\n\n#### `archive.on('close')`\n\nEmitted when the archive has been closed\n\n#### `archive.on('extension', name, message, peer)`\n\nEmitted when a peer sends you an extension message with `archive.extension()`.\nYou can respond with `peer.extension(name, message)`.\n\n#### `var oldDrive = archive.checkout(version, [opts])`\n\nCheckout a readonly copy of the archive at an old version. Options are used to configure the `oldDrive`:\n\n```js\n{\n  metadataStorageCacheSize: 65536 // how many entries to use in the metadata hypercore's LRU cache\n  contentStorageCacheSize: 65536 // how many entries to use in the content hypercore's LRU cache\n  treeCacheSize: 65536 // how many entries to use in the append-tree's LRU cache\n}\n```\n\n#### `archive.download([path], [callback])`\n\nDownload all files in path of current version.\nIf no path is specified this will download all files.\n\nYou can use this with `.checkout(version)` to download a specific version of the archive.\n\n``` js\narchive.checkout(version).download()\n```\n\n#### `var stream = archive.history([options])`\n\nGet a stream of all changes and their versions from this archive.\n\n#### `archive.extension(name, message)`\n\nSend an extension message to connected peers. [Read more in the hypercore docs](https://github.com/mafintosh/hypercore#feedextensionname-message).\n\n#### `var stream = archive.createReadStream(name, [options])`\n\nRead a file out as a stream. Similar to fs.createReadStream.\n\nOptions include:\n\n``` js\n{\n  start: optionalByteOffset, // similar to fs\n  end: optionalInclusiveByteEndOffset, // similar to fs\n  length: optionalByteLength\n}\n```\n\n#### `archive.readFile(name, [options], callback)`\n\nRead an entire file into memory. Similar to fs.readFile.\n\nOptions can either be an object or a string\n\nOptions include:\n```js\n{\n  encoding: string\n  cached: true|false // default: false\n}\n```\nor a string can be passed as options to simply set the encoding - similar to fs.\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `var stream = archive.createDiffStream(version, [options])`\n\nDiff this archive with another version. `version` can both be a version number of a checkout instance of the archive. The `data` objects looks like this\n\n``` js\n{\n  type: 'put' | 'del',\n  name: '/some/path/name.txt',\n  value: {\n    // the stat object\n  }\n}\n```\n\n#### `var stream = archive.createWriteStream(name, [options])`\n\nWrite a file as a stream. Similar to fs.createWriteStream.\nIf `options.cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `archive.writeFile(name, buffer, [options], [callback])`\n\nWrite a file from a single buffer. Similar to fs.writeFile.\n\n#### `archive.unlink(name, [callback])`\n\nUnlinks (deletes) a file. Similar to fs.unlink.\n\n#### `archive.mkdir(name, [options], [callback])`\n\nExplictly create an directory. Similar to fs.mkdir\n\n#### `archive.rmdir(name, [callback])`\n\nDelete an empty directory. Similar to fs.rmdir.\n\n#### `archive.readdir(name, [options], [callback])`\n\nLists a directory. Similar to fs.readdir.\n\nOptions include:\n\n``` js\n{\n    cached: true|false, // default: false\n}\n```\n\nIf `cached` is set to `true`, this function returns results from the local version of the archive’s append-tree. Default behavior is to fetch the latest remote version of the archive before returning list of directories.\n\n#### `archive.stat(name, [options], callback)`\n\nStat an entry. Similar to fs.stat. Sample output:\n\n```\nStat {\n  dev: 0,\n  nlink: 1,\n  rdev: 0,\n  blksize: 0,\n  ino: 0,\n  mode: 16877,\n  uid: 0,\n  gid: 0,\n  size: 0,\n  offset: 0,\n  blocks: 0,\n  atime: 2017-04-10T18:59:00.147Z,\n  mtime: 2017-04-10T18:59:00.147Z,\n  ctime: 2017-04-10T18:59:00.147Z,\n  linkname: undefined }\n```\n\nThe output object includes methods similar to fs.stat:\n\n``` js\nvar stat = archive.stat('/hello.txt')\nstat.isDirectory()\nstat.isFile()\n```\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.lstat(name, [options], callback)`\n\nStat an entry but do not follow symlinks. Similar to fs.lstat.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.access(name, [options], callback)`\n\nSimilar to fs.access.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.open(name, flags, [mode], callback)`\n\nOpen a file and get a file descriptor back. Similar to fs.open.\n\nNote that currently only read mode is supported in this API.\n\n#### `archive.read(fd, buf, offset, len, position, callback)`\n\nRead from a file descriptor into a buffer. Similar to fs.read.\n\n#### `archive.close(fd, [callback])`\n\nClose a file. Similar to fs.close.\n\n#### `archive.close([callback])`\n\nCloses all open resources used by the archive.\nThe archive should no longer be used after calling this.\n\n### `const feed = Hypercore(key, opts)`\n\nInitializes a Hypercore (aka Feed) and begins replicating it.\n\n- `key`: This is the dat key for the feed, you can omit it if you want to create a new hypercore instance\n- `opts`: The options for configuring this feed\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n  - `secretKey`: The secret key to use for the feed. Useful for restoring from backups.\n\n#### `feed.append(data, [callback])`\n\nAppend a block of data to the feed.\n\nCallback is called with `(err, seq)` when all data has been written at the returned `seq` or an error occurred.\n\n#### `feed.get(index, [options], callback)`\n\nGet a block of data.\nIf the data is not available locally this method will prioritize and wait for the data to be downloaded before calling the callback.\n\nOptions include\n\n``` js\n{\n  wait: true, // wait for index to be downloaded\n  timeout: 0, // wait at max some milliseconds (0 means no timeout)\n  valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the feed's valueEncoding\n}\n```\n\nCallback is called with `(err, data)`\n\n#### `feed.getBatch(start, end, [options], callback)`\n\nGet a range of blocks efficiently. Options include\n\n``` js\n{\n  wait: sameAsAbove,\n  timeout: sameAsAbove,\n  valueEncoding: sameAsAbove\n}\n```\n\n#### `feed.head([options], callback)`\n\nGet the block of data at the tip of the feed. This will be the most recently\nappended block.\n\nAccepts the same `options` as `feed.get()`.\n\n#### `feed.download([range], [callback])`\n\nDownload a range of data. Callback is called when all data has been downloaded.\nA range can have the following properties:\n\n``` js\n{\n  start: startIndex,\n  end: nonInclusiveEndIndex,\n  linear: false // download range linearly and not randomly\n}\n```\n\nIf you do not mark a range the entire feed will be marked for download.\n\nIf you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire\nfeed will be marked for download for you when the feed is created.\n\n#### `feed.undownload(range)`\n\nCancel a previous download request.\n\n#### `feed.signature([index], callback)`\n\nGet a signature proving the correctness of the block at index, or the whole stream.\n\nCallback is called with `(err, signature)`.\nThe signature has the following properties:\n``` js\n{\n  index: lastSignedBlock,\n  signature: Buffer\n}\n```\n\n#### `feed.verify(index, signature, callback)`\n\nVerify a signature is correct for the data up to index, which must be the last signed\nblock associated with the signature.\n\nCallback is called with `(err, success)` where success is true only if the signature is\ncorrect.\n\n#### `feed.rootHashes(index, callback)`\n\nRetrieve the root *hashes* for given `index`.\n\nCallback is called with `(err, roots)`; `roots` is an *Array* of *Node* objects:\n```\nNode {\n  index: location in the merkle tree of this root\n  size: total bytes in children of this root\n  hash: hash of the children of this root (32-byte buffer)\n}\n```\n\n\n#### `var number = feed.downloaded([start], [end])`\n\nReturns total number of downloaded blocks within range.\nIf `end` is not specified it will default to the total number of blocks.\nIf `start` is not specified it will default to 0.\n\n#### `var bool = feed.has(index)`\n\nReturn true if a data block is available locally.\nFalse otherwise.\n\n#### `var bool = feed.has(start, end)`\nReturn true if all data blocks within a range are available locally.\nFalse otherwise.\n\n#### `feed.clear(start, [end], [callback])`\n\nClear a range of data from the local cache.\nWill clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.\n\n`end` defaults to `start + 1`.\n\n#### `feed.seek(byteOffset, callback)`\n\nSeek to a byte offset.\n\nCalls the callback with `(err, index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is\nthe relative byte offset in the data block.\n\n#### `feed.update([minLength], [callback])`\n\nWait for the feed to contain at least `minLength` elements.\nIf you do not provide `minLength` it will be set to current length + 1.\n\nDoes not download any data from peers except for a proof of the new feed length.\n\n``` js\nconsole.log('length is', feed.length)\nfeed.update(function () {\n  console.log('length has increased', feed.length)\n})\n```\n\n#### `var stream = feed.createReadStream([options])`\n\nCreate a readable stream of data.\n\nOptions include:\n\n``` js\n{\n  start: 0, // read from this index\n  end: feed.length, // read until this index\n  snapshot: true, // if set to false it will update `end` to `feed.length` on every read\n  tail: false, // sets `start` to `feed.length`\n  live: false, // set to true to keep reading forever\n  timeout: 0, // timeout for each data event (0 means no timeout)\n  wait: true // wait for data to be downloaded\n}\n```\n\n#### `var stream = feed.createWriteStream()`\n\nCreate a writable stream.\n\n#### `feed.close([callback])`\n\nFully close this feed.\n\nCalls the callback with `(err)` when all storage has been closed.\n\n#### `feed.audit([callback])`\n\nAudit all data in the feed. Will check that all current data stored\nmatches the hashes in the merkle tree and clear the bitfield if not.\n\nWhen done a report is passed to the callback that looks like this:\n\n```js\n{\n  valid: 10, // how many data blocks matches the hashes\n  invalid: 0, // how many did not\n}\n```\n\nIf a block does not match the hash it is cleared from the data bitfield.\n\n#### `feed.writable`\n\nCan we append to this feed?\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.readable`\n\nCan we read from this feed? After closing a feed this will be false.\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.key`\n\nBuffer containing the public key identifying this feed.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.discoveryKey`\n\nBuffer containing a key derived from the feed.key.\nIn contrast to `feed.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same feed, without leaking the feed key.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.length`\n\nHow many blocks of data are available on this feed?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.byteLength`\n\nHow much data is available on this feed in bytes?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.stats`\n\nReturn per-peer and total upload/download counts.\n\nThe returned object is of the form:\n```js\n{\n  totals: {\n    uploadedBytes: 100,\n    uploadedBlocks: 1,\n    downloadedBytes: 0,\n    downloadedBlocks: 0\n  },\n  peers: [\n    {\n      uploadedBytes: 100,\n      uploadedBlocks: 1,\n      downloadedBytes: 0,\n      downloadedBlocks: 0\n    },\n    ...\n  ]\n}\n```\n\nStats will be collected by default, but this can be disabled by setting `opts.stats` to false.\n\n#### `feed.on('ready')`\n\nEmitted when the feed is ready and all properties have been populated.\n\n#### `feed.on('error', err)`\n\nEmitted when the feed experiences a critical error.\n\n#### `feed.on('download', index, data)`\n\nEmitted when a data block has been downloaded.\n\n#### `feed.on('upload', index, data)`\n\nEmitted when a data block is uploaded.\n\n#### `feed.on('append')`\n\nEmitted when the feed has been appended to (i.e. has a new length / byteLength)\n\n#### `feed.on('sync')`\n\nEmitted every time ALL data from `0` to `feed.length` has been downloaded.\n\n#### `feed.on('close')`\n\nEmitted when the feed has been fully closed\n\n---\n\n[Dat Project]: https://dat.foundation\n","readmeFilename":"README.md","_id":"dat-sdk@2.0.0-3","_nodeVersion":"11.15.0","_npmVersion":"6.13.7","dist":{"integrity":"sha512-WALjV866LFrsb7g70L9OjUQHyrR5vSNaEQ1n/UjaWr0/21zpumndFndJHX1QdT1MKCYTpV3CBsM9Ms0XJZ07vw==","shasum":"44461434a8c2ff53f794e42406cc5c322b901e06","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.0.0-3.tgz","fileCount":14,"unpackedSize":64538,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeTL6jCRA9TVsSAnZWagAAYjQQAItpOsSVJOfT8WbRomsI\nRWmFSL9DZ9qFnXs2SHB/FKJgZWAaiHsOYWL83ZUULHb/eS9O2DkCVr40PNzp\nQfAx0KdV+AxXzSpGw7oUEpFa7es6nLiYnTbrlW1uzdtBxqF5NlceemDXBeoe\nQDtTfOl0GSi3akbSq2u+fmWGwceiltt04F54z6SUPpHiHPBN+wGmqD1tuO0T\no5CENV9Qxd/awDmoL1Zc9NhY67S+Ue11Kivn9rBISGl1CuR5MS0j08NEwpIO\nLMNkuDLKdwG3WsRzVWw2MZL+srVfEWSBnO+5vKGsVU7jYFwVyhLl22Bo4Pwv\nyGkbwV1XrzHPBgu8d5p4YrVeV3Bso7oKl9EKiYFcWC5dwhbXoaYRmj3ylIp4\nm+zy56l/bzIMYTYrC+tldhhiIPzTNHr1YEa2qwvlVlc6zzcq/4srcUdZ4r86\nVUywwNEAP9EDhy5rncCHK6PcBuI0yTSz+ugNTZNdXNb2Wez2Lu9bCLAJHqaY\nAMDI2Qf5n3rAJtR9HwUwr9x0atZvaPyzbNmju+tFwCjIc8xGpRfn3iwmR192\nFbTxaO55p/M+Ad/6CjsdJ4zLCYgAuBxQI6VTkCKQ7CbbHaEY56+vDDtyecFN\n5ayxWwnSwEiGApdI+FYLuRwtjXwia8+Xqm7vLYbw68Dq/bULssFMFAh+dnAY\nGCHw\r\n=su3g\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDncb+3rdmmsSW5KpqK+zBWDkJ5/cXIiiAsuZGf0pmspQIgRa+uUSGYindXGx9QF71R5Me8jh+uOAlGH8vcvFph3FY="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.0.0-3_1582087843027_0.602471108812574"},"_hasShrinkwrap":false},"1.0.3":{"name":"dat-sdk","version":"1.0.3","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test && node test-promise","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","./localstorage":"./localstorage-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"concat-stream":"^2.0.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^7.5.0","hypercore-crypto":"^1.0.0","hyperdiscovery":"^10.2.0","hyperdrive":"github:mafintosh/hyperdrive#v9","node-dat-archive":"^2.2.0","node-localstorage":"^2.1.5","pauls-dat-api":"^8.1.0","random-access-memory":"^3.1.1","universal-dat-storage":"^1.3.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"2c7b988c476d78c33ef792a48b2c0d6f3f37075e","_id":"dat-sdk@1.0.3","_nodeVersion":"11.15.0","_npmVersion":"6.13.7","dist":{"integrity":"sha512-dPlO1ThKlS+BIh+eLR60kUA6TD0G/jGngcvcPtXorLeAo+5EGNKRH9bBYt2ZJ5lzKK0FhXB0GVHE70QhkFLG1A==","shasum":"9cf18d94c06e7987271ef71b4d1dc34e661c4d17","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-1.0.3.tgz","fileCount":15,"unpackedSize":78959,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeVEtdCRA9TVsSAnZWagAAg0oQAJAjnM6yKzQLjn02JGOH\ncvufMmuYKEiaLCjC7oCwiQyVCijPa7kNEzx6v1/jkSlvbgHSLlog8Y5XLCDz\n+vkohPcLeK+1l6FuaE1PraWi22Yrbesfh2HyuTcxdzSoKZ3s9vxokvQXQMxf\nGhynOnZALiIJh9qLsu9R/1xeg4LHKT5yz09gDF5Hk9+VGO/bqG3XWszCJL/j\n3EYIgawvD6N+T2q4xhgLUePojGKxdQpJYGcVuNKAtfQE/9Jbt/BhBg323yVn\n6vlLOM/tazZ7kgzaqzQXQyxGgzdN3WzQoD9x69xuyWJpYCznh1Khhx8cfHK/\nhfOwmBrtXQN8r3278rO3lQQ5skG0ObBO+YeNThpYmcyYup/8vyV9JSjjYNcl\nBsJHR2BE2NedTz7dvZ7A3a3t17W8bNvy9XJSusl7nsDucSR2H7JvyE751+5L\nmTCm+8Cxv/nUge8OmAlD92ytidRs96SqDLRVw9pFAQW6bW//BiRdvJGDUNzE\nq9HrpU/eQJaE8qafH7oWHe+i4kERRAcF9VVQdmwapWZomKX9tNFVxHM09L02\nDPDEgjN0YVA9ubmIhco7rOROFwR/A2inT5yLZG9hMbtT0FIggttQPnHde+bB\nMLsGw2ZAuBhA7SPEtgfXWniffzaikwxUh1Hk+a0XqTeLJUn5QrgTW6/4+XqK\nPPpm\r\n=SCbH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBlDsLbd9XA0/J3YTBGdh7RO5RaX2yw305mYR+RQR3mmAiBeQStv4dLZIsDA4gLazW60crmXu8aQatCZvFDWKU0bcw=="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_1.0.3_1582582620305_0.9827140356852009"},"_hasShrinkwrap":false},"2.0.0-4":{"name":"dat-sdk","version":"2.0.0-4","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build-test":"browserify -d test.js > test-bundle.js","build-test-promise":"browserify -d test-promise.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","./localstorage":"./localstorage-web.js"},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^1.1.0","@geut/hyperdrive-promise":"^3.0.0","concat-stream":"^2.0.0","corestore":"^5.0.9","corestore-swarm-networking":"^5.0.2","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^8.11.0","hypercore-crypto":"^1.0.0","hypercore-protocol":"^7.10.0","hyperdrive":"^10.8.17","hyperswarm-web":"^1.0.1","node-localstorage":"^2.1.5","random-access-application":"^1.0.0","random-access-memory":"^3.1.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"browserify":"^16.2.3","hypertrie":"^3.7.1","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0"},"gitHead":"60ce00568448a949f396e8806d1fcb8b7acec5e9","readme":"# sdk\nThe official Dat SDK\n\n[<img src=\"https://datproject.github.io/design/downloads/dat-logo.png\" align=\"right\" width=\"140\">][Dat Project]\n\n## Why use this?\n\nDat consists of a bunch of low level building blocks for working with data in distributed applications. Although this modularity makes it easy to mix and match pieces, it adds complexity when it comes to actually building something.\n\nThe Dat SDK combines the lower level pieces of the Dat ecosystem into high level APIs that you can use across platforms so that you can focus on your application rather than the gritty details of how it works.\n\n## Goals\n\n- High level API\n- Cross-platform with same codebase\n  - ✔ Node\n  - ✔ Web (non-beaker)\n  - ✔ Beaker (Promise API acts as polyfill for Beaker)\n  - React-Native?\n  - Electron?\n\n\n## Installing\n\n[Node.js](https://nodejs.org/) / [Browserify](http://browserify.org/) workflows:\n\n```shell\nnpm install --save dat-sdk\n```\n\n```js\nconst SDK = require('dat-sdk')\nconst SDKPromise = require('dat-sdk/promise')\nconst {DatArchive} = require('dat-sdk/auto')\n```\n\nOr Web Browsers\n\n```html\n<script src=\"https://bundle.run/dat-sdk@1\"></script>\n<script src=\"https://bundle.run/dat-sdk@1/promise.js\"></script>\n<script src=\"https://bundle.run/dat-sdk@1/auto.js\"></script>\n<script>\n  const SDK = window.datSDK\n  // Look at the examples from here\n</script>\n```\n\n## Examples (browserify)\n\nYou can bundle your code with [browserify](http://browserify.org/) using the following command:\n\n```\nbrowserify index.js > bundle.js\n```\n\nThen you can include `bundle.js` in your HTML page.\n\n## Examples (webpack.config.js)\n\nTo bundle with webpack instead of browserify, resolve the `fs` module with the `graceful-fs` module.\n\n```js\nconst path = require('path')\n\nmodule.exports = {\n  entry: './index.js',\n  target: 'web',\n  resolve: {\n    alias: {\n      fs: 'graceful-fs'\n    }\n  },\n  output: {\n    filename: 'bundle.js',\n    path: path.resolve(__dirname, 'dist')\n  }\n}\n```\n\nThen you can include `./dist/bundle.js` in your HTML page.\n\n## Examples (Promise)\n\n```js\n// Auto-detects sane defaults based on your environment\n// Uses Beaker's APIs if they are if they are available\n// DatArchive is the same as Beaker\n// https://beakerbrowser.com/docs/apis/dat\nconst {DatArchive} = require('dat-sdk/auto')\n\nconst archive = await DatArchive.load('dat://dat.foundation')\n\nconst someData = await archive.readFile('/dat.json', 'utf8')\n\nconsole.log('Dat foundation dat.json:', someData)\n\nconst myArchive = await DatArchive.create({\n  title: 'My Archive'\n})\n\nawait myArchive.writeFile('/example.txt', 'Hello World!')\n\n// Log the secret key in case you want to save it for later\nconsole.log(await myArchive.getSecretKey())\n\n// Use a saved secret key\nawait DatArchive.load(someKey, {\n  secretKey: someSecretKey\n})\n```\n\n## API/Examples (Callbacks)\n\n```js\nconst SDK = require('dat-sdk')\nconst { Hypercore, Hyperdrive, resolveName, deleteStorage, destroy } = SDK()\n\nconst archive = Hyperdrive(null, {\n  // This archive will disappear after the process exits\n  // This is here so that running the example doesn't clog up your history\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  //storage: RAI\n})\n\narchive.ready(() => {\n  const url = `dat://${archive.key.toString('hex')}`\n\n  // TODO: Save this for later!\n  console.log(`Here's your URL: ${url}`)\n\n  // Check out the hyperdrive docs for what you can do with it\n  // https://www.npmjs.com/package/hyperdrive#api\n  archive.writeFile('/example.txt', 'Hello World!', () => {\n    console.log('Written example file!')\n  })\n})\n\nresolveName('dat://beakerbrowser.com', (err, url) => {\n  if (err) throw err\n  const archive = Hyperdrive(url)\n\n  archive.readFile('/dat.json', 'utf8', (err, data) => {\n    if (err) throw err\n    console.log(`Beaker's dat.json is ${data}`)\n\n    archive.close((err) => {\n      if (err) throw err\n      deleteStorage(archive.key, (e) => {\n        if (e) throw e\n        console.log('Deleted beaker storage')\n      })\n    })\n  })\n})\n\nconst SOME_URL = 'dat://0a9e202b8055721bd2bc93b3c9bbc03efdbda9cfee91f01a123fdeaadeba303e/'\n\nconst someArchive = Hyperdrive(SOME_URL)\n\nreallyReady(someArchive, () => {\n  someArchive.readdir('/', console.log)\n})\n\n// This make sure you sync up with peers before trying to do anything with the archive\nfunction reallyReady (archive, cb) {\n  if (archive.metadata.peers.length) {\n    archive.metadata.update({ ifAvailable: true }, cb)\n  } else {\n    archive.metadata.once('peer-add', () => {\n      archive.metadata.update({ ifAvailable: true }, cb)\n    })\n  }\n}\n\n// Create a hypercore\n// Check out the hypercore docs for what you can do with it\n// https://github.com/mafintosh/hypercore\nconst myCore = Hypercore(null, {\n  valueEncoding: 'json',\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  // storage: RAI\n})\n\n// Add some data to it\nmyCore.append(JSON.stringify({\n  name: 'Alice'\n}), () => {\n  // Use extension messages for sending extra data over the p2p connection\n  const discoveryCoreKey = 'dat://bee80ff3a4ee5e727dc44197cb9d25bf8f19d50b0f3ad2984cfe5b7d14e75de7'\n  const discoveryCore = new Hypercore(discoveryCoreKey, {\n    extensions: ['discovery']\n  })\n\n  // When you find a new peer, tell them about your core\n  discoveryCore.on('peer-add', (peer) => {\n    console.log('Got a peer!')\n    peer.extension('discovery', myCore.key)\n  })\n\n  // When a peer tells you about their core, load it\n  discoveryCore.on('extension', (type, message) => {\n    console.log('Got extension message', type, message)\n    if (type !== 'discovery') return\n    discoveryCore.close()\n\n    const otherCore = new Hypercore(message, {\n      valueEncoding: 'json',\n      persist: false\n    })\n\n    // Render the peer's data from their core\n    otherCore.get(0, console.log)\n  })\n})\n\nconst hypertrie = require('hypertrie')\n\n// Pass in hypercores from the SDK into other dat data structures\n// Check out what you can do with hypertrie from there:\n// https://github.com/mafintosh/hypertrie\nconst trie = hypertrie(null, {\n  feed: new Hypercore(null, {\n    persist: false\n  })\n})\n\ntrie.put('key', 'value', () => {\n  trie.get('key', (err, node) => {\n    console.log('Got key: ', node.key)\n    console.log('Loaded value from trie: ', node.value)\n  })\n})\n\n```\n\n## API (Promise)\n\n### `const {DatArchive, destroy} = SDK({ storageOpts, swarmOpts, driveOpts, coreOpts, dnsOpts })`\n\nThis initializes the Dat SDK.\n\n\n- `storageOpts`: This lets you configure how the SDK will store data. Used by the [universal-dat-storage](https://github.com/RangerMauve/universal-dat-storage) module.\n  - `application: 'dat'`: The name of the application using the SDK if you want to have the data stored separately. Used by [env-paths](https://github.com/sindresorhus/env-paths#pathsdata) to generate the storageLocation\n  - `storageLocation: null`: A location (on disk) to store the archives in.\n- `swarmOpts`: This lets you configure [discovery-swarm](https://www.npmjs.com/package/discovery-swarm) and [discovery-swarm-web](https://www.npmjs.com/package/discovery-swarm-web)\n  - `id`: The ID to use when doing p2p traffic\n  - `maxConnections`: The maximum number of connections to keep for this swarm.\n  - `extensions: []`: The set of extension messages to use when replicating with peers\n  - `utp: true`: Whether to use utp in discovery-swarm\n  - `tcp: true`: Whether to use tcp in discovery-swarm\n  - `bootstrap: ['signal.mauve.moe']`: The WebRTC bootstrap server list used by discovery-swarm-web\n  - `discovery: 'discoveryswarm.mauve.moe'`: The proxy server used by discovery-swarm-web\n- `driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n- `coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `await destroy()`\n\nRelease all resources being used by the SDK so you can safely stop your process.\n\n### `const archive = await DatArchive.load(location, opts)`\n\nThis loads up a Dat Archive for the given URL / Key / File path.\n\n- `location`: This is either the `dat://` URL (which might have a domain), a dat key, or a file path for your archive.\n- `opts`: These are options for configuring this archive\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n\n### `const archive = await DatArchive.create(opts)`\n\nThis creates a new Dat Archive.\n\n- `opts` These are the options for the archive's metadata and it's properties\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n  - `title`: The title of the archive\n  - `description`: A brief description of what the archive contains\n  - `type`: An array of strings for the type of archive this is. See the [manifest](https://beakerbrowser.com/docs/apis/manifest.html#type) docs for more info.\n\n### `const archive = await DatArchive.fork(url, opts)`\n\nCreate a new archive based on the data within another archive\n\n- `url` The URL of the archive to fork off of\n- `opts` These options will be used in the new archive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretkey`: The secret key to use for this archive to get write access\n  - `title`: The title of the archive\n  - `description`: A brief description of what the archive contains\n  - `type`: An array of strings for the type of archive this is. See the [manifest](https://beakerbrowser.com/docs/apis/manifest.html#type) docs for more info.\n\n### `await DatArchive.unlink(url)`\n\nDelete the storage for an archive.\n\n- `url`: The URL of the archive to delete\n\n### `const archive = await DatArchive.selectArchive()`\n\nPrompt the user to select an archive from the ones they have created locally. The implementation is super hacky, so use with caution.\n\n### `const url = await DatArchive.resolveName(url)`\n\nResolve a URL that uses dat-dns to the raw `dat://` url.\n\n- `url`: The `dat://` URL with a domain to resolve\n\n#### `const url = archive.url`\n\nGet the URL for the given archive.\n\n#### `const info = await archive.getInfo()`\n\nGet metadata about the archive\n\n- `info`: The metadata related to the archive.\n  - `key`: string (the archive public key)\n  - `url`: string (the archive URL)\n  - `isOwner`: boolean (is the user the owner of this archive?)\n  - `version`: number (the archive's current revision number)\n  - `peers`: number (the number of active connections for the archive)\n  - `mtime`: number (the walltime of the last received update; is reliable)\n  - `size`: number (bytes, the size-on-disk of the archive)\n  - `title`: string (the archive title)\n  - `description`: string (the archive description)\n  - `type`: array of strings (the archive's type identifiers)\n  - `links`: object (top-level links to other resources)\n\n#### `await archive.configure(configuration)`\n\nUpdate the metadata about the archive.\n\n- `configuration`: The metadata to update\n  - `title` String. The title of the archive.\n  - `description` String. The description of the archive.\n  - `type` Array<String>. The archive’s type identifiers. Learn more.\n  - `links` Object. Top-level links to other resources. Learn more.\n  - `web_root` String. Path of the folder from which all web requests should be served.\n  - `fallback_page` String. Path to a fallback page to serve instead of the default 404 page.\n\n#### `const stat = await archive.stat(path)`\n\n- `path`: The path to get stats about from the archive\n- `stat.isDirectory()`: Check if the path is a directory\n- `stat.isFile()`: Check if the path is a file\n- `stat.size`: number (bytes)\n- `stat.blocks`: number (number of data blocks in the metadata)\n- `stat.downloaded`: number (number of blocks downloaded, if a remote archive)\n- `stat.mtime`: Date (last modified time; not reliable)\n- `stat.ctime`: Date (creation time; not reliable)`\n\n#### `const data = await archive.readFile(path, opts)`\n\n- `path` The path to the file you wish to read\n- `opts.encoding`: The encoding to read the file with, can be one of `utf8`, `base64`, `hex`, and `binary`\n- `data`: The entire contents of the file, either as a string, or an ArrayBuffer if you used the `binary` encoding.\n\n#### `const list = await archive.readdir(path, opts)`\n\nLists the files and folders within a directory.\n\n- `path`: The path to the directory you wish to read\n- `opts`\n  - `recursive`: Set to `true` to list subdirectories, too\n  - `stat`: Get the `Stat` objects instead of names.\n- `list`: Either a list of the file/folder names or a list of the Stat object for those items.\n\n#### `await archive.writeFile(path, data, opts)`\n\nWrite a file to your archive.\n\n- `path`: The location to write your file to.\n- `data`: Either a string or ArrayBuffer for the data you wish to save\n- `opts.encoding`: The encoding to use when writing. Must be one of `utf8`, `base64`, `hex`, or `binary`. Encoding will default to `utf8` for strings, and `binary` for ArrayBuffers.\n\n#### `await archive.mkdir(path)`\n\nCreate a directory at the given path. Will fail if the parent directory doesn't exist.\n\n- `path`: The path to the directory\n\n#### `await archive.unlink(path)`\n\nDelete the file at the given path.\n\n- `path`: The path to the file\n\n#### `await rmdir(path, opts)`\n\nDeletes the directory at the given path.\n\n- `path`: The path to the directory\n- `opts.recursive`: Whether to delete subfolders / files.\n\n#### `await archive.copy(path, dstPath)`\n\nCopy a file from one location to another.\n\n- `path`: The path to the file / directory to copy from.\n- `dstPath`: The location the file/directory should be copied to\n\n#### `await archive.rename(oldPath, newPath)`\n\nRename / move a file or directory.\n\n- `oldPath`: The path of the file/directory to rename\n- `newPath`: What the file/directory should be renamed to.\n\n#### `const history = await archive.history({opts})`\n\nList the history of all the changes in this archive.\n\n- `opts`: The options for how to fetch the history of the archive\n  - `start`: Where in the history to start reading\n  - `end`: Where in the history to stop reading\n  - `reverse`: Set to `true` to iterate through the history backwards\n- `history`: An array of history items representing changes\n  - `path`: Which file / directory got modified.\n  - `version`: The version number the archive was at for this item\n  - `type`: Either `put` for additions or `del` for deletions\n\n#### `const olderArchive = archive.checkout(version)`\n\nGet a view of the archive as it was at an earlier version.\n\n- `version`: The integer representing the version you whish to look at. This correlates to the version in the history.\n\n#### `await archive.download(path)`\n\nDownload the file or folder at the given path from the network. Use `/` to download the entire archive.\n\n#### `const events = archive.watch(pattern, onInvalidated)`\n\n```js\nconst events = archive.watch(['**/*.md'])\nevents.addEventListener('changed', ({path}) => console.log(path, 'changed!'))\n\nevents.close() // Stop listening for changes\n```\n\nWatch for changes in the archive.\n\n- `pattern`: This can either be omitted to view all changes, or have an [anymatch](https://www.npmjs.com/package/anymatch) pattern to filter out just the changes you want.\n- `onInvalidated`: You can optionally pass in this function to listen for changes instead of using an event listener.\n\n#### `archive.addEventListener('network-changed', ({peers}) => void 0)`\n\nListen for changes in the number of peers connected to for the archive.\n\n- `peers`: The number of connected peers\n\n#### `archive.addEventListener('download', ({feed, block, bytes}) => void 0)`\n\nListen for download progress from the archive\n\n- `feed`: The data feed the block was part of. Either `metadata` or `content`\n- `block`: The index of the block downloaded\n- `bytes`: The size of the block in bytes\n\n#### `archive.addEventListener('upload', ({feed, block, bytes}) => void 0)`\n\nListen for upload progress from the archive.\n\n- `feed`: The data feed the block was part of. Either `metadata` or `content`\n- `block`: The index of the block uploaded\n- `bytes`: The size of the block in bytes\n\n#### `archive.addEventListener('sync', ({feed}) => void 0)`\n\nEmitted when all known data has been downloaded\n\n## API (Callbacks)\n\n### `const {Hypercore, Hyperdrive, resolveName, deleteStorage, destroy} = SDK({ storageOpts, swarmOpts, driveOpts, coreOpts, dnsOpts })`\n\nCreates an instance of the Dat SDK based on the options.\n\n- `storageOpts`: This lets you configure how the SDK will store data. Used by the [universal-dat-storage](https://github.com/RangerMauve/universal-dat-storage) module.\n  - `application: 'dat'`: The name of the application using the SDK if you want to have the data stored separately. Used by [env-paths](https://github.com/sindresorhus/env-paths#pathsdata) to generate the storageLocation\n  - `storageLocation: null`: A location (on disk) to store the archives in.\n- `swarmOpts`: This lets you configure [discovery-swarm](https://www.npmjs.com/package/discovery-swarm) and [discovery-swarm-web](https://www.npmjs.com/package/discovery-swarm-web)\n  - `id`: The ID to use when doing p2p traffic\n  - `maxConnections`: The maximum number of connections to keep for this swarm.\n  - `extensions: []`: The set of extension messages to use when replicating with peers\n  - `utp: true`: Whether to use utp in discovery-swarm\n  - `tcp: true`: Whether to use tcp in discovery-swarm\n  - `bootstrap: ['signal.mauve.moe']`: The WebRTC bootstrap server list used by discovery-swarm-web\n  - `discovery: 'discoveryswarm.mauve.moe'`: The proxy server used by discovery-swarm-web\n- `driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n- `coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `destroy(cb)`\n\nThis closes all resources used by the SDK so you can safely end your process. `cb` will be invoked once resources are closed or if there's an error.\n\n### `resolveName(url, cb(err, key))`\n\nResolve a DNS name to a Dat key.\n\n  - `url` is a Dat URL like `dat://dat.foundation`\n  - `cb` will get invoked with the result of the resolve\n  - `key` will be the Dat key that you can pass to `hyperdrive`\n  - `err` will be any errors that happen during resolution\n\n### `deleteStorage(key, cb)`\n\nDelete the storage for a given archive or hypercore key.\n\n- `key` should be the key for the hypercore or hyperdrive that should be deleted\n- `cb` will be invoked after the deletion is over.\n\n### `const archive = Hyperdrive(location, opts)`\n\nThis initializes a Hyperdrive (aka a Dat archive), the SDK will begin finding peers for it and will de-duplicate calls to initializing the same archive more than once.\n\n- `location`: This **must** be provided. It's either a path for where the archive should be stored, or a Dat URL / key. If this is null, a new key will be generated.\n- `opts`: These are the options for configuring the hyperdrive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `extensions`: The set of extension message types to use with this archive when replicating.\n  - `secretKey`: A secret key for granting write access. This can be useful when restoring backups.\n\nThe rest of the Hyperdrive docs were taken from the [Hyperdrive README](https://github.com/mafintosh/hyperdrive/blob/v9/README.md)\n\n#### `archive.version`\n\nGet the current version of the archive (incrementing number).\n\n#### `archive.key`\n\nThe public key identifying the archive.\n\n#### `archive.discoveryKey`\n\nA key derived from the public key that can be used to discovery other peers sharing this archive.\n\n#### `archive.writable`\n\nA boolean indicating whether the archive is writable.\n\n#### `archive.on('ready')`\n\nEmitted when the archive is fully ready and all properties has been populated.\n\n#### `archive.on('update')`\n\nEmitted when the archive has got a new change.\n\n#### `archive.on('error', err)`\n\nEmitted when a critical error during load happened.\n\n#### `archive.on('close')`\n\nEmitted when the archive has been closed\n\n#### `archive.on('extension', name, message, peer)`\n\nEmitted when a peer sends you an extension message with `archive.extension()`.\nYou can respond with `peer.extension(name, message)`.\n\n#### `var oldDrive = archive.checkout(version, [opts])`\n\nCheckout a readonly copy of the archive at an old version. Options are used to configure the `oldDrive`:\n\n```js\n{\n  metadataStorageCacheSize: 65536 // how many entries to use in the metadata hypercore's LRU cache\n  contentStorageCacheSize: 65536 // how many entries to use in the content hypercore's LRU cache\n  treeCacheSize: 65536 // how many entries to use in the append-tree's LRU cache\n}\n```\n\n#### `archive.download([path], [callback])`\n\nDownload all files in path of current version.\nIf no path is specified this will download all files.\n\nYou can use this with `.checkout(version)` to download a specific version of the archive.\n\n``` js\narchive.checkout(version).download()\n```\n\n#### `var stream = archive.history([options])`\n\nGet a stream of all changes and their versions from this archive.\n\n#### `archive.extension(name, message)`\n\nSend an extension message to connected peers. [Read more in the hypercore docs](https://github.com/mafintosh/hypercore#feedextensionname-message).\n\n#### `var stream = archive.createReadStream(name, [options])`\n\nRead a file out as a stream. Similar to fs.createReadStream.\n\nOptions include:\n\n``` js\n{\n  start: optionalByteOffset, // similar to fs\n  end: optionalInclusiveByteEndOffset, // similar to fs\n  length: optionalByteLength\n}\n```\n\n#### `archive.readFile(name, [options], callback)`\n\nRead an entire file into memory. Similar to fs.readFile.\n\nOptions can either be an object or a string\n\nOptions include:\n```js\n{\n  encoding: string\n  cached: true|false // default: false\n}\n```\nor a string can be passed as options to simply set the encoding - similar to fs.\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `var stream = archive.createDiffStream(version, [options])`\n\nDiff this archive with another version. `version` can both be a version number of a checkout instance of the archive. The `data` objects looks like this\n\n``` js\n{\n  type: 'put' | 'del',\n  name: '/some/path/name.txt',\n  value: {\n    // the stat object\n  }\n}\n```\n\n#### `var stream = archive.createWriteStream(name, [options])`\n\nWrite a file as a stream. Similar to fs.createWriteStream.\nIf `options.cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `archive.writeFile(name, buffer, [options], [callback])`\n\nWrite a file from a single buffer. Similar to fs.writeFile.\n\n#### `archive.unlink(name, [callback])`\n\nUnlinks (deletes) a file. Similar to fs.unlink.\n\n#### `archive.mkdir(name, [options], [callback])`\n\nExplictly create an directory. Similar to fs.mkdir\n\n#### `archive.rmdir(name, [callback])`\n\nDelete an empty directory. Similar to fs.rmdir.\n\n#### `archive.readdir(name, [options], [callback])`\n\nLists a directory. Similar to fs.readdir.\n\nOptions include:\n\n``` js\n{\n    cached: true|false, // default: false\n}\n```\n\nIf `cached` is set to `true`, this function returns results from the local version of the archive’s append-tree. Default behavior is to fetch the latest remote version of the archive before returning list of directories.\n\n#### `archive.stat(name, [options], callback)`\n\nStat an entry. Similar to fs.stat. Sample output:\n\n```\nStat {\n  dev: 0,\n  nlink: 1,\n  rdev: 0,\n  blksize: 0,\n  ino: 0,\n  mode: 16877,\n  uid: 0,\n  gid: 0,\n  size: 0,\n  offset: 0,\n  blocks: 0,\n  atime: 2017-04-10T18:59:00.147Z,\n  mtime: 2017-04-10T18:59:00.147Z,\n  ctime: 2017-04-10T18:59:00.147Z,\n  linkname: undefined }\n```\n\nThe output object includes methods similar to fs.stat:\n\n``` js\nvar stat = archive.stat('/hello.txt')\nstat.isDirectory()\nstat.isFile()\n```\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.lstat(name, [options], callback)`\n\nStat an entry but do not follow symlinks. Similar to fs.lstat.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.access(name, [options], callback)`\n\nSimilar to fs.access.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `archive.open(name, flags, [mode], callback)`\n\nOpen a file and get a file descriptor back. Similar to fs.open.\n\nNote that currently only read mode is supported in this API.\n\n#### `archive.read(fd, buf, offset, len, position, callback)`\n\nRead from a file descriptor into a buffer. Similar to fs.read.\n\n#### `archive.close(fd, [callback])`\n\nClose a file. Similar to fs.close.\n\n#### `archive.close([callback])`\n\nCloses all open resources used by the archive.\nThe archive should no longer be used after calling this.\n\n### `const feed = Hypercore(key, opts)`\n\nInitializes a Hypercore (aka Feed) and begins replicating it.\n\n- `key`: This is the dat key for the feed, you can omit it if you want to create a new hypercore instance\n- `opts`: The options for configuring this feed\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n  - `secretKey`: The secret key to use for the feed. Useful for restoring from backups.\n\n#### `feed.append(data, [callback])`\n\nAppend a block of data to the feed.\n\nCallback is called with `(err, seq)` when all data has been written at the returned `seq` or an error occurred.\n\n#### `feed.get(index, [options], callback)`\n\nGet a block of data.\nIf the data is not available locally this method will prioritize and wait for the data to be downloaded before calling the callback.\n\nOptions include\n\n``` js\n{\n  wait: true, // wait for index to be downloaded\n  timeout: 0, // wait at max some milliseconds (0 means no timeout)\n  valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the feed's valueEncoding\n}\n```\n\nCallback is called with `(err, data)`\n\n#### `feed.getBatch(start, end, [options], callback)`\n\nGet a range of blocks efficiently. Options include\n\n``` js\n{\n  wait: sameAsAbove,\n  timeout: sameAsAbove,\n  valueEncoding: sameAsAbove\n}\n```\n\n#### `feed.head([options], callback)`\n\nGet the block of data at the tip of the feed. This will be the most recently\nappended block.\n\nAccepts the same `options` as `feed.get()`.\n\n#### `feed.download([range], [callback])`\n\nDownload a range of data. Callback is called when all data has been downloaded.\nA range can have the following properties:\n\n``` js\n{\n  start: startIndex,\n  end: nonInclusiveEndIndex,\n  linear: false // download range linearly and not randomly\n}\n```\n\nIf you do not mark a range the entire feed will be marked for download.\n\nIf you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire\nfeed will be marked for download for you when the feed is created.\n\n#### `feed.undownload(range)`\n\nCancel a previous download request.\n\n#### `feed.signature([index], callback)`\n\nGet a signature proving the correctness of the block at index, or the whole stream.\n\nCallback is called with `(err, signature)`.\nThe signature has the following properties:\n``` js\n{\n  index: lastSignedBlock,\n  signature: Buffer\n}\n```\n\n#### `feed.verify(index, signature, callback)`\n\nVerify a signature is correct for the data up to index, which must be the last signed\nblock associated with the signature.\n\nCallback is called with `(err, success)` where success is true only if the signature is\ncorrect.\n\n#### `feed.rootHashes(index, callback)`\n\nRetrieve the root *hashes* for given `index`.\n\nCallback is called with `(err, roots)`; `roots` is an *Array* of *Node* objects:\n```\nNode {\n  index: location in the merkle tree of this root\n  size: total bytes in children of this root\n  hash: hash of the children of this root (32-byte buffer)\n}\n```\n\n\n#### `var number = feed.downloaded([start], [end])`\n\nReturns total number of downloaded blocks within range.\nIf `end` is not specified it will default to the total number of blocks.\nIf `start` is not specified it will default to 0.\n\n#### `var bool = feed.has(index)`\n\nReturn true if a data block is available locally.\nFalse otherwise.\n\n#### `var bool = feed.has(start, end)`\nReturn true if all data blocks within a range are available locally.\nFalse otherwise.\n\n#### `feed.clear(start, [end], [callback])`\n\nClear a range of data from the local cache.\nWill clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.\n\n`end` defaults to `start + 1`.\n\n#### `feed.seek(byteOffset, callback)`\n\nSeek to a byte offset.\n\nCalls the callback with `(err, index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is\nthe relative byte offset in the data block.\n\n#### `feed.update([minLength], [callback])`\n\nWait for the feed to contain at least `minLength` elements.\nIf you do not provide `minLength` it will be set to current length + 1.\n\nDoes not download any data from peers except for a proof of the new feed length.\n\n``` js\nconsole.log('length is', feed.length)\nfeed.update(function () {\n  console.log('length has increased', feed.length)\n})\n```\n\n#### `var stream = feed.createReadStream([options])`\n\nCreate a readable stream of data.\n\nOptions include:\n\n``` js\n{\n  start: 0, // read from this index\n  end: feed.length, // read until this index\n  snapshot: true, // if set to false it will update `end` to `feed.length` on every read\n  tail: false, // sets `start` to `feed.length`\n  live: false, // set to true to keep reading forever\n  timeout: 0, // timeout for each data event (0 means no timeout)\n  wait: true // wait for data to be downloaded\n}\n```\n\n#### `var stream = feed.createWriteStream()`\n\nCreate a writable stream.\n\n#### `feed.close([callback])`\n\nFully close this feed.\n\nCalls the callback with `(err)` when all storage has been closed.\n\n#### `feed.audit([callback])`\n\nAudit all data in the feed. Will check that all current data stored\nmatches the hashes in the merkle tree and clear the bitfield if not.\n\nWhen done a report is passed to the callback that looks like this:\n\n```js\n{\n  valid: 10, // how many data blocks matches the hashes\n  invalid: 0, // how many did not\n}\n```\n\nIf a block does not match the hash it is cleared from the data bitfield.\n\n#### `feed.writable`\n\nCan we append to this feed?\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.readable`\n\nCan we read from this feed? After closing a feed this will be false.\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.key`\n\nBuffer containing the public key identifying this feed.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.discoveryKey`\n\nBuffer containing a key derived from the feed.key.\nIn contrast to `feed.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same feed, without leaking the feed key.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.length`\n\nHow many blocks of data are available on this feed?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.byteLength`\n\nHow much data is available on this feed in bytes?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.stats`\n\nReturn per-peer and total upload/download counts.\n\nThe returned object is of the form:\n```js\n{\n  totals: {\n    uploadedBytes: 100,\n    uploadedBlocks: 1,\n    downloadedBytes: 0,\n    downloadedBlocks: 0\n  },\n  peers: [\n    {\n      uploadedBytes: 100,\n      uploadedBlocks: 1,\n      downloadedBytes: 0,\n      downloadedBlocks: 0\n    },\n    ...\n  ]\n}\n```\n\nStats will be collected by default, but this can be disabled by setting `opts.stats` to false.\n\n#### `feed.on('ready')`\n\nEmitted when the feed is ready and all properties have been populated.\n\n#### `feed.on('error', err)`\n\nEmitted when the feed experiences a critical error.\n\n#### `feed.on('download', index, data)`\n\nEmitted when a data block has been downloaded.\n\n#### `feed.on('upload', index, data)`\n\nEmitted when a data block is uploaded.\n\n#### `feed.on('append')`\n\nEmitted when the feed has been appended to (i.e. has a new length / byteLength)\n\n#### `feed.on('sync')`\n\nEmitted every time ALL data from `0` to `feed.length` has been downloaded.\n\n#### `feed.on('close')`\n\nEmitted when the feed has been fully closed\n\n---\n\n[Dat Project]: https://dat.foundation\n","readmeFilename":"README.md","_id":"dat-sdk@2.0.0-4","_nodeVersion":"11.15.0","_npmVersion":"6.13.7","dist":{"integrity":"sha512-aIbRlBV+cTLHqukT0MeSDFcZuJnG6g8DZemJMUuV4t1AHtKV77rOpLAyQdgJU3ZymO+MLkWmeeNGeFYI0md23A==","shasum":"38b755b660f166c29f576761627cfab4ab520066","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.0.0-4.tgz","fileCount":11,"unpackedSize":54905,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeZo2SCRA9TVsSAnZWagAAJRkP/RsTmieWK5BDf4fsjuta\nfDc1FY/3nxnNykBCdZrAnFXcdWyRPG0LHU1+kkWdkDgvlb/Bv/KIjFBJ1Jh6\nlb4yLsNLfk9d2sKUotdSmwMKwBKL8OoyG9bW3nvAj3kIpAmuaDXsojOCII3c\n7PB+KYzN5C7W05ljRWjzEu8KkPRIOfYyDVKDvSKj2qW7fbtqZle8YxSw63y7\n6W4aWTkRygY7a1Z5KiTRoyEJ7LnO/1jYNzgJbyRsV6RCwpA3+A/LWdvOwzsr\nGdENAGfiPwBbyS/yg1amc3cOePa1lswAi2l++DA01/qYAc95Y6+JLjmQ9jHT\nqUa5xRvoEWZnTo+4ZYZ/XluAqHzZVrMsQYYdTe4Ka2rPf8C3z3/7uwEmBUjo\nemSIdZ3pL9ViqqeCcFIkFtOIQ3yE+buf2yx6nV8ZR+tduXpa9wKCdbYGhgVf\nxf6ZoU0EOBqjugWzd2b0o6bQ6uwS1gPx8BaB+UTz9lM8xalidPCQfByJMtrr\njqc1DgBsbh1rtqvHsxIy3tEnGaxM43OOLobFNRdDRK5o/Ch5i55dEY7D+RO3\n/51L/t82M5hLWkcLidkGo1joOsuP38+nO6BmlwHkmT5jVLAgsqP28UfdLYxE\nWKP0H05htJisRm9N7s8Dk8W4yT927nTUVSypHDugMGBOr95fT18+dA+DtWnO\nojSE\r\n=QuS6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDpOFDGMjS6RslOht1FEzG5cxHF4TW23PVy3lWemmrtuwIhAPooWfBN4df1zixnwWD7JNTDcKwcd5WaViWtrpTonzCb"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.0.0-4_1583779217988_0.9337368625754898"},"_hasShrinkwrap":false},"2.0.0-5":{"name":"dat-sdk","version":"2.0.0-5","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^1.1.0","@geut/hyperdrive-promise":"^3.0.0","@geut/sodium-javascript-plus":"0.0.4","concat-stream":"^2.0.0","corestore":"^5.1.1","corestore-swarm-networking":"^5.1.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"github:rangermauve/hypercore#destroy-rename","hypercore-crypto":"^1.0.0","hypercore-protocol":"^7.10.0","hyperdrive":"github:rangermauve/hyperdrive#destroy","hyperswarm-web":"^1.0.2","node-localstorage":"^2.1.5","random-access-application":"^1.0.0","random-access-memory":"^3.1.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"b1bb60d33870d71d685d3de3d5db57b0c72d1e5e","readme":"# sdk\nThe official Dat SDK\n\n[<img src=\"https://datproject.github.io/design/downloads/dat-logo.png\" align=\"right\" width=\"140\">][Dat Project]\n\n## Why use this?\n\nDat consists of a bunch of low level building blocks for working with data in distributed applications. Although this modularity makes it easy to mix and match pieces, it adds complexity when it comes to actually building something.\n\nThe Dat SDK combines the lower level pieces of the Dat ecosystem into high level APIs that you can use across platforms so that you can focus on your application rather than the gritty details of how it works.\n\n## Goals\n\n- High level API\n- Cross-platform with same codebase\n  - ✔ Node\n  - ✔ Web\n  - ✔ Electron\n  - React-Native (with [nodejs-mobile-react-native?](https://github.com/janeasystems/nodejs-mobile-react-native))\n\n## Installing Node\n\n[Node.js](https://nodejs.org/) / [Browserify](http://browserify.org/) workflows:\n\n```shell\nnpm install --save dat-sdk@next\n```\n\n```js\nconst SDK = require('dat-sdk')\n```\n\n## Building a bundle for Browsers\n\n```shell\ngit clone git@github.com:datproject/sdk.git\n\ncd sdk\n\n# Compile the SDK into a single JS file\nnpm run build\n\n# Copy `dat-sdk-bundle.js` into your project\n```\n\n```html\n<script src=\"dat-sdk-bundle.js\"></script>\n<script>\n  const SDK = window.datSDK\n  // Look at the examples from here\n</script>\n```\n\n## Compile with Browserify\n\n```\nnpm install --save-dev browserify\nnpm install --save dat-sdk@next\n```\n\nAdd this as the `build` command in your package.json\n\n```shell\nbrowserify index.js > bundle.js\n```\n\nThen you can use `bundle.js` in your project.\n\n## Compile with Webpack (webpack.config.js)\n\nTo bundle with webpack, you'll need to alias some dependencies.\n\n```js\nconst path = require('path')\n\nmodule.exports = {\n  entry: './index.js',\n  target: 'web',\n  resolve: {\n    alias: {\n      fs: 'graceful-fs',\n      'sodium-native': '@geut/sodium-javascript-plus',\n      'sodium-universal': '@geut/sodium-javascript-plus',\n      hyperswarm: 'hyperswarm-web',\n      util: './node_modules/util/util.js'\n    }\n  },\n  output: {\n    filename: 'bundle.js',\n    path: path.resolve(__dirname, 'dist')\n  }\n}\n```\n\nThen you can include `./dist/bundle.js` in your HTML page.\n\n## API/Examples\n\n```js\nconst SDK = require('dat-sdk')\n\nconst sdk = await SDK();\nconst {\n\tHypercore,\n\tHyperdrive,\n\tresolveName,\n\tclose\n} = sdk\n\n// Create a new Hyperdrive.\n// If you want to create a new archive, pass in a name for it\n// This will be used to derive a secret key\n// Every time you open a drive with that name it'll derive the same key\n// This uses a master key that's generated once per device\n// That means the same name will yield a different key on a different machine\nconst archive = Hyperdrive('My archive name', {\n  // This archive will disappear after the process exits\n  // This is here so that running the example doesn't clog up your history\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  //storage: RAI\n})\n\narchive.ready(() => {\n  const url = `dat://${archive.key.toString('hex')}`\n\n  // TODO: Save this for later!\n  console.log(`Here's your URL: ${url}`)\n\n  // Check out the hyperdrive docs for what you can do with it\n  // https://www.npmjs.com/package/hyperdrive#api\n  archive.writeFile('/example.txt', 'Hello World!', () => {\n    console.log('Written example file!')\n  })\n})\n\n// This example is currently broken because Beaker's website isn't on Dat 2 yet\nresolveName('dat://beakerbrowser.com', (err, key) => {\n  if (err) throw err\n  const archive = Hyperdrive(key)\n\n  archive.readFile('/dat.json', 'utf8', (err, data) => {\n    if (err) throw err\n    console.log(`Beaker's dat.json is ${data}`)\n\n    archive.close((err) => {\n      if (err) throw err\n      deleteStorage(archive.key, (e) => {\n        if (e) throw e\n        console.log('Deleted beaker storage')\n      })\n    })\n  })\n})\n\nconst SOME_URL = 'dat://0a9e202b8055721bd2bc93b3c9bbc03efdbda9cfee91f01a123fdeaadeba303e/'\n\nconst someArchive = Hyperdrive(SOME_URL)\n\nsomeArchive.readdir('/', console.log)}\n\n// Create a hypercore\n// Check out the hypercore docs for what you can do with it\n// https://github.com/mafintosh/hypercore\nconst myCore = Hypercore('my hypercore name', {\n  valueEncoding: 'json',\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  // storage: RAI\n})\n\n// Add some data to it\nmyCore.append(JSON.stringify({\n  name: 'Alice'\n}), () => {\n  // Use extension messages for sending extra data over the p2p connection\n  const discoveryCoreKey = 'dat://bee80ff3a4ee5e727dc44197cb9d25bf8f19d50b0f3ad2984cfe5b7d14e75de7'\n  const discoveryCore = new Hypercore(discoveryCoreKey)\n\n\t// Register the extension message handler\n\tconst extension = discoveryCore.registerExtension('discovery', {\n\t\t// Set the encoding type for messages\n\t\tencoding: 'binary',\n\t\tonmessage: (message, peer) => {\n\t\t\t// Recieved messages will be automatically decoded\n\t\t\tconsole.log('Got key from peer!', message)\n\n\t\t\tconst otherCore = new Hypercore(message, {\n        valueEncoding: 'json',\n        persist: false\n      })\n\n      // Render the peer's data from their core\n      otherCore.get(0, console.log)\n\t\t}\n\t})\n\n\t// When you find a peer tell them about your core\n\tdiscoveryCore.on('peer-add', (peer) => {\n\t\tconsole.log('Got a peer!')\n\t\textension.send(myCore.key, peer)\n\t})\n})\n\nconst hypertrie = require('hypertrie')\n\n// Pass in hypercores from the SDK into other dat data structures\n// Check out what you can do with hypertrie from there:\n// https://github.com/mafintosh/hypertrie\nconst trie = hypertrie(null, {\n  feed: new Hypercore('my trie core', {\n    persist: false\n  })\n})\n\ntrie.put('key', 'value', () => {\n  trie.get('key', (err, node) => {\n    console.log('Got key: ', node.key)\n    console.log('Loaded value from trie: ', node.value)\n  })\n})\n\n```\n\n## API\n\nThe API supports both promises and callbacks. Everywhere where you see `await`, you can instead pass a node-style callback.\n\n### `const {Hypercore, Hyperdrive, resolveName, getIdentity, close} = await SDK(opts?)`\n\nCreates an instance of the Dat SDK based on the options.\n\n- `opts.storage`: An optional [random-access-storage](https://github.com/random-access-storage/random-access-storage) instance for storing data.\n- `opts.applicationName`: An optional name for the application using the SDK. This will automatically silo your data from other applications using the SDK and will store it in the appropriate place using [random-access-application](https://github.com/RangerMauve/random-access-application/)\n- `opts.corestore`: An optional [Corestore](https://github.com/andrewosh/corestore) instance for using as hypercore storage.\n- `opts.corestoreOpts`: Options to pass into Corestore when it's initialized.\n- `opts.swarmOpts`: This lets you configure [hyperswarm](https://github.com/hyperswarm/hyperswarm) and [hyperswarm-web](https://github.com/RangerMauve/hyperswarm-web)\n  - `maxPeers`: The maximum number of connections to keep for this swarm.\n  - `ephemeral **NODE**`: Set to `false` if this is going to be in a long running process on a server. \n  - `bootstap **NODE**`: An array of addresses to use for the DHT bootstraping\n  - `webrtcBootstrap: ['https://geut-webrtc-signal.herokuapp.com/'] **BROWSER**`: The WebRTC bootstrap server list used by [discovery-swarm-webrtc](https://github.com/geut/discovery-swarm-webrtc)\n  - `wsProxy: 'wss://hyperswarm.mauve.moe' **BROWSER**`: The Websocket proxy used for [hyperswarm-proxy-ws](https://github.com/RangerMauve/hyperswarm-proxy-ws)\n- `opts.driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n- `opts.coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `opts.dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `await close()`\n\nThis closes all resources used by the SDK so you can safely end your process. `cb` will be invoked once resources are closed or if there's an error.\n\n### `const key = await resolveName(url)`\n\nResolve a DNS name to a Dat key.\n\n  - `url` is a Dat URL like `dat://dat.foundation`\n  - `key` will be the Dat key that you can pass to `hyperdrive`\n\n### `const {publicKey, secretKey} = await getIdentity()`\n\nThis gives you the public / private keypair used for the Noise protocol encryption when connecting to peers.\nYou can use this to identify peers in the network using `peer.remotePublicKey`\n\n### `const archive = Hyperdrive(keyOrName, opts)`\n\nThis initializes a Hyperdrive (aka a Dat archive), the SDK will begin finding peers for it and will de-duplicate calls to initializing the same archive more than once.\n\n- `keyOrName`: This **must** be provided. It's either a Dat URL / key or a string identifying the name. If you want to have a writable archive, you can use the name to generate one and use the name later to get the same archive back without having to save the key somewhere.\n- `opts`: These are the options for configuring the hyperdrive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretKey`: A secret key for granting write access. This can be useful when restoring backups.\n\t- `discoveryKey`: Optionally specify which discovery key you'd like to use for finding peers for this archive.\n\t- `lookup: true`: Specify whether you wish to lookup peers for this archive.\n\t- `announce: true`: Specify whether you wish to advertise yourself as having the archive.\n\nThe rest of the Hyperdrive docs were taken from the [Hyperdrive README](https://github.com/mafintosh/hyperdrive/blob/v9/README.md). Note that we're wrapping over the APIs with [Hyperdrive-Promise](https://github.com/geut/hyperdrive-promise) so any callback methods can be `await`ed instead.\n\n#### `archive.version`\n\nGet the current version of the archive (incrementing number).\n\n#### `archive.key`\n\nThe public key identifying the archive.\n\n#### `archive.discoveryKey`\n\nA key derived from the public key that can be used to discovery other peers sharing this archive.\n\n#### `archive.writable`\n\nA boolean indicating whether the archive is writable.\n\n#### `archive.on('ready')`\n\nEmitted when the archive is fully ready and all properties has been populated.\n\n#### `archive.on('update')`\n\nEmitted when the archive has got a new change.\n\n#### `archive.on('error', err)`\n\nEmitted when a critical error during load happened.\n\n#### `archive.on('close')`\n\nEmitted when the archive has been closed\n\n### `archive.on('peer-add', peer)`\n\nEmitted when a new peer has started replicating wiht the archive.\n\n### `archive.on('peer-remove', peer)`\n\nEmitted when a peer has stopped replicating wit the archive.\n\n#### `var oldDrive = archive.checkout(version, [opts])`\n\nCheckout a readonly copy of the archive at an old version. Options are used to configure the `oldDrive`:\n\n```js\n{\n  metadataStorageCacheSize: 65536 // how many entries to use in the metadata hypercore's LRU cache\n  contentStorageCacheSize: 65536 // how many entries to use in the content hypercore's LRU cache\n  treeCacheSize: 65536 // how many entries to use in the append-tree's LRU cache\n}\n```\n\n#### `await archive.download([path])`\n\nDownload all files in path of current version.\nIf no path is specified this will download all files.\n\nYou can use this with `.checkout(version)` to download a specific version of the archive.\n\n``` js\narchive.checkout(version).download()\n```\n\n#### `var stream = archive.history([options])`\n\nGet a stream of all changes and their versions from this archive.\n\n#### `var stream = archive.createReadStream(name, [options])`\n\nRead a file out as a stream. Similar to fs.createReadStream.\n\nOptions include:\n\n``` js\n{\n  start: optionalByteOffset, // similar to fs\n  end: optionalInclusiveByteEndOffset, // similar to fs\n  length: optionalByteLength\n}\n```\n\n#### `const data = await archive.readFile(name, [options])`\n\nRead an entire file into memory. Similar to fs.readFile.\n\nOptions can either be an object or a string\n\nOptions include:\n```js\n{\n  encoding: string\n  cached: true|false // default: false\n}\n```\nor a string can be passed as options to simply set the encoding - similar to fs.\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `var stream = archive.createDiffStream(version, [options])`\n\nDiff this archive with another version. `version` can both be a version number of a checkout instance of the archive. The `data` objects looks like this\n\n``` js\n{\n  type: 'put' | 'del',\n  name: '/some/path/name.txt',\n  value: {\n    // the stat object\n  }\n}\n```\n\n#### `var stream = archive.createWriteStream(name, [options])`\n\nWrite a file as a stream. Similar to fs.createWriteStream.\nIf `options.cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `await archive.writeFile(name, buffer, [options])`\n\nWrite a file from a single buffer. Similar to fs.writeFile.\n\n#### `await archive.unlink(name)`\n\nUnlinks (deletes) a file. Similar to fs.unlink.\n\n#### `await archive.mkdir(name, [options])`\n\nExplictly create an directory. Similar to fs.mkdir\n\n#### `await archive.rmdir(name)`\n\nDelete an empty directory. Similar to fs.rmdir.\n\n#### `const names = await archive.readdir(name, [options])`\n\nLists a directory. Similar to fs.readdir.\n\nOptions include:\n\n``` js\n{\n    cached: true|false, // default: false\n}\n```\n\nIf `cached` is set to `true`, this function returns results from the local version of the archive’s append-tree. Default behavior is to fetch the latest remote version of the archive before returning list of directories.\n\n#### `const stat = await archive.stat(name, [options])`\n\nStat an entry. Similar to fs.stat. Sample output:\n\n```\nStat {\n  dev: 0,\n  nlink: 1,\n  rdev: 0,\n  blksize: 0,\n  ino: 0,\n  mode: 16877,\n  uid: 0,\n  gid: 0,\n  size: 0,\n  offset: 0,\n  blocks: 0,\n  atime: 2017-04-10T18:59:00.147Z,\n  mtime: 2017-04-10T18:59:00.147Z,\n  ctime: 2017-04-10T18:59:00.147Z,\n  linkname: undefined }\n```\n\nThe output object includes methods similar to fs.stat:\n\n``` js\nvar stat = archive.stat('/hello.txt')\nstat.isDirectory()\nstat.isFile()\n```\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `await archive.lstat(name, [options])`\n\nStat an entry but do not follow symlinks. Similar to fs.lstat.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `await archive.access(name, [options])`\n\nSimilar to fs.access.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `const fd = await archive.open(name, flags, [mode])`\n\nOpen a file and get a file descriptor back. Similar to fs.open.\n\nNote that currently only read mode is supported in this API.\n\n#### `await archive.read(fd, buf, offset, len, position)`\n\nRead from a file descriptor into a buffer. Similar to fs.read.\n\n#### `await archive.close(fd)`\n\nClose a file. Similar to fs.close.\n\n#### `await archive.close()`\n\nCloses all open resources used by the archive.\nThe archive should no longer be used after calling this.\n\n#### `await archive.destroyData()`\n\nCloses all resources used by the archive, and destroys its data from storage.\nThe archive should no longer be used after calling this.\n\n### `const feed = Hypercore(keyOrName, opts)`\n\nInitializes a Hypercore (aka Feed) and begins replicating it.\n\n- `keyOrName`: This **must** be provided. It's either a Dat URL / key or a string identifying the name of the feed. If you want to have a writable feed, you can use the name to generate one and use the name later to get the same feed back without having to save the key somewhere.\n- `opts`: The options for configuring this feed\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n  - `secretKey`: The secret key to use for the feed. Useful for restoring from backups.\n\t- `discoveryKey`: Optionally specify which discovery key you'd like to use for finding peers for this feed.\n\t- `lookup: true`: Specify whether you wish to lookup peers for this feed.\n\t- `announce: true`: Specify whether you wish to advertise yourself as having the feed.\n\n#### `const seq = await feed.append(data)`\n\nAppend a block of data to the feed.\n\nCallback is called with `(err, seq)` when all data has been written at the returned `seq` or an error occurred.\n\n#### `const data = await feed.get(index, [options])`\n\nGet a block of data.\nIf the data is not available locally this method will prioritize and wait for the data to be downloaded before calling the callback.\n\nOptions include\n\n``` js\n{\n  wait: true, // wait for index to be downloaded\n  timeout: 0, // wait at max some milliseconds (0 means no timeout)\n  valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the feed's valueEncoding\n}\n```\n\nCallback is called with `(err, data)`\n\n#### `const results = await feed.getBatch(start, end, [options])`\n\nGet a range of blocks efficiently. Options include\n\n``` js\n{\n  wait: sameAsAbove,\n  timeout: sameAsAbove,\n  valueEncoding: sameAsAbove\n}\n```\n\n#### `const data = await feed.head([options])`\n\nGet the block of data at the tip of the feed. This will be the most recently\nappended block.\n\nAccepts the same `options` as `feed.get()`.\n\n#### `await feed.download([range])`\n\nDownload a range of data. Callback is called when all data has been downloaded.\nA range can have the following properties:\n\n``` js\n{\n  start: startIndex,\n  end: nonInclusiveEndIndex,\n  linear: false // download range linearly and not randomly\n}\n```\n\nIf you do not mark a range the entire feed will be marked for download.\n\nIf you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire\nfeed will be marked for download for you when the feed is created.\n\n#### `await feed.undownload(range)`\n\nCancel a previous download request.\n\n#### `const signature = await feed.signature([index])`\n\nGet a signature proving the correctness of the block at index, or the whole stream.\n\nCallback is called with `(err, signature)`.\nThe signature has the following properties:\n``` js\n{\n  index: lastSignedBlock,\n  signature: Buffer\n}\n```\n\n#### `const success = await feed.verify(index, signature)`\n\nVerify a signature is correct for the data up to index, which must be the last signed\nblock associated with the signature.\n\nCallback is called with `(err, success)` where success is true only if the signature is\ncorrect.\n\n#### `const roots = await feed.rootHashes(index)`\n\nRetrieve the root *hashes* for given `index`.\n\nCallback is called with `(err, roots)`; `roots` is an *Array* of *Node* objects:\n```\nNode {\n  index: location in the merkle tree of this root\n  size: total bytes in children of this root\n  hash: hash of the children of this root (32-byte buffer)\n}\n```\n\n\n#### `var number = feed.downloaded([start], [end])`\n\nReturns total number of downloaded blocks within range.\nIf `end` is not specified it will default to the total number of blocks.\nIf `start` is not specified it will default to 0.\n\n#### `var bool = feed.has(index)`\n\nReturn true if a data block is available locally.\nFalse otherwise.\n\n#### `var bool = feed.has(start, end)`\nReturn true if all data blocks within a range are available locally.\nFalse otherwise.\n\n#### `await feed.clear(start, [end])`\n\nClear a range of data from the local cache.\nWill clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.\n\n`end` defaults to `start + 1`.\n\n#### `feed.seek(byteOffset, callback)`\n\nSeek to a byte offset.\n\nCalls the callback with `(err, index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is\nthe relative byte offset in the data block.\n\n#### `await feed.update([minLength])`\n\nWait for the feed to contain at least `minLength` elements.\nIf you do not provide `minLength` it will be set to current length + 1.\n\nDoes not download any data from peers except for a proof of the new feed length.\n\n``` js\nconsole.log('length is', feed.length)\nfeed.update(function () {\n  console.log('length has increased', feed.length)\n})\n```\n\n#### `var stream = feed.createReadStream([options])`\n\nCreate a readable stream of data.\n\nOptions include:\n\n``` js\n{\n  start: 0, // read from this index\n  end: feed.length, // read until this index\n  snapshot: true, // if set to false it will update `end` to `feed.length` on every read\n  tail: false, // sets `start` to `feed.length`\n  live: false, // set to true to keep reading forever\n  timeout: 0, // timeout for each data event (0 means no timeout)\n  wait: true // wait for data to be downloaded\n}\n```\n\n#### `var stream = feed.createWriteStream()`\n\nCreate a writable stream.\n\n#### `await feed.close()`\n\nFully close this feed.\n\nCalls the callback with `(err)` when all storage has been closed.\n\n### `await feed.destroyData()`\n\nCloses the feed and deletes all of it's data from storage.\n\n#### `const {valid, invalid} = await feed.audit()`\n\nAudit all data in the feed. Will check that all current data stored\nmatches the hashes in the merkle tree and clear the bitfield if not.\n\nWhen done a report is passed to the callback that looks like this:\n\n```js\n{\n  valid: 10, // how many data blocks matches the hashes\n  invalid: 0, // how many did not\n}\n```\n\nIf a block does not match the hash it is cleared from the data bitfield.\n\n### `const extension = feed.registerExtension(name, handlers)`\n\nListens on extension messages of type `name` on the feeds replication channels.\n\n- `handlers.encoding`: The encoding to use for messages. `json`, `binary`, 'utf8'\n- `handlers.onmessage(message, peer)`: Function to invoke when a peer sends you a message for this extension type.\n- `handlers.onerror(err, peer)`: Function to invoke when a peer has sent you a mis-coded message on this extension.\n\nYou can respond to messages with `extension.send(message, peer)`.\n\n#### `feed.writable`\n\nCan we append to this feed?\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.readable`\n\nCan we read from this feed? After closing a feed this will be false.\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.key`\n\nBuffer containing the public key identifying this feed.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.discoveryKey`\n\nBuffer containing a key derived from the feed.key.\nIn contrast to `feed.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same feed, without leaking the feed key.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.length`\n\nHow many blocks of data are available on this feed?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.byteLength`\n\nHow much data is available on this feed in bytes?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.stats`\n\nReturn per-peer and total upload/download counts.\n\nThe returned object is of the form:\n```js\n{\n  totals: {\n    uploadedBytes: 100,\n    uploadedBlocks: 1,\n    downloadedBytes: 0,\n    downloadedBlocks: 0\n  },\n  peers: [\n    {\n      uploadedBytes: 100,\n      uploadedBlocks: 1,\n      downloadedBytes: 0,\n      downloadedBlocks: 0\n    },\n    ...\n  ]\n}\n```\n\nStats will be collected by default, but this can be disabled by setting `opts.stats` to false.\n\n#### `feed.on('ready')`\n\nEmitted when the feed is ready and all properties have been populated.\n\n#### `feed.on('error', err)`\n\nEmitted when the feed experiences a critical error.\n\n#### `feed.on('download', index, data)`\n\nEmitted when a data block has been downloaded.\n\n#### `feed.on('upload', index, data)`\n\nEmitted when a data block is uploaded.\n\n#### `feed.on('append')`\n\nEmitted when the feed has been appended to (i.e. has a new length / byteLength)\n\n#### `feed.on('sync')`\n\nEmitted every time ALL data from `0` to `feed.length` has been downloaded.\n\n#### `feed.on('close')`\n\nEmitted when the feed has been fully closed\n\n### `feed.on('peer-add', peer)`\n\nEmitted when a new peer has started replicating with the feed.\n\n### `feed.on('peer-remove', peer)`\n\nEmitted when a peer has stopped replicating with the feed.\n\n\n---\n\n[Dat Project]: https://dat.foundation\n","readmeFilename":"README.md","_id":"dat-sdk@2.0.0-5","_nodeVersion":"11.15.0","_npmVersion":"6.13.7","dist":{"integrity":"sha512-E8KVSfbpcR7tpIBGkfx0d0n7OeKS9IsByqzh1JlAG7p5ggX1sfzZcunjMD8JBQ5WgCuVD8x1n5yC+gJu4ZzGOA==","shasum":"1dedde09bb6293aa9ceaccebd88bbaee885d2942","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.0.0-5.tgz","fileCount":6,"unpackedSize":38045,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJekkLrCRA9TVsSAnZWagAAC0AQAJkrM/i+gHEq3B7kNVX7\n7brDNzghbTIsq9T4JaXWpWUa9uQ87fU1I8WGWf/cnjhHPuOjmzrPfBd+oKm0\nwM0wk0hJY1tiPNEC8R6YnXSk4FDEaem/VUPJqKoBo+uAPqIvFXgZg2ZGFKDg\nsbOFxrJXn6rNEQNeBmOaZoyf23IwmBjixf9Xeb4Zi1Fc9/f4X7NIuiTt+5s8\nKJjsW1Txt584YB2srFlV69g6IIkfYLwPFv1GW0p/7IOVifAhejtbVTrA6vNa\n1FL/O2nH6d5GuFH62ELXNfBd61uFST0fQx3N2XJhgG9dfihKvXnYmmSRJ05v\nqJJSB9Q3eIzK9C4Tdkoa49tnpxNBg3SEWY4hMiAj5MTP7hrSV0K7DA2ZVJdK\nSYaVEmE31Tdf5/YkF3sSoXxjViHgJPCrAC9kFswKAUswFG7qbvSIfAhwcsqz\n4urQkaoJ3Deq8vOup9KIsftnd0aX8h1UlUFAUgvoVlTLZSNQWkKlSQFuHHQO\nvkabz4tGYeGFH6l+mJPlehdmrGaSnVxydoPC0OATZ/vmGWkp7xES6ePpTzz2\nxwCKgdvdVw8X6ZGqmToTELMmQAXdcOHdWr6E1OAGiShp+tRfHoVw52d7SNLl\nBtbG4YYdOOf+x5M2Pty5ibP5mVq17kE53VL5OtpmCIP10h66hbO6b49vvsKP\nz3cr\r\n=8WOU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEvXMk39vVfrNPMdTqtOwZi42uvPU53oO0EMltLFivWdAiEA+AskGC8uQvPDc3NhaxXTfmuqsmB4pUPJZQPv+j6DqX4="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.0.0-5_1586643690938_0.2168623481073797"},"_hasShrinkwrap":false},"2.0.0-6":{"name":"dat-sdk","version":"2.0.0-6","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^1.1.0","@geut/hyperdrive-promise":"^3.0.0","@geut/sodium-javascript-plus":"0.0.4","concat-stream":"^2.0.0","corestore":"^5.1.1","corestore-swarm-networking":"^5.1.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"github:rangermauve/hypercore#destroy-rename","hypercore-crypto":"^1.0.0","hypercore-protocol":"^7.10.0","hyperdrive":"github:rangermauve/hyperdrive#destroy","hyperswarm-web":"^1.0.2","node-localstorage":"^2.1.5","random-access-application":"^1.0.0","random-access-memory":"^3.1.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"3c752aa7db4e3e21023c3c67ffeec4473c6a40cb","readme":"# sdk\nThe official Dat SDK\n\n[<img src=\"https://datproject.github.io/design/downloads/dat-logo.png\" align=\"right\" width=\"140\">][Dat Project]\n\n## Why use this?\n\nDat consists of a bunch of low level building blocks for working with data in distributed applications. Although this modularity makes it easy to mix and match pieces, it adds complexity when it comes to actually building something.\n\nThe Dat SDK combines the lower level pieces of the Dat ecosystem into high level APIs that you can use across platforms so that you can focus on your application rather than the gritty details of how it works.\n\n## Goals\n\n- High level API\n- Cross-platform with same codebase\n  - ✔ Node\n  - ✔ Web\n  - ✔ Electron\n  - React-Native (with [nodejs-mobile-react-native?](https://github.com/janeasystems/nodejs-mobile-react-native))\n\n## Installing Node\n\n[Node.js](https://nodejs.org/) / [Browserify](http://browserify.org/) workflows:\n\n```shell\nnpm install --save dat-sdk@next\n```\n\n```js\nconst SDK = require('dat-sdk')\n```\n\n## Building a bundle for Browsers\n\n```shell\ngit clone git@github.com:datproject/sdk.git\n\ncd sdk\n\n# Compile the SDK into a single JS file\nnpm run build\n\n# Copy `dat-sdk-bundle.js` into your project\n```\n\n```html\n<script src=\"dat-sdk-bundle.js\"></script>\n<script>\n  const SDK = window.datSDK\n  // Look at the examples from here\n</script>\n```\n\n## Compile with Browserify\n\n```\nnpm install --save-dev browserify\nnpm install --save dat-sdk@next\n```\n\nAdd this as the `build` command in your package.json\n\n```shell\nbrowserify index.js > bundle.js\n```\n\nThen you can use `bundle.js` in your project.\n\n## Compile with Webpack (webpack.config.js)\n\nTo bundle with webpack, you'll need to alias some dependencies.\n\n```js\nconst path = require('path')\n\nmodule.exports = {\n  entry: './index.js',\n  target: 'web',\n  resolve: {\n    alias: {\n      fs: 'graceful-fs',\n      'sodium-native': '@geut/sodium-javascript-plus',\n      'sodium-universal': '@geut/sodium-javascript-plus',\n      hyperswarm: 'hyperswarm-web',\n      util: './node_modules/util/util.js'\n    }\n  },\n  output: {\n    filename: 'bundle.js',\n    path: path.resolve(__dirname, 'dist')\n  }\n}\n```\n\nThen you can include `./dist/bundle.js` in your HTML page.\n\n## API/Examples\n\n```js\nconst SDK = require('dat-sdk')\n\nconst sdk = await SDK();\nconst {\n\tHypercore,\n\tHyperdrive,\n\tresolveName,\n\tclose\n} = sdk\n\n// Create a new Hyperdrive.\n// If you want to create a new archive, pass in a name for it\n// This will be used to derive a secret key\n// Every time you open a drive with that name it'll derive the same key\n// This uses a master key that's generated once per device\n// That means the same name will yield a different key on a different machine\nconst archive = Hyperdrive('My archive name', {\n  // This archive will disappear after the process exits\n  // This is here so that running the example doesn't clog up your history\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  //storage: RAI\n})\n\narchive.ready(() => {\n  const url = `dat://${archive.key.toString('hex')}`\n\n  // TODO: Save this for later!\n  console.log(`Here's your URL: ${url}`)\n\n  // Check out the hyperdrive docs for what you can do with it\n  // https://www.npmjs.com/package/hyperdrive#api\n  archive.writeFile('/example.txt', 'Hello World!', () => {\n    console.log('Written example file!')\n  })\n})\n\n// This example is currently broken because Beaker's website isn't on Dat 2 yet\nresolveName('dat://beakerbrowser.com', (err, key) => {\n  if (err) throw err\n  const archive = Hyperdrive(key)\n\n  archive.readFile('/dat.json', 'utf8', (err, data) => {\n    if (err) throw err\n    console.log(`Beaker's dat.json is ${data}`)\n\n    archive.close((err) => {\n      if (err) throw err\n      deleteStorage(archive.key, (e) => {\n        if (e) throw e\n        console.log('Deleted beaker storage')\n      })\n    })\n  })\n})\n\nconst SOME_URL = 'dat://0a9e202b8055721bd2bc93b3c9bbc03efdbda9cfee91f01a123fdeaadeba303e/'\n\nconst someArchive = Hyperdrive(SOME_URL)\n\nsomeArchive.readdir('/', console.log)}\n\n// Create a hypercore\n// Check out the hypercore docs for what you can do with it\n// https://github.com/mafintosh/hypercore\nconst myCore = Hypercore('my hypercore name', {\n  valueEncoding: 'json',\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  // storage: RAI\n})\n\n// Add some data to it\nmyCore.append(JSON.stringify({\n  name: 'Alice'\n}), () => {\n  // Use extension messages for sending extra data over the p2p connection\n  const discoveryCoreKey = 'dat://bee80ff3a4ee5e727dc44197cb9d25bf8f19d50b0f3ad2984cfe5b7d14e75de7'\n  const discoveryCore = new Hypercore(discoveryCoreKey)\n\n\t// Register the extension message handler\n\tconst extension = discoveryCore.registerExtension('discovery', {\n\t\t// Set the encoding type for messages\n\t\tencoding: 'binary',\n\t\tonmessage: (message, peer) => {\n\t\t\t// Recieved messages will be automatically decoded\n\t\t\tconsole.log('Got key from peer!', message)\n\n\t\t\tconst otherCore = new Hypercore(message, {\n        valueEncoding: 'json',\n        persist: false\n      })\n\n      // Render the peer's data from their core\n      otherCore.get(0, console.log)\n\t\t}\n\t})\n\n\t// When you find a peer tell them about your core\n\tdiscoveryCore.on('peer-add', (peer) => {\n\t\tconsole.log('Got a peer!')\n\t\textension.send(myCore.key, peer)\n\t})\n})\n\nconst hypertrie = require('hypertrie')\n\n// Pass in hypercores from the SDK into other dat data structures\n// Check out what you can do with hypertrie from there:\n// https://github.com/mafintosh/hypertrie\nconst trie = hypertrie(null, {\n  feed: new Hypercore('my trie core', {\n    persist: false\n  })\n})\n\ntrie.put('key', 'value', () => {\n  trie.get('key', (err, node) => {\n    console.log('Got key: ', node.key)\n    console.log('Loaded value from trie: ', node.value)\n  })\n})\n\n```\n\n## API\n\nThe API supports both promises and callbacks. Everywhere where you see `await`, you can instead pass a node-style callback.\n\n### `const {Hypercore, Hyperdrive, resolveName, getIdentity, deriveSecret, close} = await SDK(opts?)`\n\nCreates an instance of the Dat SDK based on the options.\n\n- `opts.storage`: An optional [random-access-storage](https://github.com/random-access-storage/random-access-storage) instance for storing data.\n- `opts.applicationName`: An optional name for the application using the SDK. This will automatically silo your data from other applications using the SDK and will store it in the appropriate place using [random-access-application](https://github.com/RangerMauve/random-access-application/)\n- `opts.corestore`: An optional [Corestore](https://github.com/andrewosh/corestore) instance for using as hypercore storage.\n- `opts.corestoreOpts`: Options to pass into Corestore when it's initialized.\n- `opts.swarmOpts`: This lets you configure [hyperswarm](https://github.com/hyperswarm/hyperswarm) and [hyperswarm-web](https://github.com/RangerMauve/hyperswarm-web)\n  - `maxPeers`: The maximum number of connections to keep for this swarm.\n  - `ephemeral **NODE**`: Set to `false` if this is going to be in a long running process on a server. \n  - `bootstap **NODE**`: An array of addresses to use for the DHT bootstraping\n  - `webrtcBootstrap: ['https://geut-webrtc-signal.herokuapp.com/'] **BROWSER**`: The WebRTC bootstrap server list used by [discovery-swarm-webrtc](https://github.com/geut/discovery-swarm-webrtc)\n  - `wsProxy: 'wss://hyperswarm.mauve.moe' **BROWSER**`: The Websocket proxy used for [hyperswarm-proxy-ws](https://github.com/RangerMauve/hyperswarm-proxy-ws)\n- `opts.driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n- `opts.coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `opts.dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `await close()`\n\nThis closes all resources used by the SDK so you can safely end your process. `cb` will be invoked once resources are closed or if there's an error.\n\n### `const key = await resolveName(url)`\n\nResolve a DNS name to a Dat key.\n\n  - `url` is a Dat URL like `dat://dat.foundation`\n  - `key` will be the Dat key that you can pass to `hyperdrive`\n\n### `const {publicKey, secretKey} = await getIdentity()`\n\nThis gives you the public / private keypair used for the Noise protocol encryption when connecting to peers.\nYou can use this to identify peers in the network using `peer.remotePublicKey`\n\n### `const secret = await deriveSecret(namespace, name)`\n\nDerives a secret key based on the SDK's master key.\n`namespace` can be used to namespace different applications, and `name` is the name of the key you want.\nThis can be used as a seed for generating secure private keys without needing to store an extra key on disk.\n\n### `const archive = Hyperdrive(keyOrName, opts)`\n\nThis initializes a Hyperdrive (aka a Dat archive), the SDK will begin finding peers for it and will de-duplicate calls to initializing the same archive more than once.\n\n- `keyOrName`: This **must** be provided. It's either a Dat URL / key or a string identifying the name. If you want to have a writable archive, you can use the name to generate one and use the name later to get the same archive back without having to save the key somewhere.\n- `opts`: These are the options for configuring the hyperdrive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretKey`: A secret key for granting write access. This can be useful when restoring backups.\n\t- `discoveryKey`: Optionally specify which discovery key you'd like to use for finding peers for this archive.\n\t- `lookup: true`: Specify whether you wish to lookup peers for this archive.\n\t- `announce: true`: Specify whether you wish to advertise yourself as having the archive.\n\nThe rest of the Hyperdrive docs were taken from the [Hyperdrive README](https://github.com/mafintosh/hyperdrive/blob/v9/README.md). Note that we're wrapping over the APIs with [Hyperdrive-Promise](https://github.com/geut/hyperdrive-promise) so any callback methods can be `await`ed instead.\n\n#### `archive.version`\n\nGet the current version of the archive (incrementing number).\n\n#### `archive.key`\n\nThe public key identifying the archive.\n\n#### `archive.discoveryKey`\n\nA key derived from the public key that can be used to discovery other peers sharing this archive.\n\n#### `archive.writable`\n\nA boolean indicating whether the archive is writable.\n\n#### `archive.on('ready')`\n\nEmitted when the archive is fully ready and all properties has been populated.\n\n#### `archive.on('update')`\n\nEmitted when the archive has got a new change.\n\n#### `archive.on('error', err)`\n\nEmitted when a critical error during load happened.\n\n#### `archive.on('close')`\n\nEmitted when the archive has been closed\n\n#### `archive.on('peer-add', peer)`\n\nEmitted when a new peer has started replicating wiht the archive.\n\n#### `archive.on('peer-remove', peer)`\n\nEmitted when a peer has stopped replicating wit the archive.\n\n#### `var oldDrive = archive.checkout(version, [opts])`\n\nCheckout a readonly copy of the archive at an old version. Options are used to configure the `oldDrive`:\n\n```js\n{\n  metadataStorageCacheSize: 65536 // how many entries to use in the metadata hypercore's LRU cache\n  contentStorageCacheSize: 65536 // how many entries to use in the content hypercore's LRU cache\n  treeCacheSize: 65536 // how many entries to use in the append-tree's LRU cache\n}\n```\n\n#### `await archive.download([path])`\n\nDownload all files in path of current version.\nIf no path is specified this will download all files.\n\nYou can use this with `.checkout(version)` to download a specific version of the archive.\n\n``` js\narchive.checkout(version).download()\n```\n\n#### `var stream = archive.history([options])`\n\nGet a stream of all changes and their versions from this archive.\n\n#### `var stream = archive.createReadStream(name, [options])`\n\nRead a file out as a stream. Similar to fs.createReadStream.\n\nOptions include:\n\n``` js\n{\n  start: optionalByteOffset, // similar to fs\n  end: optionalInclusiveByteEndOffset, // similar to fs\n  length: optionalByteLength\n}\n```\n\n#### `const data = await archive.readFile(name, [options])`\n\nRead an entire file into memory. Similar to fs.readFile.\n\nOptions can either be an object or a string\n\nOptions include:\n```js\n{\n  encoding: string\n  cached: true|false // default: false\n}\n```\nor a string can be passed as options to simply set the encoding - similar to fs.\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `var stream = archive.createDiffStream(version, [options])`\n\nDiff this archive with another version. `version` can both be a version number of a checkout instance of the archive. The `data` objects looks like this\n\n``` js\n{\n  type: 'put' | 'del',\n  name: '/some/path/name.txt',\n  value: {\n    // the stat object\n  }\n}\n```\n\n#### `var stream = archive.createWriteStream(name, [options])`\n\nWrite a file as a stream. Similar to fs.createWriteStream.\nIf `options.cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `await archive.writeFile(name, buffer, [options])`\n\nWrite a file from a single buffer. Similar to fs.writeFile.\n\n#### `await archive.unlink(name)`\n\nUnlinks (deletes) a file. Similar to fs.unlink.\n\n#### `await archive.mkdir(name, [options])`\n\nExplictly create an directory. Similar to fs.mkdir\n\n#### `await archive.rmdir(name)`\n\nDelete an empty directory. Similar to fs.rmdir.\n\n#### `const names = await archive.readdir(name, [options])`\n\nLists a directory. Similar to fs.readdir.\n\nOptions include:\n\n``` js\n{\n    cached: true|false, // default: false\n}\n```\n\nIf `cached` is set to `true`, this function returns results from the local version of the archive’s append-tree. Default behavior is to fetch the latest remote version of the archive before returning list of directories.\n\n#### `const stat = await archive.stat(name, [options])`\n\nStat an entry. Similar to fs.stat. Sample output:\n\n```\nStat {\n  dev: 0,\n  nlink: 1,\n  rdev: 0,\n  blksize: 0,\n  ino: 0,\n  mode: 16877,\n  uid: 0,\n  gid: 0,\n  size: 0,\n  offset: 0,\n  blocks: 0,\n  atime: 2017-04-10T18:59:00.147Z,\n  mtime: 2017-04-10T18:59:00.147Z,\n  ctime: 2017-04-10T18:59:00.147Z,\n  linkname: undefined }\n```\n\nThe output object includes methods similar to fs.stat:\n\n``` js\nvar stat = archive.stat('/hello.txt')\nstat.isDirectory()\nstat.isFile()\n```\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `await archive.lstat(name, [options])`\n\nStat an entry but do not follow symlinks. Similar to fs.lstat.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `await archive.access(name, [options])`\n\nSimilar to fs.access.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `const fd = await archive.open(name, flags, [mode])`\n\nOpen a file and get a file descriptor back. Similar to fs.open.\n\nNote that currently only read mode is supported in this API.\n\n#### `await archive.read(fd, buf, offset, len, position)`\n\nRead from a file descriptor into a buffer. Similar to fs.read.\n\n#### `await archive.close(fd)`\n\nClose a file. Similar to fs.close.\n\n#### `await archive.close()`\n\nCloses all open resources used by the archive.\nThe archive should no longer be used after calling this.\n\n#### `await archive.destroyData()`\n\nCloses all resources used by the archive, and destroys its data from storage.\nThe archive should no longer be used after calling this.\n\n### `const feed = Hypercore(keyOrName, opts)`\n\nInitializes a Hypercore (aka Feed) and begins replicating it.\n\n- `keyOrName`: This **must** be provided. It's either a Dat URL / key or a string identifying the name of the feed. If you want to have a writable feed, you can use the name to generate one and use the name later to get the same feed back without having to save the key somewhere.\n- `opts`: The options for configuring this feed\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n  - `secretKey`: The secret key to use for the feed. Useful for restoring from backups.\n\t- `discoveryKey`: Optionally specify which discovery key you'd like to use for finding peers for this feed.\n\t- `lookup: true`: Specify whether you wish to lookup peers for this feed.\n\t- `announce: true`: Specify whether you wish to advertise yourself as having the feed.\n\n#### `const seq = await feed.append(data)`\n\nAppend a block of data to the feed.\n\nCallback is called with `(err, seq)` when all data has been written at the returned `seq` or an error occurred.\n\n#### `const data = await feed.get(index, [options])`\n\nGet a block of data.\nIf the data is not available locally this method will prioritize and wait for the data to be downloaded before calling the callback.\n\nOptions include\n\n``` js\n{\n  wait: true, // wait for index to be downloaded\n  timeout: 0, // wait at max some milliseconds (0 means no timeout)\n  valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the feed's valueEncoding\n}\n```\n\nCallback is called with `(err, data)`\n\n#### `const results = await feed.getBatch(start, end, [options])`\n\nGet a range of blocks efficiently. Options include\n\n``` js\n{\n  wait: sameAsAbove,\n  timeout: sameAsAbove,\n  valueEncoding: sameAsAbove\n}\n```\n\n#### `const data = await feed.head([options])`\n\nGet the block of data at the tip of the feed. This will be the most recently\nappended block.\n\nAccepts the same `options` as `feed.get()`.\n\n#### `await feed.download([range])`\n\nDownload a range of data. Callback is called when all data has been downloaded.\nA range can have the following properties:\n\n``` js\n{\n  start: startIndex,\n  end: nonInclusiveEndIndex,\n  linear: false // download range linearly and not randomly\n}\n```\n\nIf you do not mark a range the entire feed will be marked for download.\n\nIf you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire\nfeed will be marked for download for you when the feed is created.\n\n#### `await feed.undownload(range)`\n\nCancel a previous download request.\n\n#### `const signature = await feed.signature([index])`\n\nGet a signature proving the correctness of the block at index, or the whole stream.\n\nCallback is called with `(err, signature)`.\nThe signature has the following properties:\n``` js\n{\n  index: lastSignedBlock,\n  signature: Buffer\n}\n```\n\n#### `const success = await feed.verify(index, signature)`\n\nVerify a signature is correct for the data up to index, which must be the last signed\nblock associated with the signature.\n\nCallback is called with `(err, success)` where success is true only if the signature is\ncorrect.\n\n#### `const roots = await feed.rootHashes(index)`\n\nRetrieve the root *hashes* for given `index`.\n\nCallback is called with `(err, roots)`; `roots` is an *Array* of *Node* objects:\n```\nNode {\n  index: location in the merkle tree of this root\n  size: total bytes in children of this root\n  hash: hash of the children of this root (32-byte buffer)\n}\n```\n\n\n#### `var number = feed.downloaded([start], [end])`\n\nReturns total number of downloaded blocks within range.\nIf `end` is not specified it will default to the total number of blocks.\nIf `start` is not specified it will default to 0.\n\n#### `var bool = feed.has(index)`\n\nReturn true if a data block is available locally.\nFalse otherwise.\n\n#### `var bool = feed.has(start, end)`\nReturn true if all data blocks within a range are available locally.\nFalse otherwise.\n\n#### `await feed.clear(start, [end])`\n\nClear a range of data from the local cache.\nWill clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.\n\n`end` defaults to `start + 1`.\n\n#### `feed.seek(byteOffset, callback)`\n\nSeek to a byte offset.\n\nCalls the callback with `(err, index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is\nthe relative byte offset in the data block.\n\n#### `await feed.update([minLength])`\n\nWait for the feed to contain at least `minLength` elements.\nIf you do not provide `minLength` it will be set to current length + 1.\n\nDoes not download any data from peers except for a proof of the new feed length.\n\n``` js\nconsole.log('length is', feed.length)\nfeed.update(function () {\n  console.log('length has increased', feed.length)\n})\n```\n\n#### `var stream = feed.createReadStream([options])`\n\nCreate a readable stream of data.\n\nOptions include:\n\n``` js\n{\n  start: 0, // read from this index\n  end: feed.length, // read until this index\n  snapshot: true, // if set to false it will update `end` to `feed.length` on every read\n  tail: false, // sets `start` to `feed.length`\n  live: false, // set to true to keep reading forever\n  timeout: 0, // timeout for each data event (0 means no timeout)\n  wait: true // wait for data to be downloaded\n}\n```\n\n#### `var stream = feed.createWriteStream()`\n\nCreate a writable stream.\n\n#### `await feed.close()`\n\nFully close this feed.\n\nCalls the callback with `(err)` when all storage has been closed.\n\n#### `await feed.destroyData()`\n\nCloses the feed and deletes all of it's data from storage.\n\n#### `const {valid, invalid} = await feed.audit()`\n\nAudit all data in the feed. Will check that all current data stored\nmatches the hashes in the merkle tree and clear the bitfield if not.\n\nWhen done a report is passed to the callback that looks like this:\n\n```js\n{\n  valid: 10, // how many data blocks matches the hashes\n  invalid: 0, // how many did not\n}\n```\n\nIf a block does not match the hash it is cleared from the data bitfield.\n\n#### `const extension = feed.registerExtension(name, handlers)`\n\nListens on extension messages of type `name` on the feeds replication channels.\n\n- `handlers.encoding`: The encoding to use for messages. `json`, `binary`, 'utf8'\n- `handlers.onmessage(message, peer)`: Function to invoke when a peer sends you a message for this extension type.\n- `handlers.onerror(err, peer)`: Function to invoke when a peer has sent you a mis-coded message on this extension.\n\nYou can respond to messages with `extension.send(message, peer)`.\n\n#### `feed.writable`\n\nCan we append to this feed?\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.readable`\n\nCan we read from this feed? After closing a feed this will be false.\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.key`\n\nBuffer containing the public key identifying this feed.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.discoveryKey`\n\nBuffer containing a key derived from the feed.key.\nIn contrast to `feed.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same feed, without leaking the feed key.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.length`\n\nHow many blocks of data are available on this feed?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.byteLength`\n\nHow much data is available on this feed in bytes?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.stats`\n\nReturn per-peer and total upload/download counts.\n\nThe returned object is of the form:\n```js\n{\n  totals: {\n    uploadedBytes: 100,\n    uploadedBlocks: 1,\n    downloadedBytes: 0,\n    downloadedBlocks: 0\n  },\n  peers: [\n    {\n      uploadedBytes: 100,\n      uploadedBlocks: 1,\n      downloadedBytes: 0,\n      downloadedBlocks: 0\n    },\n    ...\n  ]\n}\n```\n\nStats will be collected by default, but this can be disabled by setting `opts.stats` to false.\n\n#### `feed.on('ready')`\n\nEmitted when the feed is ready and all properties have been populated.\n\n#### `feed.on('error', err)`\n\nEmitted when the feed experiences a critical error.\n\n#### `feed.on('download', index, data)`\n\nEmitted when a data block has been downloaded.\n\n#### `feed.on('upload', index, data)`\n\nEmitted when a data block is uploaded.\n\n#### `feed.on('append')`\n\nEmitted when the feed has been appended to (i.e. has a new length / byteLength)\n\n#### `feed.on('sync')`\n\nEmitted every time ALL data from `0` to `feed.length` has been downloaded.\n\n#### `feed.on('close')`\n\nEmitted when the feed has been fully closed\n\n#### `feed.on('peer-add', peer)`\n\nEmitted when a new peer has started replicating with the feed.\n\n#### `feed.on('peer-remove', peer)`\n\nEmitted when a peer has stopped replicating with the feed.\n\n\n---\n\n[Dat Project]: https://dat.foundation\n","readmeFilename":"README.md","_id":"dat-sdk@2.0.0-6","_nodeVersion":"11.15.0","_npmVersion":"6.13.7","dist":{"integrity":"sha512-8QNKosPxrybKWbPlEbCoNrkFiQWxkZt/P2TC7hY9j57Mcg7sfth2t7mkx0agmWcTDcWa1o5t7Kaazb1RG/IvNw==","shasum":"db3fabafbd7bbeb33a2446fe7f1b5d61bf358bd4","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.0.0-6.tgz","fileCount":6,"unpackedSize":38510,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeljm/CRA9TVsSAnZWagAAaR8P/0caGPbridVDH3XNg5vp\n0o6dcI3nQvEg/RnULXD881m/h0fZO9v7SlJkk9J2aIsORXCirsGqnx4CRdPx\n+PreokI2Rr6N2G2SnDMWHkoJbfwYL1HLzVy8tzvxnYQImERAq1yl1srSFzgw\nrg3NcWDA9M20byZasyEfGjyMRppuWmr614uJ3yFydjHWAqt0qQMLbTBwBOma\nzyJf9ReA7gaDiQEdz/BGZlkDKV6WVB5kf9KNtRR03e2QCghnj3sokiLta9K0\nQRMxIUjDJKP/nXS87jesg0AI285LAi5vBJgcrYwCSM/azjYTeS9uXKwV6+mP\nF4bQ/whkgREjH82+777MsFBhEJfrOngYQ3VbvQUhe8bsc/S9KL2kklnDqIYS\nw20H0AbDh+pPzfOBytU6r8gMibXNfuc58nfjrRoKz0I+Xh5Kf2iIsuBGpy1Y\n8/8bdGY8Cm5UaliVXPL/iPGjHZjWkl172QNIjgMGrLll0xgm3RZF5gNwEpi5\nUgt1D68Fk/MqYoC7LIZuvSSvsBmatfZXMEWix6QSRIHrQygpi7XjNLSN2rtQ\nsPhZGTJTE97k2iRTHHZYVtU9XDpeIK97fds+bas9vydpb80vz8D8DCyp1aRJ\necZK5hVXMAy5yDHQTq9gXqnpf7jaO/VXWbNVo4jRobYfXuBQDVFzLiNAflWZ\n92z6\r\n=Scvw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA99jutBall7KIkJgo12xPuZnoZA02HoLaLEYcxF5JLaAiEApOGm489x3lgyN+VtdEBCrI+S9evUw+OPGawCw0IGm2M="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.0.0-6_1586903487089_0.9922270195461642"},"_hasShrinkwrap":false},"2.0.0-7":{"name":"dat-sdk","version":"2.0.0-7","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^1.1.0","@geut/hyperdrive-promise":"^3.0.0","@geut/sodium-javascript-plus":"0.0.4","concat-stream":"^2.0.0","corestore":"^5.1.1","corestore-swarm-networking":"^5.1.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"github:rangermauve/hypercore#destroy-rename","hypercore-crypto":"^1.0.0","hypercore-protocol":"^7.10.0","hyperdrive":"github:rangermauve/hyperdrive#destroy","hyperswarm-web":"^1.0.2","node-localstorage":"^2.1.5","random-access-application":"^1.0.0","random-access-memory":"^3.1.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"readme":"# sdk\nThe official Dat SDK\n\n[<img src=\"https://datproject.github.io/design/downloads/dat-logo.png\" align=\"right\" width=\"140\">][Dat Project]\n\n## Why use this?\n\nDat consists of a bunch of low level building blocks for working with data in distributed applications. Although this modularity makes it easy to mix and match pieces, it adds complexity when it comes to actually building something.\n\nThe Dat SDK combines the lower level pieces of the Dat ecosystem into high level APIs that you can use across platforms so that you can focus on your application rather than the gritty details of how it works.\n\n## Goals\n\n- High level API\n- Cross-platform with same codebase\n  - ✔ Node\n  - ✔ Web\n  - ✔ Electron\n  - React-Native (with [nodejs-mobile-react-native?](https://github.com/janeasystems/nodejs-mobile-react-native))\n\n## Installing Node\n\n[Node.js](https://nodejs.org/) / [Browserify](http://browserify.org/) workflows:\n\n```shell\nnpm install --save dat-sdk@next\n```\n\n```js\nconst SDK = require('dat-sdk')\n```\n\n## Building a bundle for Browsers\n\n```shell\ngit clone git@github.com:datproject/sdk.git\n\ncd sdk\n\n# Compile the SDK into a single JS file\nnpm run build\n\n# Copy `dat-sdk-bundle.js` into your project\n```\n\n```html\n<script src=\"dat-sdk-bundle.js\"></script>\n<script>\n  const SDK = window.datSDK\n  // Look at the examples from here\n</script>\n```\n\n## Compile with Browserify\n\n```\nnpm install --save-dev browserify\nnpm install --save dat-sdk@next\n```\n\nAdd this as the `build` command in your package.json\n\n```shell\nbrowserify index.js > bundle.js\n```\n\nThen you can use `bundle.js` in your project.\n\n## Compile with Webpack (webpack.config.js)\n\nTo bundle with webpack, you'll need to alias some dependencies.\n\n```js\nconst path = require('path')\n\nmodule.exports = {\n  entry: './index.js',\n  target: 'web',\n  resolve: {\n    alias: {\n      fs: 'graceful-fs',\n      'sodium-native': '@geut/sodium-javascript-plus',\n      'sodium-universal': '@geut/sodium-javascript-plus',\n      hyperswarm: 'hyperswarm-web',\n      util: './node_modules/util/util.js'\n    }\n  },\n  output: {\n    filename: 'bundle.js',\n    path: path.resolve(__dirname, 'dist')\n  }\n}\n```\n\nThen you can include `./dist/bundle.js` in your HTML page.\n\n## API/Examples\n\n```js\nconst SDK = require('dat-sdk')\n\nconst sdk = await SDK();\nconst {\n\tHypercore,\n\tHyperdrive,\n\tresolveName,\n\tclose\n} = sdk\n\n// Create a new Hyperdrive.\n// If you want to create a new archive, pass in a name for it\n// This will be used to derive a secret key\n// Every time you open a drive with that name it'll derive the same key\n// This uses a master key that's generated once per device\n// That means the same name will yield a different key on a different machine\nconst archive = Hyperdrive('My archive name', {\n  // This archive will disappear after the process exits\n  // This is here so that running the example doesn't clog up your history\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  //storage: RAI\n})\n\narchive.ready(() => {\n  const url = `dat://${archive.key.toString('hex')}`\n\n  // TODO: Save this for later!\n  console.log(`Here's your URL: ${url}`)\n\n  // Check out the hyperdrive docs for what you can do with it\n  // https://www.npmjs.com/package/hyperdrive#api\n  archive.writeFile('/example.txt', 'Hello World!', () => {\n    console.log('Written example file!')\n  })\n})\n\n// This example is currently broken because Beaker's website isn't on Dat 2 yet\nresolveName('dat://beakerbrowser.com', (err, key) => {\n  if (err) throw err\n  const archive = Hyperdrive(key)\n\n  archive.readFile('/dat.json', 'utf8', (err, data) => {\n    if (err) throw err\n    console.log(`Beaker's dat.json is ${data}`)\n\n    archive.close((err) => {\n      if (err) throw err\n      deleteStorage(archive.key, (e) => {\n        if (e) throw e\n        console.log('Deleted beaker storage')\n      })\n    })\n  })\n})\n\nconst SOME_URL = 'dat://0a9e202b8055721bd2bc93b3c9bbc03efdbda9cfee91f01a123fdeaadeba303e/'\n\nconst someArchive = Hyperdrive(SOME_URL)\n\nsomeArchive.readdir('/', console.log)}\n\n// Create a hypercore\n// Check out the hypercore docs for what you can do with it\n// https://github.com/mafintosh/hypercore\nconst myCore = Hypercore('my hypercore name', {\n  valueEncoding: 'json',\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  // storage: RAI\n})\n\n// Add some data to it\nmyCore.append(JSON.stringify({\n  name: 'Alice'\n}), () => {\n  // Use extension messages for sending extra data over the p2p connection\n  const discoveryCoreKey = 'dat://bee80ff3a4ee5e727dc44197cb9d25bf8f19d50b0f3ad2984cfe5b7d14e75de7'\n  const discoveryCore = new Hypercore(discoveryCoreKey)\n\n\t// Register the extension message handler\n\tconst extension = discoveryCore.registerExtension('discovery', {\n\t\t// Set the encoding type for messages\n\t\tencoding: 'binary',\n\t\tonmessage: (message, peer) => {\n\t\t\t// Recieved messages will be automatically decoded\n\t\t\tconsole.log('Got key from peer!', message)\n\n\t\t\tconst otherCore = new Hypercore(message, {\n        valueEncoding: 'json',\n        persist: false\n      })\n\n      // Render the peer's data from their core\n      otherCore.get(0, console.log)\n\t\t}\n\t})\n\n\t// When you find a peer tell them about your core\n\tdiscoveryCore.on('peer-add', (peer) => {\n\t\tconsole.log('Got a peer!')\n\t\textension.send(myCore.key, peer)\n\t})\n})\n\nconst hypertrie = require('hypertrie')\n\n// Pass in hypercores from the SDK into other dat data structures\n// Check out what you can do with hypertrie from there:\n// https://github.com/mafintosh/hypertrie\nconst trie = hypertrie(null, {\n  feed: new Hypercore('my trie core', {\n    persist: false\n  })\n})\n\ntrie.put('key', 'value', () => {\n  trie.get('key', (err, node) => {\n    console.log('Got key: ', node.key)\n    console.log('Loaded value from trie: ', node.value)\n  })\n})\n\n```\n\n## API\n\nThe API supports both promises and callbacks. Everywhere where you see `await`, you can instead pass a node-style callback.\n\n### `const {Hypercore, Hyperdrive, resolveName, getIdentity, deriveSecret, close} = await SDK(opts?)`\n\nCreates an instance of the Dat SDK based on the options.\n\n- `opts.storage`: An optional [random-access-storage](https://github.com/random-access-storage/random-access-storage) instance for storing data.\n- `opts.applicationName`: An optional name for the application using the SDK. This will automatically silo your data from other applications using the SDK and will store it in the appropriate place using [random-access-application](https://github.com/RangerMauve/random-access-application/)\n- `opts.corestore`: An optional [Corestore](https://github.com/andrewosh/corestore) instance for using as hypercore storage.\n- `opts.corestoreOpts`: Options to pass into Corestore when it's initialized.\n- `opts.swarmOpts`: This lets you configure [hyperswarm](https://github.com/hyperswarm/hyperswarm) and [hyperswarm-web](https://github.com/RangerMauve/hyperswarm-web)\n  - `maxPeers`: The maximum number of connections to keep for this swarm.\n  - `ephemeral **NODE**`: Set to `false` if this is going to be in a long running process on a server. \n  - `bootstap **NODE**`: An array of addresses to use for the DHT bootstraping\n  - `webrtcBootstrap: ['https://geut-webrtc-signal.herokuapp.com/'] **BROWSER**`: The WebRTC bootstrap server list used by [discovery-swarm-webrtc](https://github.com/geut/discovery-swarm-webrtc)\n  - `wsProxy: 'wss://hyperswarm.mauve.moe' **BROWSER**`: The Websocket proxy used for [hyperswarm-proxy-ws](https://github.com/RangerMauve/hyperswarm-proxy-ws)\n- `opts.driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n- `opts.coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `opts.dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `await close()`\n\nThis closes all resources used by the SDK so you can safely end your process. `cb` will be invoked once resources are closed or if there's an error.\n\n### `const key = await resolveName(url)`\n\nResolve a DNS name to a Dat key.\n\n  - `url` is a Dat URL like `dat://dat.foundation`\n  - `key` will be the Dat key that you can pass to `hyperdrive`\n\n### `const {publicKey, secretKey} = await getIdentity()`\n\nThis gives you the public / private keypair used for the Noise protocol encryption when connecting to peers.\nYou can use this to identify peers in the network using `peer.remotePublicKey`\n\n### `const secret = await deriveSecret(namespace, name)`\n\nDerives a secret key based on the SDK's master key.\n`namespace` can be used to namespace different applications, and `name` is the name of the key you want.\nThis can be used as a seed for generating secure private keys without needing to store an extra key on disk.\n\n### `const archive = Hyperdrive(keyOrName, opts)`\n\nThis initializes a Hyperdrive (aka a Dat archive), the SDK will begin finding peers for it and will de-duplicate calls to initializing the same archive more than once.\n\n- `keyOrName`: This **must** be provided. It's either a Dat URL / key or a string identifying the name. If you want to have a writable archive, you can use the name to generate one and use the name later to get the same archive back without having to save the key somewhere.\n- `opts`: These are the options for configuring the hyperdrive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretKey`: A secret key for granting write access. This can be useful when restoring backups.\n\t- `discoveryKey`: Optionally specify which discovery key you'd like to use for finding peers for this archive.\n\t- `lookup: true`: Specify whether you wish to lookup peers for this archive. Set `false` along with `announce` to avoid advertising\n\t- `announce: true`: Specify whether you wish to advertise yourself as having the archive.\n\nThe rest of the Hyperdrive docs were taken from the [Hyperdrive README](https://github.com/mafintosh/hyperdrive/blob/v9/README.md). Note that we're wrapping over the APIs with [Hyperdrive-Promise](https://github.com/geut/hyperdrive-promise) so any callback methods can be `await`ed instead.\n\n#### `archive.version`\n\nGet the current version of the archive (incrementing number).\n\n#### `archive.key`\n\nThe public key identifying the archive.\n\n#### `archive.discoveryKey`\n\nA key derived from the public key that can be used to discovery other peers sharing this archive.\n\n#### `archive.writable`\n\nA boolean indicating whether the archive is writable.\n\n#### `archive.on('ready')`\n\nEmitted when the archive is fully ready and all properties has been populated.\n\n#### `archive.on('update')`\n\nEmitted when the archive has got a new change.\n\n#### `archive.on('error', err)`\n\nEmitted when a critical error during load happened.\n\n#### `archive.on('close')`\n\nEmitted when the archive has been closed\n\n#### `archive.on('peer-add', peer)`\n\nEmitted when a new peer has started replicating wiht the archive.\n\n#### `archive.on('peer-remove', peer)`\n\nEmitted when a peer has stopped replicating wit the archive.\n\n#### `var oldDrive = archive.checkout(version, [opts])`\n\nCheckout a readonly copy of the archive at an old version. Options are used to configure the `oldDrive`:\n\n```js\n{\n  metadataStorageCacheSize: 65536 // how many entries to use in the metadata hypercore's LRU cache\n  contentStorageCacheSize: 65536 // how many entries to use in the content hypercore's LRU cache\n  treeCacheSize: 65536 // how many entries to use in the append-tree's LRU cache\n}\n```\n\n#### `await archive.download([path])`\n\nDownload all files in path of current version.\nIf no path is specified this will download all files.\n\nYou can use this with `.checkout(version)` to download a specific version of the archive.\n\n``` js\narchive.checkout(version).download()\n```\n\n#### `var stream = archive.history([options])`\n\nGet a stream of all changes and their versions from this archive.\n\n#### `var stream = archive.createReadStream(name, [options])`\n\nRead a file out as a stream. Similar to fs.createReadStream.\n\nOptions include:\n\n``` js\n{\n  start: optionalByteOffset, // similar to fs\n  end: optionalInclusiveByteEndOffset, // similar to fs\n  length: optionalByteLength\n}\n```\n\n#### `const data = await archive.readFile(name, [options])`\n\nRead an entire file into memory. Similar to fs.readFile.\n\nOptions can either be an object or a string\n\nOptions include:\n```js\n{\n  encoding: string\n  cached: true|false // default: false\n}\n```\nor a string can be passed as options to simply set the encoding - similar to fs.\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `var stream = archive.createDiffStream(version, [options])`\n\nDiff this archive with another version. `version` can both be a version number of a checkout instance of the archive. The `data` objects looks like this\n\n``` js\n{\n  type: 'put' | 'del',\n  name: '/some/path/name.txt',\n  value: {\n    // the stat object\n  }\n}\n```\n\n#### `var stream = archive.createWriteStream(name, [options])`\n\nWrite a file as a stream. Similar to fs.createWriteStream.\nIf `options.cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `await archive.writeFile(name, buffer, [options])`\n\nWrite a file from a single buffer. Similar to fs.writeFile.\n\n#### `await archive.unlink(name)`\n\nUnlinks (deletes) a file. Similar to fs.unlink.\n\n#### `await archive.mkdir(name, [options])`\n\nExplictly create an directory. Similar to fs.mkdir\n\n#### `await archive.rmdir(name)`\n\nDelete an empty directory. Similar to fs.rmdir.\n\n#### `const names = await archive.readdir(name, [options])`\n\nLists a directory. Similar to fs.readdir.\n\nOptions include:\n\n``` js\n{\n    cached: true|false, // default: false\n}\n```\n\nIf `cached` is set to `true`, this function returns results from the local version of the archive’s append-tree. Default behavior is to fetch the latest remote version of the archive before returning list of directories.\n\n#### `const stat = await archive.stat(name, [options])`\n\nStat an entry. Similar to fs.stat. Sample output:\n\n```\nStat {\n  dev: 0,\n  nlink: 1,\n  rdev: 0,\n  blksize: 0,\n  ino: 0,\n  mode: 16877,\n  uid: 0,\n  gid: 0,\n  size: 0,\n  offset: 0,\n  blocks: 0,\n  atime: 2017-04-10T18:59:00.147Z,\n  mtime: 2017-04-10T18:59:00.147Z,\n  ctime: 2017-04-10T18:59:00.147Z,\n  linkname: undefined }\n```\n\nThe output object includes methods similar to fs.stat:\n\n``` js\nvar stat = archive.stat('/hello.txt')\nstat.isDirectory()\nstat.isFile()\n```\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `await archive.lstat(name, [options])`\n\nStat an entry but do not follow symlinks. Similar to fs.lstat.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `await archive.access(name, [options])`\n\nSimilar to fs.access.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `const fd = await archive.open(name, flags, [mode])`\n\nOpen a file and get a file descriptor back. Similar to fs.open.\n\nNote that currently only read mode is supported in this API.\n\n#### `await archive.read(fd, buf, offset, len, position)`\n\nRead from a file descriptor into a buffer. Similar to fs.read.\n\n#### `await archive.close(fd)`\n\nClose a file. Similar to fs.close.\n\n#### `await archive.close()`\n\nCloses all open resources used by the archive.\nThe archive should no longer be used after calling this.\n\n#### `await archive.destroyData()`\n\nCloses all resources used by the archive, and destroys its data from storage.\nThe archive should no longer be used after calling this.\n\n### `const feed = Hypercore(keyOrName, opts)`\n\nInitializes a Hypercore (aka Feed) and begins replicating it.\n\n- `keyOrName`: This **must** be provided. It's either a Dat URL / key or a string identifying the name of the feed. If you want to have a writable feed, you can use the name to generate one and use the name later to get the same feed back without having to save the key somewhere.\n- `opts`: The options for configuring this feed\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n  - `secretKey`: The secret key to use for the feed. Useful for restoring from backups.\n\t- `discoveryKey`: Optionally specify which discovery key you'd like to use for finding peers for this feed.\n\t- `lookup: true`: Specify whether you wish to lookup peers for this feed. Set to `false` along with `announce` to avoid advertising.\n\t- `announce: true`: Specify whether you wish to advertise yourself as having the feed.\n\n#### `const seq = await feed.append(data)`\n\nAppend a block of data to the feed.\n\nCallback is called with `(err, seq)` when all data has been written at the returned `seq` or an error occurred.\n\n#### `const data = await feed.get(index, [options])`\n\nGet a block of data.\nIf the data is not available locally this method will prioritize and wait for the data to be downloaded before calling the callback.\n\nOptions include\n\n``` js\n{\n  wait: true, // wait for index to be downloaded\n  timeout: 0, // wait at max some milliseconds (0 means no timeout)\n  valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the feed's valueEncoding\n}\n```\n\nCallback is called with `(err, data)`\n\n#### `const results = await feed.getBatch(start, end, [options])`\n\nGet a range of blocks efficiently. Options include\n\n``` js\n{\n  wait: sameAsAbove,\n  timeout: sameAsAbove,\n  valueEncoding: sameAsAbove\n}\n```\n\n#### `const data = await feed.head([options])`\n\nGet the block of data at the tip of the feed. This will be the most recently\nappended block.\n\nAccepts the same `options` as `feed.get()`.\n\n#### `await feed.download([range])`\n\nDownload a range of data. Callback is called when all data has been downloaded.\nA range can have the following properties:\n\n``` js\n{\n  start: startIndex,\n  end: nonInclusiveEndIndex,\n  linear: false // download range linearly and not randomly\n}\n```\n\nIf you do not mark a range the entire feed will be marked for download.\n\nIf you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire\nfeed will be marked for download for you when the feed is created.\n\n#### `await feed.undownload(range)`\n\nCancel a previous download request.\n\n#### `const signature = await feed.signature([index])`\n\nGet a signature proving the correctness of the block at index, or the whole stream.\n\nCallback is called with `(err, signature)`.\nThe signature has the following properties:\n``` js\n{\n  index: lastSignedBlock,\n  signature: Buffer\n}\n```\n\n#### `const success = await feed.verify(index, signature)`\n\nVerify a signature is correct for the data up to index, which must be the last signed\nblock associated with the signature.\n\nCallback is called with `(err, success)` where success is true only if the signature is\ncorrect.\n\n#### `const roots = await feed.rootHashes(index)`\n\nRetrieve the root *hashes* for given `index`.\n\nCallback is called with `(err, roots)`; `roots` is an *Array* of *Node* objects:\n```\nNode {\n  index: location in the merkle tree of this root\n  size: total bytes in children of this root\n  hash: hash of the children of this root (32-byte buffer)\n}\n```\n\n\n#### `var number = feed.downloaded([start], [end])`\n\nReturns total number of downloaded blocks within range.\nIf `end` is not specified it will default to the total number of blocks.\nIf `start` is not specified it will default to 0.\n\n#### `var bool = feed.has(index)`\n\nReturn true if a data block is available locally.\nFalse otherwise.\n\n#### `var bool = feed.has(start, end)`\nReturn true if all data blocks within a range are available locally.\nFalse otherwise.\n\n#### `await feed.clear(start, [end])`\n\nClear a range of data from the local cache.\nWill clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.\n\n`end` defaults to `start + 1`.\n\n#### `feed.seek(byteOffset, callback)`\n\nSeek to a byte offset.\n\nCalls the callback with `(err, index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is\nthe relative byte offset in the data block.\n\n#### `await feed.update([minLength])`\n\nWait for the feed to contain at least `minLength` elements.\nIf you do not provide `minLength` it will be set to current length + 1.\n\nDoes not download any data from peers except for a proof of the new feed length.\n\n``` js\nconsole.log('length is', feed.length)\nfeed.update(function () {\n  console.log('length has increased', feed.length)\n})\n```\n\n#### `var stream = feed.createReadStream([options])`\n\nCreate a readable stream of data.\n\nOptions include:\n\n``` js\n{\n  start: 0, // read from this index\n  end: feed.length, // read until this index\n  snapshot: true, // if set to false it will update `end` to `feed.length` on every read\n  tail: false, // sets `start` to `feed.length`\n  live: false, // set to true to keep reading forever\n  timeout: 0, // timeout for each data event (0 means no timeout)\n  wait: true // wait for data to be downloaded\n}\n```\n\n#### `var stream = feed.createWriteStream()`\n\nCreate a writable stream.\n\n#### `await feed.close()`\n\nFully close this feed.\n\nCalls the callback with `(err)` when all storage has been closed.\n\n#### `await feed.destroyData()`\n\nCloses the feed and deletes all of it's data from storage.\n\n#### `const {valid, invalid} = await feed.audit()`\n\nAudit all data in the feed. Will check that all current data stored\nmatches the hashes in the merkle tree and clear the bitfield if not.\n\nWhen done a report is passed to the callback that looks like this:\n\n```js\n{\n  valid: 10, // how many data blocks matches the hashes\n  invalid: 0, // how many did not\n}\n```\n\nIf a block does not match the hash it is cleared from the data bitfield.\n\n#### `const extension = feed.registerExtension(name, handlers)`\n\nListens on extension messages of type `name` on the feeds replication channels.\n\n- `handlers.encoding`: The encoding to use for messages. `json`, `binary`, 'utf8'\n- `handlers.onmessage(message, peer)`: Function to invoke when a peer sends you a message for this extension type.\n- `handlers.onerror(err, peer)`: Function to invoke when a peer has sent you a mis-coded message on this extension.\n\nYou can respond to messages with `extension.send(message, peer)`.\n\n#### `feed.writable`\n\nCan we append to this feed?\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.readable`\n\nCan we read from this feed? After closing a feed this will be false.\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.key`\n\nBuffer containing the public key identifying this feed.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.discoveryKey`\n\nBuffer containing a key derived from the feed.key.\nIn contrast to `feed.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same feed, without leaking the feed key.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.length`\n\nHow many blocks of data are available on this feed?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.byteLength`\n\nHow much data is available on this feed in bytes?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.stats`\n\nReturn per-peer and total upload/download counts.\n\nThe returned object is of the form:\n```js\n{\n  totals: {\n    uploadedBytes: 100,\n    uploadedBlocks: 1,\n    downloadedBytes: 0,\n    downloadedBlocks: 0\n  },\n  peers: [\n    {\n      uploadedBytes: 100,\n      uploadedBlocks: 1,\n      downloadedBytes: 0,\n      downloadedBlocks: 0\n    },\n    ...\n  ]\n}\n```\n\nStats will be collected by default, but this can be disabled by setting `opts.stats` to false.\n\n#### `feed.on('ready')`\n\nEmitted when the feed is ready and all properties have been populated.\n\n#### `feed.on('error', err)`\n\nEmitted when the feed experiences a critical error.\n\n#### `feed.on('download', index, data)`\n\nEmitted when a data block has been downloaded.\n\n#### `feed.on('upload', index, data)`\n\nEmitted when a data block is uploaded.\n\n#### `feed.on('append')`\n\nEmitted when the feed has been appended to (i.e. has a new length / byteLength)\n\n#### `feed.on('sync')`\n\nEmitted every time ALL data from `0` to `feed.length` has been downloaded.\n\n#### `feed.on('close')`\n\nEmitted when the feed has been fully closed\n\n#### `feed.on('peer-add', peer)`\n\nEmitted when a new peer has started replicating with the feed.\n\n#### `feed.on('peer-remove', peer)`\n\nEmitted when a peer has stopped replicating with the feed.\n\n\n---\n\n[Dat Project]: https://dat.foundation\n","readmeFilename":"README.md","gitHead":"f47c4b983fcf4c639ca92418069b5b9f6081d15a","_id":"dat-sdk@2.0.0-7","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-KmhE7P7aKxEpEALeKWr5KSR2fU+CXfosq3RfqECvFfkKpNIthjB07+4r706GNmktPyVUlk37chkuVutOst1mVA==","shasum":"5d36fbfcbf648b7439843cce2e6300e0c1e5a653","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.0.0-7.tgz","fileCount":6,"unpackedSize":39466,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJetZryCRA9TVsSAnZWagAAv8oP/3HaHchpe/GeWbsGL6t5\nmfxbzoWRHmWm2rOoHtgK1zmxe56tcQzfa8NMIt8DHJVTWlNyqiqMXacuO+er\n39slIFnyqONsSK3XLE9tyfSBBLtfjp9wIj6Ej3joPmhWXFWZew6DeJlIC4AC\nlBaZ1/3g1MHN73deR2bjDziohyh2umm+iU4QI8nJELRV3G3acMWqJnMEi3Q+\n9JeQyEsTy2hRjmcFd0yWisvKUyNFm8t8b2CbuqnGDNI+bXVbdXUeIU32BvC0\nyNO/4w5FMc3741thbSt35PyujVLPh8NV3DMg5mkikz97Awi2ihAEgvTaTYMC\nv2V3Xmz82rSwPkCC6iSG/vZuU2gagl0EfVcprgaKPm5siNtI+zXi6zAquceA\nJuWjXe87IQ90Jl6OdrXjgX5Fk32LJjaXeLqPczxUjj2dX2zsOHhJuYOlHJ9t\nrI8Qj+2mxlCDzNUkKEjVF2zdhI6FXe8uQ77IUBw+13Eu6/EMY0AM93YMFF4/\nFvw8Ayc6sIGkldiTrLodC4j39E6SowShj1uunu2fWHDTC8v86FXaV1x6AIv6\nBOgj0IO6yuMOprmc+h6AYiemsfjrrQwwXWk+uTRAcvDRhkdVwBnRkpnI6SZS\nVTErIWOuK9s7WmaVttPK8XOaf1HU9WxCWHgzHt2R85LLSBQRsPOUBMKsiJmj\nSiDb\r\n=YoU2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHARYk8mjs/jcVT7ER5+I9T5XZl2Xtws519/S8yhlBbGAiEAz2cqAbYdCJcUZY/a2XY8P3DFU00thcl6zb275/oKokw="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.0.0-7_1588959985939_0.20806815124324296"},"_hasShrinkwrap":false},"2.0.0-8":{"name":"dat-sdk","version":"2.0.0-8","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^1.1.0","@geut/hyperdrive-promise":"^3.0.0","@geut/sodium-javascript-plus":"0.0.5","concat-stream":"^2.0.0","corestore":"^5.3.2","corestore-swarm-networking":"^5.4.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^9.0.0","hypercore-crypto":"^2.0.1","hypercore-protocol":"^8.0.0","hyperdrive":"^10.10.1","hyperswarm-web":"^1.0.2","node-localstorage":"^2.1.5","random-access-application":"^1.0.0","random-access-memory":"^3.1.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"readme":"# sdk\nThe official Dat SDK\n\n[<img src=\"https://datproject.github.io/design/downloads/dat-logo.png\" align=\"right\" width=\"140\">][Dat Project]\n\n## Why use this?\n\nDat consists of a bunch of low level building blocks for working with data in distributed applications. Although this modularity makes it easy to mix and match pieces, it adds complexity when it comes to actually building something.\n\nThe Dat SDK combines the lower level pieces of the Dat ecosystem into high level APIs that you can use across platforms so that you can focus on your application rather than the gritty details of how it works.\n\n## Goals\n\n- High level API\n- Cross-platform with same codebase\n  - ✔ Node\n  - ✔ Web\n  - ✔ Electron\n  - React-Native (with [nodejs-mobile-react-native?](https://github.com/janeasystems/nodejs-mobile-react-native))\n\n## Installing Node\n\n[Node.js](https://nodejs.org/) / [Browserify](http://browserify.org/) workflows:\n\n```shell\nnpm install --save dat-sdk@next\n```\n\n```js\nconst SDK = require('dat-sdk')\n```\n\n## Building a bundle for Browsers\n\n```shell\ngit clone git@github.com:datproject/sdk.git\n\ncd sdk\n\n# Compile the SDK into a single JS file\nnpm run build\n\n# Copy `dat-sdk-bundle.js` into your project\n```\n\n```html\n<script src=\"dat-sdk-bundle.js\"></script>\n<script>\n  const SDK = window.datSDK\n  // Look at the examples from here\n</script>\n```\n\n## Compile with Browserify\n\n```\nnpm install --save-dev browserify\nnpm install --save dat-sdk@next\n```\n\nAdd this as the `build` command in your package.json\n\n```shell\nbrowserify index.js > bundle.js\n```\n\nThen you can use `bundle.js` in your project.\n\n## Compile with Webpack (webpack.config.js)\n\nTo bundle with webpack, you'll need to alias some dependencies.\n\n```js\nconst path = require('path')\n\nmodule.exports = {\n  entry: './index.js',\n  target: 'web',\n  resolve: {\n    alias: {\n      fs: 'graceful-fs',\n      'sodium-native': '@geut/sodium-javascript-plus',\n      'sodium-universal': '@geut/sodium-javascript-plus',\n      hyperswarm: 'hyperswarm-web',\n      util: './node_modules/util/util.js'\n    }\n  },\n  output: {\n    filename: 'bundle.js',\n    path: path.resolve(__dirname, 'dist')\n  }\n}\n```\n\nThen you can include `./dist/bundle.js` in your HTML page.\n\n## API/Examples\n\n```js\nconst SDK = require('dat-sdk')\n\nconst sdk = await SDK();\nconst {\n\tHypercore,\n\tHyperdrive,\n\tresolveName,\n\tclose\n} = sdk\n\n// Create a new Hyperdrive.\n// If you want to create a new archive, pass in a name for it\n// This will be used to derive a secret key\n// Every time you open a drive with that name it'll derive the same key\n// This uses a master key that's generated once per device\n// That means the same name will yield a different key on a different machine\nconst archive = Hyperdrive('My archive name', {\n  // This archive will disappear after the process exits\n  // This is here so that running the example doesn't clog up your history\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  //storage: RAI\n})\n\n// You should wait for the archive to be totally initialized\nawait archive.ready()\n\nconst url = `dat://${archive.key.toString('hex')}`\n\n// TODO: Save this for later!\nconsole.log(`Here's your URL: ${url}`)\n\n// Check out the hyperdrive docs for what you can do with it\n// https://www.npmjs.com/package/hyperdrive#api\nawait archive.writeFile('/example.txt', 'Hello World!')\nconsole.log('Written example file!')\n\n// This example is currently broken because Beaker's website isn't on Dat 2 yet\nconst key = await resolveName('dat://beakerbrowser.com')\nconst archive = Hyperdrive(key)\nawait archive.download()\n// Pure all the data\nawait archive.destroyStorage()\n\nconst SOME_URL = 'dat://0a9e202b8055721bd2bc93b3c9bbc03efdbda9cfee91f01a123fdeaadeba303e/'\n\nconst someArchive = Hyperdrive(SOME_URL)\n\nconsole.log(await someArchive.readdir('/'))\n\n// Create a hypercore\n// Check out the hypercore docs for what you can do with it\n// https://github.com/mafintosh/hypercore\nconst myCore = Hypercore('my hypercore name', {\n  valueEncoding: 'json',\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  // storage: RAI\n})\n\n// Add some data to it\nawait myCore.append(JSON.stringify({\n  name: 'Alice'\n})\n\n// Use extension messages for sending extra data over the p2p connection\nconst discoveryCoreKey = 'dat://bee80ff3a4ee5e727dc44197cb9d25bf8f19d50b0f3ad2984cfe5b7d14e75de7'\nconst discoveryCore = new Hypercore(discoveryCoreKey)\n\n// Register the extension message handler\nconst extension = discoveryCore.registerExtension('discovery', {\n\t// Set the encoding type for messages\n\tencoding: 'binary',\n\tonmessage: (message, peer) => {\n\t\t// Recieved messages will be automatically decoded\n\t\tconsole.log('Got key from peer!', message)\n\n\t\tconst otherCore = new Hypercore(message, {\n      valueEncoding: 'json',\n      persist: false\n    })\n\n    // Render the peer's data from their core\n    otherCore.get(0, console.log)\n\t}\n})\n\n// When you find a peer tell them about your core\ndiscoveryCore.on('peer-add', (peer) => {\n\tconsole.log('Got a peer!')\n\textension.send(myCore.key, peer)\n})\n\nconst hypertrie = require('hypertrie')\n\n// Pass in hypercores from the SDK into other dat data structures\n// Check out what you can do with hypertrie from there:\n// https://github.com/mafintosh/hypertrie\nconst trie = hypertrie(null, {\n  feed: new Hypercore('my trie core', {\n    persist: false\n  })\n})\n\ntrie.put('key', 'value', () => {\n  trie.get('key', (err, node) => {\n    console.log('Got key: ', node.key)\n    console.log('Loaded value from trie: ', node.value)\n  })\n})\n\n```\n\n## API\n\nThe API supports both promises and callbacks. Everywhere where you see `await`, you can instead pass a node-style callback.\n\n### `const {Hypercore, Hyperdrive, resolveName, getIdentity, deriveSecret, close} = await SDK(opts?)`\n\nCreates an instance of the Dat SDK based on the options.\n\n- `opts.storage`: An optional [random-access-storage](https://github.com/random-access-storage/random-access-storage) instance for storing data.\n- `opts.applicationName`: An optional name for the application using the SDK. This will automatically silo your data from other applications using the SDK and will store it in the appropriate place using [random-access-application](https://github.com/RangerMauve/random-access-application/)\n- `opts.corestore`: An optional [Corestore](https://github.com/andrewosh/corestore) instance for using as hypercore storage.\n- `opts.corestoreOpts`: Options to pass into Corestore when it's initialized.\n- `opts.swarmOpts`: This lets you configure [hyperswarm](https://github.com/hyperswarm/hyperswarm) and [hyperswarm-web](https://github.com/RangerMauve/hyperswarm-web)\n  - `maxPeers`: The maximum number of connections to keep for this swarm.\n  - `ephemeral **NODE**`: Set to `false` if this is going to be in a long running process on a server. \n  - `bootstap **NODE**`: An array of addresses to use for the DHT bootstraping\n  - `webrtcBootstrap: ['https://geut-webrtc-signal.herokuapp.com/'] **BROWSER**`: The WebRTC bootstrap server list used by [discovery-swarm-webrtc](https://github.com/geut/discovery-swarm-webrtc)\n  - `wsProxy: 'wss://hyperswarm.mauve.moe' **BROWSER**`: The Websocket proxy used for [hyperswarm-proxy-ws](https://github.com/RangerMauve/hyperswarm-proxy-ws)\n- `opts.driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n- `opts.coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `opts.dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `await close()`\n\nThis closes all resources used by the SDK so you can safely end your process. `cb` will be invoked once resources are closed or if there's an error.\n\n### `const key = await resolveName(url)`\n\nResolve a DNS name to a Dat key.\n\n  - `url` is a Dat URL like `dat://dat.foundation`\n  - `key` will be the Dat key that you can pass to `hyperdrive`\n\n### `const {publicKey, secretKey} = await getIdentity()`\n\nThis gives you the public / private keypair used for the Noise protocol encryption when connecting to peers.\nYou can use this to identify peers in the network using `peer.remotePublicKey`\n\n### `const secret = await deriveSecret(namespace, name)`\n\nDerives a secret key based on the SDK's master key.\n`namespace` can be used to namespace different applications, and `name` is the name of the key you want.\nThis can be used as a seed for generating secure private keys without needing to store an extra key on disk.\n\n### `const archive = Hyperdrive(keyOrName, opts)`\n\nThis initializes a Hyperdrive (aka a Dat archive), the SDK will begin finding peers for it and will de-duplicate calls to initializing the same archive more than once.\n\n- `keyOrName`: This **must** be provided. It's either a Dat URL / key or a string identifying the name. If you want to have a writable archive, you can use the name to generate one and use the name later to get the same archive back without having to save the key somewhere.\n- `opts`: These are the options for configuring the hyperdrive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretKey`: A secret key for granting write access. This can be useful when restoring backups.\n\t- `discoveryKey`: Optionally specify which discovery key you'd like to use for finding peers for this archive.\n\t- `lookup: true`: Specify whether you wish to lookup peers for this archive. Set `false` along with `announce` to avoid advertising\n\t- `announce: true`: Specify whether you wish to advertise yourself as having the archive.\n\nThe rest of the Hyperdrive docs were taken from the [Hyperdrive README](https://github.com/mafintosh/hyperdrive/blob/v9/README.md). Note that we're wrapping over the APIs with [Hyperdrive-Promise](https://github.com/geut/hyperdrive-promise) so any callback methods can be `await`ed instead.\n\n#### `archive.version`\n\nGet the current version of the archive (incrementing number).\n\n#### `archive.key`\n\nThe public key identifying the archive.\n\n#### `archive.discoveryKey`\n\nA key derived from the public key that can be used to discovery other peers sharing this archive.\n\n#### `archive.writable`\n\nA boolean indicating whether the archive is writable.\n\n#### `archive.on('ready')`\n\nEmitted when the archive is fully ready and all properties has been populated.\n\n#### `archive.on('update')`\n\nEmitted when the archive has got a new change.\n\n#### `archive.on('error', err)`\n\nEmitted when a critical error during load happened.\n\n#### `archive.on('close')`\n\nEmitted when the archive has been closed\n\n#### `archive.on('peer-add', peer)`\n\nEmitted when a new peer has started replicating wiht the archive.\n\n#### `archive.on('peer-remove', peer)`\n\nEmitted when a peer has stopped replicating wit the archive.\n\n#### `var oldDrive = archive.checkout(version, [opts])`\n\nCheckout a readonly copy of the archive at an old version. Options are used to configure the `oldDrive`:\n\n```js\n{\n  metadataStorageCacheSize: 65536 // how many entries to use in the metadata hypercore's LRU cache\n  contentStorageCacheSize: 65536 // how many entries to use in the content hypercore's LRU cache\n  treeCacheSize: 65536 // how many entries to use in the append-tree's LRU cache\n}\n```\n\n#### `await archive.download([path])`\n\nDownload all files in path of current version.\nIf no path is specified this will download all files.\n\nYou can use this with `.checkout(version)` to download a specific version of the archive.\n\n``` js\narchive.checkout(version).download()\n```\n\n#### `var stream = archive.history([options])`\n\nGet a stream of all changes and their versions from this archive.\n\n#### `var stream = archive.createReadStream(name, [options])`\n\nRead a file out as a stream. Similar to fs.createReadStream.\n\nOptions include:\n\n``` js\n{\n  start: optionalByteOffset, // similar to fs\n  end: optionalInclusiveByteEndOffset, // similar to fs\n  length: optionalByteLength\n}\n```\n\n#### `const data = await archive.readFile(name, [options])`\n\nRead an entire file into memory. Similar to fs.readFile.\n\nOptions can either be an object or a string\n\nOptions include:\n```js\n{\n  encoding: string\n  cached: true|false // default: false\n}\n```\nor a string can be passed as options to simply set the encoding - similar to fs.\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `var stream = archive.createDiffStream(version, [options])`\n\nDiff this archive with another version. `version` can both be a version number of a checkout instance of the archive. The `data` objects looks like this\n\n``` js\n{\n  type: 'put' | 'del',\n  name: '/some/path/name.txt',\n  value: {\n    // the stat object\n  }\n}\n```\n\n#### `var stream = archive.createWriteStream(name, [options])`\n\nWrite a file as a stream. Similar to fs.createWriteStream.\nIf `options.cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `await archive.writeFile(name, buffer, [options])`\n\nWrite a file from a single buffer. Similar to fs.writeFile.\n\n#### `await archive.unlink(name)`\n\nUnlinks (deletes) a file. Similar to fs.unlink.\n\n#### `await archive.mkdir(name, [options])`\n\nExplictly create an directory. Similar to fs.mkdir\n\n#### `await archive.rmdir(name)`\n\nDelete an empty directory. Similar to fs.rmdir.\n\n#### `const names = await archive.readdir(name, [options])`\n\nLists a directory. Similar to fs.readdir.\n\nOptions include:\n\n``` js\n{\n    cached: true|false, // default: false\n}\n```\n\nIf `cached` is set to `true`, this function returns results from the local version of the archive’s append-tree. Default behavior is to fetch the latest remote version of the archive before returning list of directories.\n\n#### `const stat = await archive.stat(name, [options])`\n\nStat an entry. Similar to fs.stat. Sample output:\n\n```\nStat {\n  dev: 0,\n  nlink: 1,\n  rdev: 0,\n  blksize: 0,\n  ino: 0,\n  mode: 16877,\n  uid: 0,\n  gid: 0,\n  size: 0,\n  offset: 0,\n  blocks: 0,\n  atime: 2017-04-10T18:59:00.147Z,\n  mtime: 2017-04-10T18:59:00.147Z,\n  ctime: 2017-04-10T18:59:00.147Z,\n  linkname: undefined }\n```\n\nThe output object includes methods similar to fs.stat:\n\n``` js\nvar stat = archive.stat('/hello.txt')\nstat.isDirectory()\nstat.isFile()\n```\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `await archive.lstat(name, [options])`\n\nStat an entry but do not follow symlinks. Similar to fs.lstat.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `await archive.access(name, [options])`\n\nSimilar to fs.access.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `const fd = await archive.open(name, flags, [mode])`\n\nOpen a file and get a file descriptor back. Similar to fs.open.\n\nNote that currently only read mode is supported in this API.\n\n#### `await archive.read(fd, buf, offset, len, position)`\n\nRead from a file descriptor into a buffer. Similar to fs.read.\n\n#### `await archive.close(fd)`\n\nClose a file. Similar to fs.close.\n\n#### `await archive.close()`\n\nCloses all open resources used by the archive.\nThe archive should no longer be used after calling this.\n\n#### `await archive.destroyStorage()`\n\nCloses all resources used by the archive, and destroys its data from storage.\nThe archive should no longer be used after calling this.\n\n### `const feed = Hypercore(keyOrName, opts)`\n\nInitializes a Hypercore (aka Feed) and begins replicating it.\n\n- `keyOrName`: This **must** be provided. It's either a Dat URL / key or a string identifying the name of the feed. If you want to have a writable feed, you can use the name to generate one and use the name later to get the same feed back without having to save the key somewhere.\n- `opts`: The options for configuring this feed\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n  - `secretKey`: The secret key to use for the feed. Useful for restoring from backups.\n\t- `discoveryKey`: Optionally specify which discovery key you'd like to use for finding peers for this feed.\n\t- `lookup: true`: Specify whether you wish to lookup peers for this feed. Set to `false` along with `announce` to avoid advertising.\n\t- `announce: true`: Specify whether you wish to advertise yourself as having the feed.\n\n#### `const seq = await feed.append(data)`\n\nAppend a block of data to the feed.\n\nCallback is called with `(err, seq)` when all data has been written at the returned `seq` or an error occurred.\n\n#### `const data = await feed.get(index, [options])`\n\nGet a block of data.\nIf the data is not available locally this method will prioritize and wait for the data to be downloaded before calling the callback.\n\nOptions include\n\n``` js\n{\n  wait: true, // wait for index to be downloaded\n  timeout: 0, // wait at max some milliseconds (0 means no timeout)\n  valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the feed's valueEncoding\n}\n```\n\nCallback is called with `(err, data)`\n\n#### `const results = await feed.getBatch(start, end, [options])`\n\nGet a range of blocks efficiently. Options include\n\n``` js\n{\n  wait: sameAsAbove,\n  timeout: sameAsAbove,\n  valueEncoding: sameAsAbove\n}\n```\n\n#### `const data = await feed.head([options])`\n\nGet the block of data at the tip of the feed. This will be the most recently\nappended block.\n\nAccepts the same `options` as `feed.get()`.\n\n#### `await feed.download([range])`\n\nDownload a range of data. Callback is called when all data has been downloaded.\nA range can have the following properties:\n\n``` js\n{\n  start: startIndex,\n  end: nonInclusiveEndIndex,\n  linear: false // download range linearly and not randomly\n}\n```\n\nIf you do not mark a range the entire feed will be marked for download.\n\nIf you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire\nfeed will be marked for download for you when the feed is created.\n\n#### `await feed.undownload(range)`\n\nCancel a previous download request.\n\n#### `const signature = await feed.signature([index])`\n\nGet a signature proving the correctness of the block at index, or the whole stream.\n\nCallback is called with `(err, signature)`.\nThe signature has the following properties:\n``` js\n{\n  index: lastSignedBlock,\n  signature: Buffer\n}\n```\n\n#### `const success = await feed.verify(index, signature)`\n\nVerify a signature is correct for the data up to index, which must be the last signed\nblock associated with the signature.\n\nCallback is called with `(err, success)` where success is true only if the signature is\ncorrect.\n\n#### `const roots = await feed.rootHashes(index)`\n\nRetrieve the root *hashes* for given `index`.\n\nCallback is called with `(err, roots)`; `roots` is an *Array* of *Node* objects:\n```\nNode {\n  index: location in the merkle tree of this root\n  size: total bytes in children of this root\n  hash: hash of the children of this root (32-byte buffer)\n}\n```\n\n\n#### `var number = feed.downloaded([start], [end])`\n\nReturns total number of downloaded blocks within range.\nIf `end` is not specified it will default to the total number of blocks.\nIf `start` is not specified it will default to 0.\n\n#### `var bool = feed.has(index)`\n\nReturn true if a data block is available locally.\nFalse otherwise.\n\n#### `var bool = feed.has(start, end)`\nReturn true if all data blocks within a range are available locally.\nFalse otherwise.\n\n#### `await feed.clear(start, [end])`\n\nClear a range of data from the local cache.\nWill clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.\n\n`end` defaults to `start + 1`.\n\n#### `feed.seek(byteOffset, callback)`\n\nSeek to a byte offset.\n\nCalls the callback with `(err, index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is\nthe relative byte offset in the data block.\n\n#### `await feed.update([minLength])`\n\nWait for the feed to contain at least `minLength` elements.\nIf you do not provide `minLength` it will be set to current length + 1.\n\nDoes not download any data from peers except for a proof of the new feed length.\n\n``` js\nconsole.log('length is', feed.length)\nfeed.update(function () {\n  console.log('length has increased', feed.length)\n})\n```\n\n#### `var stream = feed.createReadStream([options])`\n\nCreate a readable stream of data.\n\nOptions include:\n\n``` js\n{\n  start: 0, // read from this index\n  end: feed.length, // read until this index\n  snapshot: true, // if set to false it will update `end` to `feed.length` on every read\n  tail: false, // sets `start` to `feed.length`\n  live: false, // set to true to keep reading forever\n  timeout: 0, // timeout for each data event (0 means no timeout)\n  wait: true // wait for data to be downloaded\n}\n```\n\n#### `var stream = feed.createWriteStream()`\n\nCreate a writable stream.\n\n#### `await feed.close()`\n\nFully close this feed.\n\nCalls the callback with `(err)` when all storage has been closed.\n\n#### `await feed.destroyStorage()`\n\nCloses the feed and deletes all of it's data from storage.\n\n#### `const {valid, invalid} = await feed.audit()`\n\nAudit all data in the feed. Will check that all current data stored\nmatches the hashes in the merkle tree and clear the bitfield if not.\n\nWhen done a report is passed to the callback that looks like this:\n\n```js\n{\n  valid: 10, // how many data blocks matches the hashes\n  invalid: 0, // how many did not\n}\n```\n\nIf a block does not match the hash it is cleared from the data bitfield.\n\n#### `const extension = feed.registerExtension(name, handlers)`\n\nListens on extension messages of type `name` on the feeds replication channels.\n\n- `handlers.encoding`: The encoding to use for messages. `json`, `binary`, 'utf8'\n- `handlers.onmessage(message, peer)`: Function to invoke when a peer sends you a message for this extension type.\n- `handlers.onerror(err, peer)`: Function to invoke when a peer has sent you a mis-coded message on this extension.\n\nYou can respond to messages with `extension.send(message, peer)`.\n\n#### `feed.writable`\n\nCan we append to this feed?\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.readable`\n\nCan we read from this feed? After closing a feed this will be false.\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.key`\n\nBuffer containing the public key identifying this feed.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.discoveryKey`\n\nBuffer containing a key derived from the feed.key.\nIn contrast to `feed.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same feed, without leaking the feed key.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.length`\n\nHow many blocks of data are available on this feed?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.byteLength`\n\nHow much data is available on this feed in bytes?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.stats`\n\nReturn per-peer and total upload/download counts.\n\nThe returned object is of the form:\n```js\n{\n  totals: {\n    uploadedBytes: 100,\n    uploadedBlocks: 1,\n    downloadedBytes: 0,\n    downloadedBlocks: 0\n  },\n  peers: [\n    {\n      uploadedBytes: 100,\n      uploadedBlocks: 1,\n      downloadedBytes: 0,\n      downloadedBlocks: 0\n    },\n    ...\n  ]\n}\n```\n\nStats will be collected by default, but this can be disabled by setting `opts.stats` to false.\n\n#### `feed.on('ready')`\n\nEmitted when the feed is ready and all properties have been populated.\n\n#### `feed.on('error', err)`\n\nEmitted when the feed experiences a critical error.\n\n#### `feed.on('download', index, data)`\n\nEmitted when a data block has been downloaded.\n\n#### `feed.on('upload', index, data)`\n\nEmitted when a data block is uploaded.\n\n#### `feed.on('append')`\n\nEmitted when the feed has been appended to (i.e. has a new length / byteLength)\n\n#### `feed.on('sync')`\n\nEmitted every time ALL data from `0` to `feed.length` has been downloaded.\n\n#### `feed.on('close')`\n\nEmitted when the feed has been fully closed\n\n#### `feed.on('peer-add', peer)`\n\nEmitted when a new peer has started replicating with the feed.\n\n#### `feed.on('peer-remove', peer)`\n\nEmitted when a peer has stopped replicating with the feed.\n\n\n---\n\n[Dat Project]: https://dat.foundation\n","readmeFilename":"README.md","gitHead":"146c192f8948eb2216d5561ababbc9efe67b5109","_id":"dat-sdk@2.0.0-8","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-zWx2WCFbrwYCd9j4lgGr6W9mI59oeXnTnuOQ8H+viccq1MYVMAruwbdT9MP7TZyyfjpdTGYrW4V7kJCl/ELXqQ==","shasum":"79a294dfc03e961edd2e3795fa71fba4dd361d3b","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.0.0-8.tgz","fileCount":6,"unpackedSize":39621,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJevI0WCRA9TVsSAnZWagAAiCEQAIR5ycTPUO1+2SZYldge\nM6j8YApwLyjoB9TVZiiOiGSQ+XflAI8J8xINY2CFOgwouYisfepUrxe4F+MX\nwF1Vhxnl0viOjHBOxWgQNqDTokd3MwrAX8rA5X+Yhw0wTtV4FWlVIJd5/X69\nSZn6i0baFr/DeeoU3tcEXi6lUi3iKxtia6OvdTUKUc4jHVqarzZdD6zOJuDQ\nb2wFXGqoBZjrbFCZcFQYFOqkvZZR0BchIDRmDgqR3lKMl5X6qZoDkCle+MIQ\nSS6fY4UpqD1yKLbA+CpEdDcWjeGNvfYYi5gbixgKIVdZQatLlXXrO8FO4ClE\nkD9ZhJx4H79lAP+iJvUk/BYG0iahyQwYYuIgFf1T+4dus0PSJJIpfGl84DkL\ndWuZFaI8bOB9YNpx4pyN5V/rqsH4ZduPgSe440WhzTINkvZgHrt2A1nb0mBg\nDhPJAFYQCfPApJHMcZbGMiuNlNp8ggHtqmjKU5x3PlxCwaemFiV10jNDGKlV\nqsXoDUjXUWAWmUnlcD4Crx43X5HhncjSGKjzFIh7NwhoJzCjwTOImsDF0hMK\nLXseZgOL11Yysjy0sbPg925vGdJ+9NRVyjr+2n4H0TV26lnlNJA0NUFdfa9B\nRVTzMwlvMtpEa8fAmMZsz6fyDJ7hEF95vEwHjPHSm0f4Sb9vwIkP9CsNsYYo\n0fhs\r\n=OHaT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE2nBVbqfJHJcreaVrowe43jKl6RtvDspphdulRqf6naAiEAgT90ik/FymYLp6qi43R0AzLm0ctsktw8d0L27vNXMJk="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.0.0-8_1589415189475_0.7949195224447159"},"_hasShrinkwrap":false},"2.0.0":{"name":"dat-sdk","version":"2.0.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^2.0.0","@geut/hyperdrive-promise":"^3.0.1","@geut/sodium-javascript-plus":"0.0.6","concat-stream":"^2.0.0","corestore":"^5.3.2","corestore-swarm-networking":"^5.4.2","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","dom-event-target":"^1.0.0","global":"^4.4.0","hex-to-32":"^2.0.0","hypercore":"^9.0.1","hypercore-crypto":"^2.1.0","hypercore-protocol":"^8.0.0","hyperdrive":"^10.11.0","hyperswarm-web":"^1.0.2","node-localstorage":"^2.1.5","random-access-application":"^1.0.0","random-access-memory":"^3.1.1","universal-localstorage":"^1.0.2","universal-prompt":"^1.0.0","url-parse":"^1.4.7"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"786cea2298658499d82f12e03878e45e05c0f404","_id":"dat-sdk@2.0.0","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-oBnJHipwyPua6xhD9sdE1y7Hu+K6rUjrZ9FTzcTHArJ8YndjpsNdIJvu8bchTxuxayrPkxR50TcKmuc2SEvjCA==","shasum":"80274334a73d794d6b0c40460464007dd9b0a04d","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.0.0.tgz","fileCount":6,"unpackedSize":39619,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJew/SaCRA9TVsSAnZWagAAomkP/15cmUCmXAhp9yJVa4MB\naPJww6CUsOhWvyoxXMDIOZ3qz+AP/BnNor2aWfGhjtcsWcF9nxj4/TtfxfP9\nGRO0uHI2hcMPFTywxKIIxnMIuKGbDRbhaxp9TZDIqdW5nhuM8ou7kjSjxlDV\nP7fz8Ae/yAtOtLJL28OxImIZq20aw1rcZFDKOFu5JBYswijAwNYWDxP9cng9\nI7nVj0/cvJ2Pi8oKFkzmiZ1wgUSCYMEpXWwUiDGjK1y7dyr7DxP4+iEQjszJ\ngv0Darpz6ayESD8GLfQF1lU9ApJJBkPq4sJWz817ZlVLrBo8oNKub7U1w/1O\nNwwJu3dIiwbwz5CoUCjhw/dasq0oS1LDd5AX1XT0OgbJSy+rpB8hJFWIrIAU\n5VfIu2zszIf9avd+/dgWlJu0ZdkaeI/NKg9mXefIIzqhl5aZscL7DAljBERy\nthDUUzWw/orUGW0csIacPDYQSQDV77RbeOGgEU3kZXqN/Csil0wLRrE1VMQ7\nvzVErSY1Qgs4U0dME0PEcqks2JDqP438RZTmO2p++uU3vvifvV2kkmdVrDdl\nc/H+FqagdHFvLdBpgARmlNu12DL1FCsWrEiANO0ziTllFidCQnW5lIXyRfW9\nrctJC+osH249YVPhp5InbigeyvxEwjEkoosmQvpgCqpp1BooZlLJ3Qiu8TcD\n2R/l\r\n=eJCi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCKqQoKWhtj02x4ZhfkITNFoWuNg9rjPDdudut8EqEVuQIhAMpIqWdtOr1oM0BKRD9BZPQomnVG3ku3mjvv10V6/GtL"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.0.0_1589900441364_0.8871950004540747"},"_hasShrinkwrap":false},"2.1.0":{"name":"dat-sdk","version":"2.1.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest corestore-swarm-networking@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^2.0.0","@geut/hyperdrive-promise":"^3.0.1","@geut/sodium-javascript-plus":"0.0.6","corestore":"^5.5.0","corestore-swarm-networking":"^5.5.1","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.2.2","hypercore-crypto":"^2.1.0","hypercore-protocol":"^8.0.0","hyperdrive":"^10.12.3","hyperswarm":"^2.14.0","hyperswarm-web":"^1.0.2","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"74d41281f9983f58c10b9d2afb4b060df9fefe08","_id":"dat-sdk@2.1.0","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-AZDKfCjSQu2Exb3J1P4MK2zg+zordeMbOmSCexKdMpKnOafin/nAbHoPQ/74JKi+PXKs4f66+mEmcoqAYla0sw==","shasum":"23af231f02b5f9d09f74d32977d14dec74326e2c","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.1.0.tgz","fileCount":6,"unpackedSize":39878,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe4+WtCRA9TVsSAnZWagAAlDYQAJySkGolUsyKUMOWtq04\nLKfWCJBDtlupSdUbwKAE+ETTi7sUMy8oM7qrkaUQGuEZ3CTOPcJk1jBA/Xfm\n7YWW7ITWdQ9P+2oREhkfSdGIXx7A+staWXaOmdyLaFV0rUYkiSxuFieSdKGv\nmxqQ+zsBYvwDNqSGxCPMcLRLiCjM1k5uq38Ukvp8bOkE5wYdWnVNDBzgX60C\nlxC9k2fdKdoVVnBtxa3d+KV6PSVFilqRXy8P5GrPVYzpRcgkhzEO6m4WzWDV\nFfLswSshYWJGNltsOtjqHwTr7WFiWB9wC1U3Y8mSwYZTheXNlLw58YZ2g5SI\nuplfrGbgzuEQXjKAyOpF4b0yxWx/4u4sgt6TpnK8syebF20eOX8KSbSusZmZ\nmOYrJf3EJtjN2eSA0LV+hKtkTrrzOxdqkz/ZjBmrY1Xu4NY506mcXsRab5qm\n3qWlNGB3vR3NAT+f21P+SdmZVStiPBjT3qRG4Kf5H8QgDTd557abYlXgznIL\nviEB7LWvesGVwk4lM+pnEkOlRTGcFtB1x+r5w3ju+foZkMUUSzDuDPHGOzVm\ncmgDXKowzWbLKBydJhe/I0J6y4cFR7THRDkERR3DCuE6Sfa0ZQjnN1bpoP4J\n2AabYKC5PpIeAitfGNlJ6qo7dCPgcOM1GAvhM5eicMPme3Dbv1SNGBx8pnGT\nZ2fG\r\n=Mzn+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCBapX6bJ028LHGrmeDHc5Ds5fQREZny8v+iMO8UJZtGQIgBblSiPSIZ04FMMgXTbmiWWZd7pyvRBPtaBLUhJo1AxI="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.1.0_1591993772395_0.7394895663094889"},"_hasShrinkwrap":false},"2.2.0":{"name":"dat-sdk","version":"2.2.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] --standalone datSDK index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest corestore-swarm-networking@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@geut/hypercore-promise":"^2.0.0","@geut/hyperdrive-promise":"^3.0.1","@geut/sodium-javascript-plus":"0.0.6","corestore":"^5.5.0","corestore-swarm-networking":"^5.5.1","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.4.1","hypercore-crypto":"^2.1.0","hypercore-protocol":"^8.0.0","hyperdrive":"^10.13.0","hyperswarm":"^2.14.0","hyperswarm-web":"^1.0.2","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"a07a53aa4625d1417dd2489fe4e45eb3e929eff8","_id":"dat-sdk@2.2.0","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-k2FkE8dXgeUPFZfbnnP+YrxxU++h/Clq6aHYlarDuXAVn+clUr34qlV2JtBDJjFjtraEo5y7amjAFBY3vVyyGw==","shasum":"ef9ab6f23139c2762eef20f7640f3ccb73ead196","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.2.0.tgz","fileCount":6,"unpackedSize":40498,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe+ndcCRA9TVsSAnZWagAATMIP/21j9QYwibQV6tqIFeEr\nhN43YT+po0cwrTHxtYYEKLXLITznQNk1+eNpqAehLtcp7aI2aEml8bSOw4ZP\n36e1k0hin30qNWbiQa3T6b1aL1tQd9mcmwj3ur7st4ycK4Mr0xUApM1/lfZ1\n1S6Bf9N8KwPhjxNxCvWSPKzpvKnaV536dKOtuO+Eoru2cL0Cwa9y4Ig/SxWQ\n9WJQzSv7HaGY2LZsWmLJ3kwf+ol+S8cq2Uh6ZOxO2Ku+ye2giz6QJ45Y1XO+\nttu39d1YhzLxm6SsCLQTqG64e2TVNPV38oB5z6rV82jlQJa4dZM0qxuVYzVP\npyxKIxyjHvIogh1hbHiTMrAnsV1MdcF2MBA4KGe39ISw7yHTg+9FAz2pTTR/\nHbQ3QS06JGspPbhsTrHlq3jt0BZSvKdinOnl6i0ZhfaK7UP/2SvrePWVjqay\nOsimiBe82AND3zpERcKBSqgt8KiSdHKxF2MhgDY6lgcqDAkYUaGfNRCZDXlH\neP/IhfawTlKc16SNGxCZMmynodJys6Hz5n8JZYzcDkZOMdsxvU3E68jAYIxq\nAUli/5yqMgCQBbXyljeNWIoYwd8/Em220OJCgwCFGs/bHv8rio9UNmySlgQZ\nMQ4yW3OcCQ4+QxNXBpYu0GuaytY0rjAV13kZOOra2iEf9GoOOol2SQYh6iTf\nqW5r\r\n=8DAB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDQ8v/H+sLrswBnk7+hOtc0m3ITFtcfHq5muJk1YHkWVQIhAJ68/pe/jJDHPrTfJeDGp9NhIAutMLJL/tkML3+P2zD9"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.2.0_1593472859487_0.818904473122319"},"_hasShrinkwrap":false},"2.3.0":{"name":"dat-sdk","version":"2.3.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] --standalone datSDK index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest @corestore/networker@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest hypercore-crypto@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@corestore/networker":"0.0.3","@geut/hypercore-promise":"^2.0.0","@geut/hyperdrive-promise":"^3.0.1","@geut/sodium-javascript-plus":"0.0.6","corestore":"^5.6.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.5.0","hypercore-crypto":"^2.1.1","hypercore-protocol":"^8.0.1","hyperdrive":"^10.13.0","hyperswarm":"^2.14.1","hyperswarm-web":"^1.0.2","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"13874ffe1e751f1ca879aee54ae944faed27d92e","_id":"dat-sdk@2.3.0","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-kv0GTlSFIETY6DJJYKgZkm/hBr1bY5PxTT7i1L1hSa7lRb/zG9uCXNTjYT0vYvdmGNfd4+x36QfwLMD+39uYKw==","shasum":"33405db7ddd008311f9615794e3129dd5438feda","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.3.0.tgz","fileCount":6,"unpackedSize":41497,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfB3ehCRA9TVsSAnZWagAAKD4P/i0iapm1Xo4WEwd6H9zV\nE0BhPu+l7arRK7ODSVxsqTzZd1EVVrxCljNVYL5tPAMRXpxTgSfo17Ea2A2f\nr87ZZKAWssB77qGsErFE7B8kIPbOQ2eSWTfchCHqV5IgywB77mAbnilozjtx\nEXJcRhKkukWRrthgpaWv3E9jX4LuEOlFQxziJe+rtXxRawk5KJzkdehaI1Ot\nRW6raH9rBgNPPuOymQAXD66KRBkh46hysjDajxlBtSFg9uFMMx4SavUH0wf9\neZ49fLgypxmEtywX/jVWWSvkVfTAKzB7muy1AaE0S3nY0janRNP1465gWMYo\nE9XWUhulYBx+8IHewPG5w0ZEFRac17spwYpvPpcfQ93RjINbjTVbPWZjnqh7\n2+4vpgv6ZSJY6PBt8VydnbrwTLKCVg7kvpKM4EKQZ53B8dasTKhjN0R3TgfB\nHOqO5PrHMpEAEenOltzthh8isiPsmcNMpgUa+bYqc3Ih+fe/ZkCYrRL1T42A\nqktW/TuZapibBOsrh2ClE4lLZQ4QKxVyV3wJlQeMhHbDJIgkQaeNPCRQ3eKL\nf3nooe9zKiK4W0tdX/h5EqskdyybeY4aaJbyguC7J9eZ0eHi6kkM5FIRK1t5\nZVh/v1tC97/Tl+keCA89crDomoXVMZ6AuNFFqaLdnBiEZeOJQEXlzsqWq/ek\n/gpf\r\n=3E+Q\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCQHrNXAZduB2OAa78NMz3IdbZBPLIEg9ePNBPDVznqOQIgOm79SPyvTRbCilcikLgO/M85IWNE3jBi1Mt/LnemMJg="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.3.0_1594324896702_0.7029412666419428"},"_hasShrinkwrap":false},"2.4.0":{"name":"dat-sdk","version":"2.4.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] --standalone datSDK index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest @corestore/networker@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest hypercore-crypto@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@corestore/networker":"0.0.3","@geut/hypercore-promise":"^2.0.0","@geut/hyperdrive-promise":"^3.0.1","@geut/sodium-javascript-plus":"0.0.6","corestore":"^5.6.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.5.0","hypercore-crypto":"^2.1.1","hypercore-protocol":"^8.0.1","hyperdrive":"^10.13.0","hyperswarm":"^2.14.1","hyperswarm-web":"^1.0.2","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"f96cc427d5ba8d730808c995a8435aea2bd77057","_id":"dat-sdk@2.4.0","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-r86WQGYRkYoor3ezhJV6NX/Qzg9i09ntn00xjJk9xaoxUpWjSKqKydqiXV5xxnJce0etd6UJCNNCy/SY8M/9bQ==","shasum":"240578de78588db92a363228b71780049accca3c","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.4.0.tgz","fileCount":6,"unpackedSize":41485,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfB8YCCRA9TVsSAnZWagAAX9AP/jCu8EwYsWL3K5YOR95M\n5kTEtUmve0j4aDWLamGfWqOQspikIPbRCr5XH87D3zBICafEIlAVUffi39Oq\nzgDfefZf8rJ15/LrHWKlaMiH4Tyr7O3RaxLuvxp+sSFXkiqJ5Dj4rUzJgihp\n2uuY/Dy4LVaboJcb9jgCxU3WnohwU95MsMJ/KjlMn7eGkzo3CwLM/+2jjfpa\nsIGZwyXHEanbZiZJziHtaCJ3wOs4cWE3cHke29i+g/d3Ugy5okuwjuCdwiLE\nlU/qsUQEf3fCYtEt3MdWGTWRA5uuPitbGGhzvl3LG65IF36L/xQwRVpsl8iz\nAsVAy1TlzHAOFFF2C2Ja43KK270jKnMYTIJ2WcwbGnlD4T2usel1Enzpa7IK\njF2aJuMPMEDF1Lq7/yFuYY0AHoPWkg3qCQY0az6QkQwnwABg55Jr3744RvZP\nP+5f7vsTuL0BnJU2zlLYWWFAPFGcn3xRAYafnWmBTKlEE5TQfCG5rhJHO+w7\nwHY+AhjyzZEhFW8Vuz4wJVQGjinEQpCOSX9R8G97iUlr6f0R+cflOu5vd+rt\nttsH0FlDBGJsu18bONHgoM+hc/ilPKQNCcLYGqKU6rSUPFfAdQsRaUiIDNq0\nTYh4wZPVAe3RHV31irhlDj0hStgMl8KQ0Bb3TQ5fDs8EQ3dOZQZxJIZKVwZJ\neDeQ\r\n=4eIj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDw4UL2uMD9pnfLFr2cdzwwB134QDcqFqmzICFXp8G2VAiEAqoj7acd4DmDWasOfVqXKw9/ndg2qO6Gst4XkCt7sWYg="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.4.0_1594344961788_0.07640296865313245"},"_hasShrinkwrap":false},"2.5.0":{"name":"dat-sdk","version":"2.5.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] --standalone datSDK index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest @corestore/networker@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest hypercore-crypto@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@corestore/networker":"0.0.3","@geut/hypercore-promise":"^2.0.0","@geut/hyperdrive-promise":"^3.0.1","@geut/sodium-javascript-plus":"0.0.6","corestore":"^5.6.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.5.0","hypercore-crypto":"^2.1.1","hypercore-protocol":"^8.0.1","hyperdrive":"^10.13.0","hyperswarm":"^2.14.1","hyperswarm-web":"^1.0.2","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"c10432dc2fe6b32a6a7b0d5891ae2d2dbfd352f1","_id":"dat-sdk@2.5.0","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-u8svd6xYuPoqDfCgeCaiZUhl4VpUjFoNj3EZoKFZDRHjs6VGdyEz85FtY+MbsxMrZkCf/d6OXe1zuFQRsmCiRg==","shasum":"20e26afccc8c11a9db0710a7b9f8ad159c525636","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.5.0.tgz","fileCount":6,"unpackedSize":41634,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfB8vOCRA9TVsSAnZWagAAgEgQAIjJjmP0vvl0WmEjYvDb\npTP6lMR4vU6wcidp7NiwBIS6SbM6PmWr5DnsHeZDLsuGluLNOR2XAkP1O0a8\nrVIXN5xHZEpPP642hqONNHRywcqvaly8mjEvMXB1QPV7u/ea14h7RKjdTUYA\n6u91KJpyc7rUsSgeggXXg5Uo2EF8rOWfaXJIHWUAzbk3t1wOi6hZwwj/Xh4J\n+ho+sgjHmc7QCuvVVFggcx3F7t1ExKmioYCQQfLMKUmcitWDW2PB+zmcCYeq\nwtDoc+9LCSGO4U58iyV5i/Xm4V7qHLRZiaCErDVXqz7hWiLK3ROFptYNLH5+\nhx8fau82yf470irnQKN8LrXIcD73dmyiIb58W2aellGgQUzGcvwyYd0NIM0W\nb8VrrV5HxSfaIlHTcCv1IWCKjhGWok+rkGazlyNC97ILIGzEGI/MDMftMU/N\nMpN7IK9xRR3g4yvz1u6OZNnArQ7ZEk2f1Wxvo4jLcOUflXNn8Q6NBZweuBow\nINZbPi3L+dVzPazI6ytVazoC0UycJsweO1fnPGya6csh5KWNGcMjtes/OR1x\nK9rp7PdVGZaBJTiuUcEPsuSWxgD7wwvQfPKwDoeE+r6tnms3MLFVXEmy6JL/\nqPNdhuQaLs8xo7+LKnXsNY09WVn/TxWDWWuSVCRSQxnD/QhlxJ9ZZCcPinc/\nxIyW\r\n=B9kB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCzu216sx9GUdwBnigN16VY5/oNxtXvMbe4MqtqMKnddgIhALcoa0nz2KF4TK3xZI4LpfX2bfkGI4rJKx3yHs+Vv7KQ"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.5.0_1594346445657_0.05077622976055185"},"_hasShrinkwrap":false},"2.6.0":{"name":"dat-sdk","version":"2.6.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] --standalone datSDK index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest @corestore/networker@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest hypercore-crypto@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@corestore/networker":"0.0.3","@geut/hypercore-promise":"^2.0.0","@geut/hyperdrive-promise":"^3.0.1","@geut/sodium-javascript-plus":"0.0.6","corestore":"^5.6.0","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.5.0","hypercore-crypto":"^2.1.1","hypercore-protocol":"^8.0.1","hyperdrive":"^10.13.0","hyperswarm":"^2.14.1","hyperswarm-web":"^1.0.2","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"6688469b51145aeb18fe437671fafe4c818a4d0e","_id":"dat-sdk@2.6.0","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-q0SRyUOb3obLOFrQjv9EvNO6BpXMbE6DCmx69EdXb2qIWJfzxMv8f8SEWQx+Dgk+k0YTVpED3zIuWKWjzmMmUw==","shasum":"4aa1a9c8de62ad62be065674f6dd2ddff388a88b","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.6.0.tgz","fileCount":6,"unpackedSize":41964,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfIF4CCRA9TVsSAnZWagAAKoUQAJ6zoRXCbB+dGelF23kI\nJxVv/T1Rfl2vsyA/Tp3t5T3UEDQ/1hcl6b3aYan1c+rmN66fHie8CKMPYOKl\nM6cFOCn9m3RoJkwfNitl64mK4O6OhBJ3lYpeGpLGCworIMWoa7DDkLPXkK86\nuPPVgmwQRUSmGRG2dZi1aVbms6ZYIBRr6NgknTCStywe+VozpeUV2aJ4+m2u\nlYO/SrFCjuIxpicwFYcDPHEP66Ae/WPK7V+Kr3FdGl7clVDsZAoiJRmPmCFO\nBMOBfG0TTeFeO4Su2YC95GpBUIElHsv2JcOCV1NIgNmLTjBfZ4iLuqS3mIbE\neBfKi1kSLLV0ek0mNOHTFewGTC+yk5XWS4lzVs6V/kSHYtoJePytNj8RnHpF\n2rHmLPaQCWJSY4sPorZCXi4tSmeYOc5yvbaCEVItKdzTuOxnrxKY6EfhJNMo\nh49unQJi+dFySRNzIDA7eH49mKyVqvdP1ERbo0H51cH0jL7VqM3cALEvqdTM\n9jsGjNYVQp9hTY9MPEs1MYUSlnPbQmNCp0adNyk0LXoOlV1xO3HlcfyvDJkS\n5L+t5RtEDkqiMmp4G3rpIIUCfCnGDJysshIIXz0nT9pGyYbawGRaI7I3JTOB\nHPRkRq7ulB0tZLnqZH7KaAXKM3Uy19Jll2CwdzBeXOwQQhy+niQqKm+WWB9H\ngSov\r\n=KPdr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFOBmBnRQx9abwTdfBnf58PXBEfjMJdJcUaYAbV4qSu2AiEA+Lboleq21ObgBoTdgw3jl4rrZfOM1WEpl3na8K+/D8A="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.6.0_1595956737389_0.050120339722343976"},"_hasShrinkwrap":false},"2.6.1":{"name":"dat-sdk","version":"2.6.1","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] --standalone datSDK index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest @corestore/networker@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest hypercore-crypto@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@corestore/networker":"^1.0.2","@geut/hypercore-promise":"^2.0.0","@geut/hyperdrive-promise":"^3.0.1","@geut/sodium-javascript-plus":"0.0.6","corestore":"^5.7.3","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.5.0","hypercore-crypto":"^2.1.1","hypercore-protocol":"^8.0.1","hyperdrive":"^10.16.2","hyperswarm":"^2.15.0","hyperswarm-web":"^1.0.2","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"f933d25b6c41c93969aeade3bcb2bfa57a877efe","_id":"dat-sdk@2.6.1","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-2natKOjhCT9iRjRUYR1RZBebbvYkzcxkbyeJvg30S0trWmlXc5pISL5lj3VB3cJQo/PolRvhiq8vpvNbs3kxeQ==","shasum":"a48d17cb84b35dcda54f99a104116d7d84c45ecd","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.6.1.tgz","fileCount":6,"unpackedSize":42113,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfIGbKCRA9TVsSAnZWagAAVIwQAIxMoVcqSKCRNsK1TVuk\n+3gNc9Sj1zwJVIc1puZwZuO/8PFzC7BC3xrMps+VFEGp7GvxuTDySv9akr7F\nZSOvknRwC0Xxy1zVHSi46UQBKgBS/dOx4ZJwajLdq/C0iXAtZMdS2/yGYk/C\n31j2V8MFLF/JrDCSv38Vds8DTBbHszNLB+PGVJ/WbcrO4M69iCgNy4zqdlpb\nwEmAzu9kPHKnRhqGadKWGpRKwHmyfHZgaieosxhqIhoHqxAeiNKkQDGkLt6X\nGHh4TCXRvCS2kNVUH2+/n6663sAZLTO8JtYM2/fxfQwoU3+q8KXaNFFG1GmV\nNwZYGlZFtuFaJdttVLh3rw3svSPO96S1YypMW1zxCZCzQJKYn+cRFy+hh/xz\nJwztQw8ezuIsSWkAjBkOoqUcHQfgENs4rARnbw8wqwGGA/+B+JiCaqVE83T/\na4inQExO++sOfpHJdTIMOBmxyx0/BFBZKZ/xXhADwNXFWYkCgXhUr6P1GCvS\ntCg/Fncdj6fRP5ku/CR29d6PMHdRbqKlF0bTN1mCR1pMLniX9eYpoSyGch1u\nVU9LfMzkypKeAStbY7/7qnDWrdEHIXZzBOaFL9KfRa2zUnlnRo+qQR4N01m5\nbCfwmqy2qxWHWNcKDSN8OHJwibEj4MWvHKvLinIS4S/Z0u5cyxzsg8yvGLBD\nfzj6\r\n=89hE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDgx7KlGCwawSu3IgzXrDYV39olm4NNtrMxbkJWYsFXmAIhAKv+vNxiP5hVyFa2I8DZMoXBKVu+5BQ8PTLUmW1YQ0Bg"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.6.1_1595958985420_0.3537144291652683"},"_hasShrinkwrap":false},"2.7.0":{"name":"dat-sdk","version":"2.7.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] --standalone datSDK index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest @corestore/networker@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest hypercore-crypto@latest @geut/hyperdrive-promise@latest @geut/hypercore-promise@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@corestore/networker":"^1.0.3","@geut/hypercore-promise":"^2.1.1","@geut/hyperdrive-promise":"^3.0.1","@geut/sodium-javascript-plus":"0.0.6","corestore":"^5.7.3","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.5.0","hypercore-crypto":"^2.1.1","hypercore-protocol":"^8.0.1","hyperdrive":"^10.17.0","hyperswarm":"^2.15.0","hyperswarm-web":"^1.0.2","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"1c25570d339b20a60a1793c3463453058ddb6597","_id":"dat-sdk@2.7.0","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-KMPNZx57qcgEgcn5ZEMUOUuKsuORD+Up8OYWUkn0NZ35/F/G1KnZSA3XQzTz7m+QxW7coi9/7oJq5JGV0HFrYg==","shasum":"530899330d1d82744bf83239973d1be5cafc0282","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.7.0.tgz","fileCount":6,"unpackedSize":42670,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfKzL8CRA9TVsSAnZWagAANS4P/0eHcDAoIGA5st1tsZha\nWBY7eyADl6DULsRsN0bH/ROIiULwUf7RkFZgP5cpN5CtlyJgvfrY93tRIJTy\nRm7oAK5BLrykQWGjkjovFbnv8Po5kEg0WNbCOh4vF2n3dMY7PDA+Rv52qADr\ncifWzGtjdAr3nUh6oLaBAegw/yrIbNLx5D0g+SBczm26FUXCEtKwXOwz8lLu\niR3oZKJngGPUxOt4J/xWMMimrSpeaUusLVJ2+BZjw4VNlpYWKnzSCCOjBawU\nfQkc83/EvBW7XO3cJ+as/pv3qfaGKvefw3YgWCmNjSq4DmIwuQTeXaTK6mIp\nnuMc4I2ols62dSBmZY8777i5W9GLwodC97fbq/BKpL76/yRgdcuGvRhM5qcm\nxCaUqyXIM2g01zQw6MXUgRr4MLfZC/z3hDw0p1nAaB8ZLujvOpKcbCaXzQWv\nki5enNnR5Pn/sJvzQeO6bqlinaHaov6YpvgTWP+LYRtI+43o4j95kqzC1VA7\n1HnnPvU16z2zcT/ZUY355A8kr7Xel1JjnpaGugqOApyH8JyyBs7Ub7eGmFzJ\nbM1dO5cQ0gUgJT9hhJjNv8WIOMd98Iy76jgcyysdzlN+1zpPWbU63t2nuxr+\nnfsOnQP/YF/nB3d8UYRBVI2mtbQUtRkHalKUFTY2ek5NRbrL61dHiwgHT6Fg\nWLHA\r\n=SuHi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD6H6ekv2EiKC65Jflt7EgebkjGAbeNN3MgyOjII5GxqwIgNO8Faiy96nrvPuXEHILwcBOIFvgIbs/p0BJ/tIyJftY="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.7.0_1596666620300_0.9816314575009599"},"_hasShrinkwrap":false},"2.7.1":{"name":"dat-sdk","version":"2.7.1","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] --standalone datSDK index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest @corestore/networker@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest hypercore-crypto@latest @geut/hyperdrive-promise@latest @geut/hypercore-promise@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@corestore/networker":"^1.0.3","@geut/hypercore-promise":"^2.1.1","@geut/hyperdrive-promise":"^3.1.0","@geut/sodium-javascript-plus":"0.0.6","corestore":"^5.7.3","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.5.0","hypercore-crypto":"^2.1.1","hypercore-protocol":"^8.0.1","hyperdrive":"^10.17.2","hyperswarm":"^2.15.0","hyperswarm-web":"^1.0.2","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"671297a722e8b409129e36df850e3c137d11c1b0","_id":"dat-sdk@2.7.1","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-eJBjDOXAVZvWTkKmV+tjdSzsXdSHAo7EdiaQ4i06rwJUhKq1PKc8Zd6363YBsncIXxWbomc6nDNrLMvEpf9G6A==","shasum":"806d16321cb2e05d2acca7d626599e8acb356bf4","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.7.1.tgz","fileCount":6,"unpackedSize":42670,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfVmLPCRA9TVsSAnZWagAAaAwP/0UzSYWiKcRPDpkwDE7I\n5NcnuQAA1xZdr5vcuTcDY1d6x0j8+LtBJp1NjFebHuIqkkGaEflh/bqlU5u8\nWlJ+kjJnc8xEQyMv4iMvaoyHGAcw9m+UMN5QLZF/3wP6GwCrXVdczhLVWgwP\nm8xXCLTR657McGb5IKZ3A61fbBKuS0taBCgJ9CKjV0NK47VBhVmeS840GBxW\nNq69HfABtj2II5f5xN1V3Qqhn2CWs6c+MJd+UtvHeqdFjiBpl/0NDA1HdW+0\nkjzs0qEYWpR6RHZfPj2M0uelhvw/qjU2AL4ulcoquXe8+6KXCN7O74J6E5ol\nv+9aHzUclUkr4Y4exyVz0d//9ImYnsyzCmr5NPDgq/dDq/KXIRdGjjiVHa6k\n5diJlU4c4UZYTYVM9c4RU11Ne+HhyGlP6BhjS8fe9YC75q5JTXy++Hv+zyda\nHQplQ3QFHCPzOuFuXq9iLdeH31YDADGfBw4+zmDSO9fVoZf4iRiGd398Sqc0\nxS2d3cVSPeUZ0NSyAIlvtgOWm0FZEYPl/BX3E9Q1Alemx6A32w6soGi+FfRX\nNus+G69WgvNvgZXLuqC+dU8paNYskqKRGrf64fMO/S/upPGE1Su9C1WgxkU5\nGlI/Pz8tsFUbwEiiD4UMoW2IqacfgFdP9TbWRW1R6C4ouqzbsIKrE5o4iNcj\nLmhf\r\n=rvzr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCQvoD6LE+F6ldgqrAy34f0cYDp4zaMd41hmwZF8xZmXAIhAN6WpdLNDIHYxNGjL2Bznx6/3WBuKKO0zOFhBnF7Lw4z"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.7.1_1599496910569_0.5149839794309452"},"_hasShrinkwrap":false},"2.8.0":{"name":"dat-sdk","version":"2.8.0","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] --standalone datSDK index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest @corestore/networker@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest hypercore-crypto@latest @geut/hyperdrive-promise@latest @geut/hypercore-promise@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web","sodium-native":"@geut/sodium-javascript-plus","sodium-universal":"@geut/sodium-javascript-plus"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@corestore/networker":"^1.0.3","@geut/hypercore-promise":"^2.1.1","@geut/hyperdrive-promise":"^3.1.0","corestore":"^5.7.3","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.5.4","hypercore-crypto":"^2.1.1","hypercore-protocol":"^8.0.4","hyperdrive":"^10.18.0","hyperswarm":"^2.15.2","hyperswarm-web":"^2.1.0","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"6f0f7e0064d46b94c6246ffb8d8db0a684890dc2","_id":"dat-sdk@2.8.0","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-Q7P5txVt+fMuTGFJk3tiIjA3l6PfDbj90TWBoCEgomujiwxthxLeakUVeNaQdG9w/QU0QF0MuUIZOn9vmJGd1A==","shasum":"e6b2c0f079a6e6e18cff4fda25b143b11bb9cf52","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.8.0.tgz","fileCount":6,"unpackedSize":43526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbphxCRA9TVsSAnZWagAAy1cP/1RR5Ge+a3N1W3T7DmA7\n98bSQo0+wrvcVGWMKibuldYTFU58kjjmVTa7G1HKO6mFMr2xjp5E6bMJsH+e\nGDOBuZx+PmIfpbUcIbwmfxhzhf6+zPbEqSugmujD9wofgeOfstNhxyD3eDor\ni+Ub8V0WYrRDY+BPdBXEqzI9xITw38QwIRN3VpRd2LEPoBCVfbLcBdvJ9idk\nxjeE44vDrMpo85BRdLIH+SrkzS//H/cskuHOoegt3gng1AWX/KDIPC5di68d\nKiICE7mg1iet318wQ/7d6sJGmWy/KeIT50nYm7C2ApaEOqGIilNunCLy2AJH\nqR5SDKamrZERicERcMN2R+sVu/7KUB1ReSNwR1TBExkL6hsdD0cuwnIwYU9P\nmQdPcRMaw5sz7giEkWVBB1BRdsTP4Hxj9bgAhJODjXdRXvTNW6HY7Q7Tc0Ij\n/fU7Ibc1UuJNAF173evyBdVpBCMWr2bH0WIXUl/UxmZAjZ0u8eNmbY45PbbS\nrNRxeU9GepjTYlgyhHaR4zytddc+fUURb6niTPsT6mHB6jBcYjJbfdQMYvSu\nmKWCvj6J5XoY1uss+Zx5besBCTZC80Y4Y9no8BoHTCibJU4HtGhKPeY5MfGe\n/c45aPDLFdnKBPgj7e0FEgIXMof+iOVaBfvmSGcGFuuDWiUmFZDfs0cavxCH\nsJ/H\r\n=DRoH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDlZryUCJ0Lzv8i1B6vvNOBXfkdD465w/2L5xn+nbZBBwIhANFY63YOG0l86hFsJWYcYu1nms4O12aZ/WHl+nvximMJ"}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.8.0_1601083504942_0.35345602250817487"},"_hasShrinkwrap":false},"2.8.1":{"name":"dat-sdk","version":"2.8.1","description":"The official Dat SDK","main":"index.js","scripts":{"test":"node test","build":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] --standalone datSDK index.js > dat-sdk-bundle.js","build-test":"cross-env BABEL_DISABLE_CACHE=1 browserify -t [ babelify --global ] -d test.js > test-bundle.js","update-deps":"npm install --save hyperswarm@latest @corestore/networker@latest hyperdrive@latest corestore@latest hypercore@latest hypercore-protocol@latest hypercore-crypto@latest @geut/hyperdrive-promise@latest @geut/hypercore-promise@latest"},"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"author":{"name":"datproject"},"license":"MIT","bugs":{"url":"https://github.com/datproject/sdk/issues"},"browser":{"dat-dns":"./dns-web.js","hyperswarm":"hyperswarm-web"},"browserify":{"transform":[["babelify",{"global":true}]]},"homepage":"https://github.com/datproject/sdk#readme","dependencies":{"@corestore/networker":"^1.0.3","@geut/hypercore-promise":"^2.1.1","@geut/hyperdrive-promise":"^3.1.0","corestore":"^5.7.3","dat-dns":"^4.0.0","dat-encoding":"^5.0.1","hypercore":"^9.5.4","hypercore-crypto":"^2.1.1","hypercore-protocol":"^8.0.4","hyperdrive":"^10.18.0","hyperswarm":"^2.15.2","hyperswarm-web":"^2.1.1","random-access-application":"^1.0.0","random-access-memory":"^3.1.1"},"devDependencies":{"@babel/core":"^7.9.0","babel-plugin-module-resolver":"^4.0.0","babelify":"^10.0.0","browserify":"^16.2.3","cross-env":"^7.0.2","random-access-file":"^2.1.3","tape":"^4.10.2","tmp":"^0.1.0","util":"^0.12.2"},"gitHead":"d706f344f95387b4717d199a57e423b8bfdfaaa4","_id":"dat-sdk@2.8.1","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-G0ML0RQWYeMwFij0trdD9vytmXJYBIEAXTvJ6rW+Wik0YjbpEqjkio+xtAPQxGJAo2kjgWpYx8l3oDETIxcyTQ==","shasum":"edc41c3a0fff82c6422798f99e55ec8adb668d74","tarball":"https://registry.npmjs.org/dat-sdk/-/dat-sdk-2.8.1.tgz","fileCount":6,"unpackedSize":43417,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbrSTCRA9TVsSAnZWagAAqlUP/iNvktgOVag7jr0PYv5p\nw2Tu7dhGKmBQJ1Wk699YlehQAqgg4zDdt4ucSFJjNSUE5bAUH7lkHagMisd8\nO84zHM5zrySBFR+iYvwOTJPxrEcSmsKRJwnN+gugi8aTMI05w1hg1RJSKQj1\nJIDt/VQetooymFLEoyRvwT6QZKix1KtXqcjs/rjFLN6gzam9XSbbsDDXojDx\nt0Deg/bbiGYHiOgoIF8jJorxrGfnwOLds973NCu2hBBqVDHV9IPmqStZa475\nEgvolTqeh7DJLsSLlXutnpC7XQvZaxoOF81FBiS8kbX1DUg4DP4LR/tB74Av\ntnsASaXDjTEkxJl+34yGG7j7YVFKSp6QIncnUseka56zpGwBsG9NqQ/DDVMS\nL345Wjw9aqMJaT/5E0aFEdRasBVyMnmUtcLo7Q0A33q9LYpKxv1Xi7vqBnAF\nJpK1WtCyzAXWIfAsqf9dWMGh8QC7L+nGBcbVi/3LLyJVK5doJWpi1Qye9qMz\nEbTOn5QG3Rfm9VBOfhFTHNAKNrB9mIW3uxhlzMir6Ll7NDcWLPxB6IbblvDu\n7Cjo7yvehwe7cQqOK0AqMd/2nlxoEkQebegoLNGkMgsfuePMaIyA9oGcJE2/\nApEUlZcBEBg+FXE/nTHNcqYlaX1+duu1AVUs1pJhNxGQkD0jzf3u3hDMVsWA\nfOnw\r\n=U9Oc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHuwGyug1HXkkgtUY0flxfc10cgoc7Fs1IZsmosMxlVtAiEA77JzoFAzyCeg5shzMW73eGwIUhGHCViNBnQ3O6d1pKM="}]},"maintainers":[{"name":"rangermauve","email":"rangermauve@hotmail.com"}],"_npmUser":{"name":"rangermauve","email":"rangermauve@hotmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dat-sdk_2.8.1_1601090707292_0.9801082719019536"},"_hasShrinkwrap":false}},"time":{"created":"2019-07-10T19:22:01.193Z","0.1.0":"2019-07-10T19:22:01.283Z","modified":"2022-04-28T04:41:23.189Z","0.2.0":"2019-08-08T19:52:48.752Z","0.2.1":"2019-08-16T16:55:17.415Z","0.2.2":"2019-08-19T19:33:41.741Z","0.3.0":"2019-08-27T20:35:51.308Z","0.3.1":"2019-08-31T03:51:42.931Z","0.3.2":"2019-09-13T18:08:17.667Z","0.3.3":"2019-10-07T15:30:13.586Z","0.3.4":"2019-10-10T16:41:40.519Z","0.3.5":"2019-11-02T16:18:27.698Z","0.3.6":"2019-11-06T20:34:54.829Z","1.0.0":"2020-01-26T20:39:52.290Z","1.0.1":"2020-01-28T20:30:22.016Z","1.0.2":"2020-02-06T19:24:04.067Z","2.0.0-0":"2020-02-11T01:15:55.717Z","2.0.0-1":"2020-02-11T18:39:20.775Z","2.0.0-2":"2020-02-11T19:41:47.533Z","2.0.0-3":"2020-02-19T04:50:43.378Z","1.0.3":"2020-02-24T22:17:00.418Z","2.0.0-4":"2020-03-09T18:40:18.160Z","2.0.0-5":"2020-04-11T22:21:31.059Z","2.0.0-6":"2020-04-14T22:31:27.272Z","2.0.0-7":"2020-05-08T17:46:26.102Z","2.0.0-8":"2020-05-14T00:13:09.684Z","2.0.0":"2020-05-19T15:00:41.508Z","2.1.0":"2020-06-12T20:29:32.738Z","2.2.0":"2020-06-29T23:20:59.693Z","2.3.0":"2020-07-09T20:01:36.865Z","2.4.0":"2020-07-10T01:36:01.932Z","2.5.0":"2020-07-10T02:00:45.779Z","2.6.0":"2020-07-28T17:18:57.587Z","2.6.1":"2020-07-28T17:56:25.768Z","2.7.0":"2020-08-05T22:30:20.488Z","2.7.1":"2020-09-07T16:41:50.685Z","2.8.0":"2020-09-26T01:25:05.135Z","2.8.1":"2020-09-26T03:25:07.439Z"},"maintainers":[{"email":"julian@juliangruber.com","name":"juliangruber"},{"email":"joe@hand.email","name":"jhand"},{"email":"zootella@zootella.com","name":"zootella"},{"email":"dev@serapath.de","name":"serapath"},{"email":"rangermauve@hotmail.com","name":"rangermauve"},{"email":"ninabreznik@gmail.com","name":"ninabreznik"},{"email":"angellus.falsus@gmail.com","name":"cblgh"},{"email":"dev@unbiskant.org","name":"frando"},{"email":"pfrazee@gmail.com","name":"pfrazee"},{"email":"diego@geutstudio.com","name":"the-real-dk"},{"email":"martin.heidegger@gmail.com","name":"leichtgewicht"}],"description":"The official Dat SDK","homepage":"https://github.com/datproject/sdk#readme","keywords":["dat","sdk","hyperdrive","hypercore","p2p"],"repository":{"type":"git","url":"git+https://github.com/datproject/sdk.git"},"author":{"name":"datproject"},"bugs":{"url":"https://github.com/datproject/sdk/issues"},"license":"MIT","readme":"# sdk\nThe official Dat SDK\n\n[<img src=\"https://datproject.github.io/design/downloads/dat-logo.png\" align=\"right\" width=\"140\">][Dat Project]\n\n## Why use this?\n\nDat consists of a bunch of low level building blocks for working with data in distributed applications. Although this modularity makes it easy to mix and match pieces, it adds complexity when it comes to actually building something.\n\nThe Dat SDK combines the lower level pieces of the Dat ecosystem into high level APIs that you can use across platforms so that you can focus on your application rather than the gritty details of how it works.\n\n## Goals\n\n- High level API\n- Cross-platform with same codebase\n  - ✔ Node\n  - ✔ Web\n  - ✔ Electron\n  - React-Native (with [nodejs-mobile-react-native?](https://github.com/janeasystems/nodejs-mobile-react-native))\n\n## Watch the workshop [Video](https://www.youtube.com/watch?v=HyHk4aImd_I&list=PL7sG5SCUNyeYx8wnfMOUpsh7rM_g0w_cu&index=20). Try it yourself: [workshop](https://github.com/RangerMauve/dat-workshop)\n\n## Installing Node\n\n[Node.js](https://nodejs.org/) / [Browserify](http://browserify.org/) workflows:\n\n```shell\nnpm install --save dat-sdk\n```\n\n```js\nconst SDK = require('dat-sdk')\n```\n\n## Building a bundle for Browsers\n\nThe easiest way to get started is to run the `build` command in this `sdk`, then copy the `bundle.js` into your own project. Here's how:\n\n```shell\ngit clone git@github.com:datproject/sdk.git\n\ncd sdk\n\n# Compile the SDK into a single JS file\nnpm run build\n\n# Copy `dat-sdk-bundle.js` into your project\n```\n\n```html\n<script src=\"dat-sdk-bundle.js\"></script>\n<script>\n  const SDK = window.datSDK\n  // Look at the examples from here\n</script>\n```\n\n## Compile with Browserify\n\nIf the bundle above doesn't work for your setup, and you want to DIY in your own project, you'll need to mimic how the SDK generates the bundle, using:\n\n- [x] Browserify\n- [x] Babelify (babel for browserify)\n- [x] babel.config.json file\n\nCombine [Browserify](http://browserify.org/) with [Babel](https://babeljs.io/) (via [Babelify](https://www.npmjs.com/package/babelify)) to make this work in the browser:\n\n**Dev** Dependencies (*must* be a DevDependency):\n\n```\nnpm install --save-dev browserify babelify util \n```\nand the regular dependencies\n```\nnpm install --save dat-sdk@next @geut/sodium-javascript-plus hyperswarm-web\n```\n\nAdd this as the `build` command in your `package.json`. It is important to add the transform (`-t`) with `babelify` to make it work. Babel will use the aliases in the [babel.config.json](https://github.com/datproject/sdk/blob/master/babel.config.json) file to change the code from nodejs to browser.\n\n```shell\n\"build\": \"browserify -t [ babelify --global ] index.js > bundle.js\"\n```\n\nOnce you `npm run build` then you can use the generated `bundle.js` in your project!\n\n## Compile with Webpack (webpack.config.js)\n\nTo bundle with webpack, you'll need to alias some dependencies.\n\n```js\nconst path = require('path')\n\nmodule.exports = {\n  entry: './index.js',\n  target: 'web',\n  resolve: {\n    alias: {\n      fs: 'graceful-fs',\n      'sodium-native': '@geut/sodium-javascript-plus',\n      'sodium-universal': '@geut/sodium-javascript-plus',\n      hyperswarm: 'hyperswarm-web',\n      util: './node_modules/util/util.js'\n    }\n  },\n  output: {\n    filename: 'bundle.js',\n    path: path.resolve(__dirname, 'dist')\n  }\n}\n```\n\nThen you can include `./dist/bundle.js` in your HTML page.\n\n## API/Examples\n\n```js\nconst SDK = require('dat-sdk')\n\nconst sdk = await SDK();\nconst {\n\tHypercore,\n\tHyperdrive,\n\tresolveName,\n\tclose\n} = sdk\n\n// Create a new Hyperdrive.\n// If you want to create a new archive, pass in a name for it\n// This will be used to derive a secret key\n// Every time you open a drive with that name it'll derive the same key\n// This uses a master key that's generated once per device\n// That means the same name will yield a different key on a different machine\nconst archive = Hyperdrive('My archive name', {\n  // This archive will disappear after the process exits\n  // This is here so that running the example doesn't clog up your history\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  //storage: RAI\n})\n\n// You should wait for the archive to be totally initialized\nawait archive.ready()\n\nconst url = `dat://${archive.key.toString('hex')}`\n\n// TODO: Save this for later!\nconsole.log(`Here's your URL: ${url}`)\n\n// Check out the hyperdrive docs for what you can do with it\n// https://www.npmjs.com/package/hyperdrive#api\nawait archive.writeFile('/example.txt', 'Hello World!')\nconsole.log('Written example file!')\n\n// This example is currently broken because Beaker's website isn't on Dat 2 yet\nconst key = await resolveName('dat://beakerbrowser.com')\nconst archive = Hyperdrive(key)\nawait archive.download()\n// Pure all the data\nawait archive.destroyStorage()\n\nconst SOME_URL = 'dat://0a9e202b8055721bd2bc93b3c9bbc03efdbda9cfee91f01a123fdeaadeba303e/'\n\nconst someArchive = Hyperdrive(SOME_URL)\n\nconsole.log(await someArchive.readdir('/'))\n\n// Create a hypercore\n// Check out the hypercore docs for what you can do with it\n// https://github.com/mafintosh/hypercore\nconst myCore = Hypercore('my hypercore name', {\n  valueEncoding: 'json',\n  persist: false,\n  // storage can be set to an instance of `random-access-*`\n  // const RAI = require('random-access-idb')\n  // otherwise it defaults to `random-access-web` in the browser\n  // and `random-access-file` in node\n  storage: null  // storage: RAI\n})\n\n// Add some data to it\nawait myCore.append(JSON.stringify({\n  name: 'Alice'\n}))\n\n// Use extension messages for sending extra data over the p2p connection\nconst discoveryCoreKey = 'dat://bee80ff3a4ee5e727dc44197cb9d25bf8f19d50b0f3ad2984cfe5b7d14e75de7'\nconst discoveryCore = new Hypercore(discoveryCoreKey)\n\n// Register the extension message handler\nconst extension = discoveryCore.registerExtension('discovery', {\n\t// Set the encoding type for messages\n\tencoding: 'binary',\n\tonmessage: (message, peer) => {\n\t\t// Recieved messages will be automatically decoded\n\t\tconsole.log('Got key from peer!', message)\n\n\t\tconst otherCore = new Hypercore(message, {\n      valueEncoding: 'json',\n      persist: false\n    })\n\n    // Render the peer's data from their core\n    otherCore.get(0, console.log)\n\t}\n})\n\n// When you find a peer tell them about your core\ndiscoveryCore.on('peer-add', (peer) => {\n\tconsole.log('Got a peer!')\n\textension.send(myCore.key, peer)\n})\n\nconst hypertrie = require('hypertrie')\n\n// Pass in hypercores from the SDK into other dat data structures\n// Check out what you can do with hypertrie from there:\n// https://github.com/mafintosh/hypertrie\nconst trie = hypertrie(null, {\n  feed: new Hypercore('my trie core', {\n    persist: false\n  })\n})\n\ntrie.put('key', 'value', () => {\n  trie.get('key', (err, node) => {\n    console.log('Got key: ', node.key)\n    console.log('Loaded value from trie: ', node.value)\n  })\n})\n\n```\n\n## API\n\nThe API supports both promises and callbacks. Everywhere where you see `await`, you can instead pass a node-style callback.\n\n### `const {Hypercore, Hyperdrive, resolveName, keyPair, deriveSecret, registerExtension, close} = await SDK(opts?)`\n\nCreates an instance of the Dat SDK based on the options.\n\n- `opts.applicationName`: An optional name for the application using the SDK. This will automatically silo your data from other applications using the SDK and will store it in the appropriate place using [random-access-application](https://github.com/RangerMauve/random-access-application/)\n- `opts.persist: true`: An optional arg for whether data should be persisted. Set this to `false` if you want stuff stored in memory. Ignored if you pass in a custom storage or corestore.\n- `opts.storage`: An optional [random-access-storage](https://github.com/random-access-storage/random-access-storage) instance for storing data.\n- `opts.corestore`: An optional [Corestore](https://github.com/andrewosh/corestore) instance for using as hypercore storage.\n- `opts.corestoreOpts`: Options to pass into Corestore when it's initialized.\n- `opts.swarmOpts`: This lets you configure [hyperswarm](https://github.com/hyperswarm/hyperswarm) and [hyperswarm-web](https://github.com/RangerMauve/hyperswarm-web)\n  - `maxPeers`: The maximum number of connections to keep for this swarm.\n  - `ephemeral **Node**`: Set to `false` if this is going to be in a long running process on a server. \n  - `bootstap **Node**`: An array of addresses to use for the DHT bootstraping. Defaults to `['bootstrap1.hyperdht.org:49737', 'bootstrap2.hyperdht.org:49737', 'bootstrap3.hyperdht.org:49737']`\n  - `preferredPort: 42666 **Node**`: The port hyperswarm should try to bind on. You should allow it through your firewall on TCP/UDP for best results. \n  - `webrtcBootstrap **Browser**: ['https://geut-webrtc-signal.herokuapp.com/'] **BROWSER**`: The WebRTC bootstrap server list used by [discovery-swarm-webrtc](https://github.com/geut/discovery-swarm-webrtc)\n  - `wsProxy **Browser**: 'wss://hyperswarm.mauve.moe' **BROWSER**`: The Websocket proxy used for [hyperswarm-proxy-ws](https://github.com/RangerMauve/hyperswarm-proxy-ws)\n- `opts.driveOpts`: This lets you configure the behavior of [Hyperdrive](https://github.com/mafintosh/hyperdrive) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n- `opts.coreOpts`: This lets you configure the behavior of [Hypercore](https://github.com/mafintosh/hypercore) instances\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `extensions`: The set of extension message types to use with this feed when replicating.\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n- `opts.dnsOpts`: Configure the [dat dns](https://github.com/datprotocol/dat-dns) resolution module. You probably shouldn't mess with this.\n  - `recordName: 'dat'`: name of .well-known file\n  - `protocolRegex: /^dat:\\/\\/([0-9a-f]{64})/i`: RegExp object for custom protocol\n  - `hashRegex: /^[0-9a-f]{64}?$/i`: RegExp object for custom hash i.e.\n  - `txtRegex: /\"?datkey=([0-9a-f]{64})\"?/i`: RegExp object for DNS TXT record of custom protocol\n\n### `await close()`\n\nThis closes all resources used by the SDK so you can safely end your process. `cb` will be invoked once resources are closed or if there's an error.\n\n### `const key = await resolveName(url)`\n\nResolve a DNS name to a Dat key.\n\n  - `url` is a Dat URL like `dat://dat.foundation`\n  - `key` will be the Dat key that you can pass to `hyperdrive`\n\n### `const {publicKey, secretKey} = keyPair`\n\nThis gives you the public / private keypair used for the Noise protocol encryption when connecting to peers.\nYou can use this to identify peers in the network using `peer.remotePublicKey`\n\n### `const secret = await deriveSecret(namespace, name)`\n\nDerives a secret key based on the SDK's master key.\n`namespace` can be used to namespace different applications, and `name` is the name of the key you want.\nThis can be used as a seed for generating secure private keys without needing to store an extra key on disk.\n\n### `const extension = registerExtension(name, handlers)`\n\nListens on extension messages of type `name` on the feeds replication channels.\n\n- `handlers.encoding`: The encoding to use for messages. `json`, `binary`, 'utf8'\n- `handlers.onmessage(message, peer)`: Function to invoke when a peer sends you a message for this extension type.\n- `handlers.onerror(err, peer)`: Function to invoke when a peer has sent you a mis-coded message on this extension.\n\nYou can respond to messages with `extension.send(message, peer)`.\nYou can also broadcast out messages to all peers with `extension.broadcast(message)`\n\n### `const archive = Hyperdrive(keyOrName, opts)`\n\nThis initializes a Hyperdrive (aka a Dat archive), the SDK will begin finding peers for it and will de-duplicate calls to initializing the same archive more than once.\n\n- `keyOrName`: This **must** be provided. It's either a Dat URL / key or a string identifying the name. If you want to have a writable archive, you can use the name to generate one and use the name later to get the same archive back without having to save the key somewhere.\n- `opts`: These are the options for configuring the hyperdrive.\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory archives\n  - `secretKey`: A secret key for granting write access. This can be useful when restoring backups.\n\t- `discoveryKey`: Optionally specify which discovery key you'd like to use for finding peers for this archive.\n\t- `lookup: true`: Specify whether you wish to lookup peers for this archive. Set `false` along with `announce` to avoid advertising\n\t- `announce: true`: Specify whether you wish to advertise yourself as having the archive.\n\nThe rest of the Hyperdrive docs were taken from the [Hyperdrive README](https://github.com/mafintosh/hyperdrive/blob/v9/README.md). Note that we're wrapping over the APIs with [Hyperdrive-Promise](https://github.com/geut/hyperdrive-promise) so any callback methods can be `await`ed instead.\n\n#### `archive.version`\n\nGet the current version of the archive (incrementing number).\n\n#### `archive.key`\n\nThe public key identifying the archive.\n\n#### `archive.discoveryKey`\n\nA key derived from the public key that can be used to discovery other peers sharing this archive.\n\n#### `archive.writable`\n\nA boolean indicating whether the archive is writable.\n\n#### `archive.on('ready')`\n\nEmitted when the archive is fully ready and all properties has been populated.\n\n#### `archive.on('update')`\n\nEmitted when the archive has got a new change.\n\n#### `archive.on('error', err)`\n\nEmitted when a critical error during load happened.\n\n#### `archive.on('close')`\n\nEmitted when the archive has been closed\n\n#### `archive.on('peer-add', peer)`\n\nEmitted when a new peer has started replicating wiht the archive.\n\n#### `archive.on('peer-remove', peer)`\n\nEmitted when a peer has stopped replicating wit the archive.\n\n#### `var oldDrive = archive.checkout(version, [opts])`\n\nCheckout a readonly copy of the archive at an old version. Options are used to configure the `oldDrive`:\n\n```js\n{\n  metadataStorageCacheSize: 65536 // how many entries to use in the metadata hypercore's LRU cache\n  contentStorageCacheSize: 65536 // how many entries to use in the content hypercore's LRU cache\n  treeCacheSize: 65536 // how many entries to use in the append-tree's LRU cache\n}\n```\n\n#### `await archive.download([path])`\n\nDownload all files in path of current version.\nIf no path is specified this will download all files.\n\nYou can use this with `.checkout(version)` to download a specific version of the archive.\n\n``` js\narchive.checkout(version).download()\n```\n\n#### `await archive.clear(path)`\n\nClear the storage of all files in the path.\nThis is the opposite of the `download` API.\nNote that this doesn't delete the files from history, just clears the data locally.\n\nYou can use this with `.checkout(version)` to clear a specific version of the archive.\n\n#### `var stream = archive.history([options])`\n\nGet a stream of all changes and their versions from this archive.\n\n#### `var stream = archive.createReadStream(name, [options])`\n\nRead a file out as a stream. Similar to fs.createReadStream.\n\nOptions include:\n\n``` js\n{\n  start: optionalByteOffset, // similar to fs\n  end: optionalInclusiveByteEndOffset, // similar to fs\n  length: optionalByteLength\n}\n```\n\n#### `const data = await archive.readFile(name, [options])`\n\nRead an entire file into memory. Similar to fs.readFile.\n\nOptions can either be an object or a string\n\nOptions include:\n```js\n{\n  encoding: string\n  cached: true|false // default: false\n}\n```\nor a string can be passed as options to simply set the encoding - similar to fs.\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `var stream = archive.createDiffStream(version, [options])`\n\nDiff this archive with another version. `version` can both be a version number of a checkout instance of the archive. The `data` objects looks like this\n\n``` js\n{\n  type: 'put' | 'del',\n  name: '/some/path/name.txt',\n  value: {\n    // the stat object\n  }\n}\n```\n\n#### `var stream = archive.createWriteStream(name, [options])`\n\nWrite a file as a stream. Similar to fs.createWriteStream.\nIf `options.cached` is set to `true`, this function returns results only if they have already been downloaded.\n\n#### `await archive.writeFile(name, buffer, [options])`\n\nWrite a file from a single buffer. Similar to fs.writeFile.\n\n#### `await archive.unlink(name)`\n\nUnlinks (deletes) a file. Similar to fs.unlink.\n\n#### `await archive.mkdir(name, [options])`\n\nExplictly create an directory. Similar to fs.mkdir\n\n#### `await archive.rmdir(name)`\n\nDelete an empty directory. Similar to fs.rmdir.\n\n#### `const names = await archive.readdir(name, [options])`\n\nLists a directory. Similar to fs.readdir.\n\nOptions include:\n\n``` js\n{\n    cached: true|false, // default: false\n}\n```\n\nIf `cached` is set to `true`, this function returns results from the local version of the archive’s append-tree. Default behavior is to fetch the latest remote version of the archive before returning list of directories.\n\n#### `const stat = await archive.stat(name, [options])`\n\nStat an entry. Similar to fs.stat. Sample output:\n\n```\nStat {\n  dev: 0,\n  nlink: 1,\n  rdev: 0,\n  blksize: 0,\n  ino: 0,\n  mode: 16877,\n  uid: 0,\n  gid: 0,\n  size: 0,\n  offset: 0,\n  blocks: 0,\n  atime: 2017-04-10T18:59:00.147Z,\n  mtime: 2017-04-10T18:59:00.147Z,\n  ctime: 2017-04-10T18:59:00.147Z,\n  linkname: undefined }\n```\n\nThe output object includes methods similar to fs.stat:\n\n``` js\nvar stat = archive.stat('/hello.txt')\nstat.isDirectory()\nstat.isFile()\n```\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `await archive.lstat(name, [options])`\n\nStat an entry but do not follow symlinks. Similar to fs.lstat.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `await archive.access(name, [options])`\n\nSimilar to fs.access.\n\nOptions include:\n```js\n{\n  cached: true|false // default: false,\n  wait: true|false // default: true\n}\n```\n\nIf `cached` is set to `true`, this function returns results only if they have already been downloaded.\n\nIf `wait` is set to `true`, this function will wait for data to be downloaded. If false, will return an error.\n\n#### `const fd = await archive.open(name, flags, [mode])`\n\nOpen a file and get a file descriptor back. Similar to fs.open.\n\nNote that currently only read mode is supported in this API.\n\n#### `await archive.read(fd, buf, offset, len, position)`\n\nRead from a file descriptor into a buffer. Similar to fs.read.\n\n#### `await archive.close(fd)`\n\nClose a file. Similar to fs.close.\n\n#### `await archive.close()`\n\nCloses all open resources used by the archive.\nThe archive should no longer be used after calling this.\nIf you load this hyperdrive's key more than once at once, `close()` will be a noop until all handles invoke it.\n\n#### `await archive.destroyStorage()`\n\nCloses all resources used by the archive, and destroys its data from storage.\nThe archive should no longer be used after calling this.\n\n### `const feed = Hypercore(keyOrName, opts)`\n\nInitializes a Hypercore (aka Feed) and begins replicating it.\n\n- `keyOrName`: This **must** be provided. It's either a Dat URL / key or a string identifying the name of the feed. If you want to have a writable feed, you can use the name to generate one and use the name later to get the same feed back without having to save the key somewhere.\n- `opts`: The options for configuring this feed\n  - `sparse: true`: Whether the history should be loaded on the fly instead of replicating the full history\n  - `persist: true`: Whether the data should be persisted to storage. Set to false to create in-memory feeds\n  - `valueEncoding: 'json' | 'utf-8' | 'binary'`: The encoding to use for the data stored in the hypercore. Use JSON to store / retrieve objects.\n  - `secretKey`: The secret key to use for the feed. Useful for restoring from backups.\n\t- `discoveryKey`: Optionally specify which discovery key you'd like to use for finding peers for this feed.\n\t- `lookup: true`: Specify whether you wish to lookup peers for this feed. Set to `false` along with `announce` to avoid advertising.\n\t- `announce: true`: Specify whether you wish to advertise yourself as having the feed.\n\n#### `const seq = await feed.append(data)`\n\nAppend a block of data to the feed.\n\nCallback is called with `(err, seq)` when all data has been written at the returned `seq` or an error occurred.\n\n#### `const data = await feed.get(index, [options])`\n\nGet a block of data.\nIf the data is not available locally this method will prioritize and wait for the data to be downloaded before calling the callback.\n\nOptions include\n\n``` js\n{\n  wait: true, // wait for index to be downloaded\n  timeout: 0, // wait at max some milliseconds (0 means no timeout)\n  valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the feed's valueEncoding\n}\n```\n\nCallback is called with `(err, data)`\n\n#### `const results = await feed.getBatch(start, end, [options])`\n\nGet a range of blocks efficiently. Options include\n\n``` js\n{\n  wait: sameAsAbove,\n  timeout: sameAsAbove,\n  valueEncoding: sameAsAbove\n}\n```\n\n#### `const data = await feed.head([options])`\n\nGet the block of data at the tip of the feed. This will be the most recently\nappended block.\n\nAccepts the same `options` as `feed.get()`.\n\n#### `await feed.download([range])`\n\nDownload a range of data. Callback is called when all data has been downloaded.\nA range can have the following properties:\n\n``` js\n{\n  start: startIndex,\n  end: nonInclusiveEndIndex,\n  linear: false // download range linearly and not randomly\n}\n```\n\nIf you do not mark a range the entire feed will be marked for download.\n\nIf you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire\nfeed will be marked for download for you when the feed is created.\n\n#### `await feed.undownload(range)`\n\nCancel a previous download request.\n\n#### `const signature = await feed.signature([index])`\n\nGet a signature proving the correctness of the block at index, or the whole stream.\n\nCallback is called with `(err, signature)`.\nThe signature has the following properties:\n``` js\n{\n  index: lastSignedBlock,\n  signature: Buffer\n}\n```\n\n#### `const success = await feed.verify(index, signature)`\n\nVerify a signature is correct for the data up to index, which must be the last signed\nblock associated with the signature.\n\nCallback is called with `(err, success)` where success is true only if the signature is\ncorrect.\n\n#### `const roots = await feed.rootHashes(index)`\n\nRetrieve the root *hashes* for given `index`.\n\nCallback is called with `(err, roots)`; `roots` is an *Array* of *Node* objects:\n```\nNode {\n  index: location in the merkle tree of this root\n  size: total bytes in children of this root\n  hash: hash of the children of this root (32-byte buffer)\n}\n```\n\n\n#### `var number = feed.downloaded([start], [end])`\n\nReturns total number of downloaded blocks within range.\nIf `end` is not specified it will default to the total number of blocks.\nIf `start` is not specified it will default to 0.\n\n#### `var bool = feed.has(index)`\n\nReturn true if a data block is available locally.\nFalse otherwise.\n\n#### `var bool = feed.has(start, end)`\nReturn true if all data blocks within a range are available locally.\nFalse otherwise.\n\n#### `await feed.clear(start, [end])`\n\nClear a range of data from the local cache.\nWill clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.\n\n`end` defaults to `start + 1`.\n\n#### `feed.seek(byteOffset, callback)`\n\nSeek to a byte offset.\n\nCalls the callback with `(err, index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is\nthe relative byte offset in the data block.\n\n#### `await feed.update([minLength])`\n\nWait for the feed to contain at least `minLength` elements.\nIf you do not provide `minLength` it will be set to current length + 1.\n\nDoes not download any data from peers except for a proof of the new feed length.\n\n``` js\nconsole.log('length is', feed.length)\nfeed.update(function () {\n  console.log('length has increased', feed.length)\n})\n```\n\n#### `var stream = feed.createReadStream([options])`\n\nCreate a readable stream of data.\n\nOptions include:\n\n``` js\n{\n  start: 0, // read from this index\n  end: feed.length, // read until this index\n  snapshot: true, // if set to false it will update `end` to `feed.length` on every read\n  tail: false, // sets `start` to `feed.length`\n  live: false, // set to true to keep reading forever\n  timeout: 0, // timeout for each data event (0 means no timeout)\n  wait: true // wait for data to be downloaded\n}\n```\n\n#### `var stream = feed.createWriteStream()`\n\nCreate a writable stream.\n\n#### `await feed.close()`\n\nFully close this feed.\nIf you loaded this feed more than once, `close` will be a noop until all handles have invoked it.\n\nCalls the callback with `(err)` when all storage has been closed.\n\n#### `await feed.destroyStorage()`\n\nCloses the feed and deletes all of it's data from storage.\n\n#### `const {valid, invalid} = await feed.audit()`\n\nAudit all data in the feed. Will check that all current data stored\nmatches the hashes in the merkle tree and clear the bitfield if not.\n\nWhen done a report is passed to the callback that looks like this:\n\n```js\n{\n  valid: 10, // how many data blocks matches the hashes\n  invalid: 0, // how many did not\n}\n```\n\nIf a block does not match the hash it is cleared from the data bitfield.\n\n#### `const extension = feed.registerExtension(name, handlers)`\n\nListens on extension messages of type `name` on the feeds replication channels.\n\n- `handlers.encoding`: The encoding to use for messages. `json`, `binary`, 'utf8'\n- `handlers.onmessage(message, peer)`: Function to invoke when a peer sends you a message for this extension type.\n- `handlers.onerror(err, peer)`: Function to invoke when a peer has sent you a mis-coded message on this extension.\n\nYou can respond to messages with `extension.send(message, peer)`.\nYou can also broadcast out messages to all peers with `extension.broadcast(message)`\n\n#### `feed.writable`\n\nCan we append to this feed?\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.readable`\n\nCan we read from this feed? After closing a feed this will be false.\n\nPopulated after `ready` has been emitted. Will be `false` before the event.\n\n#### `feed.key`\n\nBuffer containing the public key identifying this feed.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.discoveryKey`\n\nBuffer containing a key derived from the feed.key.\nIn contrast to `feed.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same feed, without leaking the feed key.\n\nPopulated after `ready` has been emitted. Will be `null` before the event.\n\n#### `feed.length`\n\nHow many blocks of data are available on this feed?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.byteLength`\n\nHow much data is available on this feed in bytes?\n\nPopulated after `ready` has been emitted. Will be `0` before the event.\n\n#### `feed.stats`\n\nReturn per-peer and total upload/download counts.\n\nThe returned object is of the form:\n```js\n{\n  totals: {\n    uploadedBytes: 100,\n    uploadedBlocks: 1,\n    downloadedBytes: 0,\n    downloadedBlocks: 0\n  },\n  peers: [\n    {\n      uploadedBytes: 100,\n      uploadedBlocks: 1,\n      downloadedBytes: 0,\n      downloadedBlocks: 0\n    },\n    ...\n  ]\n}\n```\n\nStats will be collected by default, but this can be disabled by setting `opts.stats` to false.\n\n#### `feed.on('ready')`\n\nEmitted when the feed is ready and all properties have been populated.\n\n#### `feed.on('error', err)`\n\nEmitted when the feed experiences a critical error.\n\n#### `feed.on('download', index, data)`\n\nEmitted when a data block has been downloaded.\n\n#### `feed.on('upload', index, data)`\n\nEmitted when a data block is uploaded.\n\n#### `feed.on('append')`\n\nEmitted when the feed has been appended to (i.e. has a new length / byteLength)\n\n#### `feed.on('sync')`\n\nEmitted every time ALL data from `0` to `feed.length` has been downloaded.\n\n#### `feed.on('close')`\n\nEmitted when the feed has been fully closed\n\n#### `feed.on('peer-add', peer)`\n\nEmitted when a new peer has started replicating with the feed.\n\n#### `feed.on('peer-remove', peer)`\n\nEmitted when a peer has stopped replicating with the feed.\n\n\n---\n\n[Dat Project]: https://dat.foundation\n","readmeFilename":"README.md"}