{"_id":"graph-state","_rev":"63-7cb47255825f1f4e86a726c32db44e2f","name":"graph-state","dist-tags":{"latest":"2.1.4","canary":"1.6.2-alpha.12"},"versions":{"0.1.0":{"version":"0.1.0","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.5","eslint":"^7.10.0","eslint-config-lxsmnsyc":"^0.1.18","pridepack":"^0.1.3","tslib":"^2.0.2","typescript":"^4.0.3"},"gitHead":"de110b2ae3c56f88fd54e4accbd7de0e936eda36","description":"> Digraph-based state management","_id":"graph-state@0.1.0","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-uu7S3QePt5yyjJBSFNI6tTfdLyogJHCZUlrrFIKb8djFlu3EiQj2NWHqDx+X5CHEA34rNGQq9I8uwaIJIVGErA==","shasum":"d01568193defe50bfcea4d7e56aa79bbbe43e4ca","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.1.0.tgz","fileCount":48,"unpackedSize":334765,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfgGnOCRA9TVsSAnZWagAA1ogQAI1aC0NEBwqR4lSnadL/\n00QNMhEZMx/nQvg6W02ooV7O1w3x41FkPcA6eTkhT4cvnZtHfW6ICg+K5J9R\nxaiaHPwRw9IVFELuyYUhLSLYvhXRye5tdEkW69Vv9D8IhP3CfjJlJi+DEJqh\n89NzrpWl6mw33/rdEorXKvskMyIW+ExV3LnjFQKU8UB8kidF/KHqS3jkcKaK\niqMyMot2IbPk9klaACswAqS5OwSD1Ms2XPO5MJzwovlWbYVKLAdHTAZ7TOen\nY9BbZgyiw+YUVFxbuWRRFiPJfhyCQ8iFtDCpK95DwHRY/co6nr1PpTYBlAnr\nRPdHHyfno8cLHMXvKeLE/tkKx7d0SzKY9NATPzsHw/LwSthDwqbyJkb36fYe\n2M13Bc3z/SrTTaTZ95ssbgaAgQTKW3WfYtPh82zg56VNp+qBNiw/wvC1HIU5\nyh21yZYQLGQ/Sr5WblH3TeD00X0R6yMTPFo5tE2KNB+MG3oDETlfjZEQ/DQ3\nIwWBxJzzXwCD7mOSID4VsxKvNFfGixw3+HYNfe7I7gH3wFqpZ5Fyo+I/5TQe\nB7MJvIn/ENLzapudWn1SjVqqWaLxMqX0GkNRiqtGejk8XrpHgt6oxuHvIuyv\n1b4WYuRtLZwxuomqXv/ZXSnhDJFPu7mI+DBKL9aV3LX/EHfzWjhwxCbTvbI8\nwQt3\r\n=Jm6a\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBatWgfAZSqMUIysl6Q/4TiTqw7JSlRnsk3eoy1aBQlQAiA7G9td8+qI1/4E6QE4CsCqdy3NloDgjkBYvXP12EuAAA=="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.1.0_1602251213867_0.6863984263626792"},"_hasShrinkwrap":false},"0.1.1":{"version":"0.1.1","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.18","pridepack":"^0.1.3","tslib":"^2.0.2","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"59518f7c9e7033ad17e9f329eaecf4c36dc4a064","_id":"graph-state@0.1.1","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-fnhJ3pPNrNLP6Yc2CooDIunfKF/Gauz/72Gi/aA9Waa310oEAxPXQpXiYhNHQjMHuTHKn5Tqxnu5uFFvstEqSw==","shasum":"1f86f884ea8cac82dd85271364bde89bd802c33d","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.1.1.tgz","fileCount":48,"unpackedSize":335083,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfgcWNCRA9TVsSAnZWagAAM20P/it1FhZ9fevzo9whl5z2\n2GpAbXndguUGdWzlSCk3XfCarl9wYmmL2UInjOMJWcj5oXP5XHi2agcT9g+c\nSwww0d2cmQ/Tn5l1ynkXujf0s9U+fhP80x0JmJ9Sr2/u06YlD3hRuuevG+FZ\nhOJIVuKyqXOJ2AC5duJQvb1fPm8D+I5V4zwjpIieQXc4XfybAqcHxj2bnhiJ\ntV4Wm8rvOYN4lfx/bfgAZt/XkxzTVq7RAXiAFDGa3FjJW7O1bwM3AqJ9UYln\nrbbzv8Prn0dmUXB6ed1btLdzg+qG/sMnM7Lh0edvL88DY725aHrVClxfQzDV\nqqIOvkndeHTm5mMqp2xloCvH+FNaEQvC8B/XqrGJA9SRvFwUm0mMiyBz1Ep1\nb6d9xm+V4YBJIi7D/uFLw1r4PVK8KIxDADyW1YXdCS6WstD125XYhWsLY7Ri\nixxwG7Aczc2Xae0bXMf64FR2WDwFUVrfN+57LVocTL+ACdbJ/YAhqJSiqIZn\nlMaLSjp9NDBSzoKiBG/iotkfYzDoaJytyn9D3Dfp+FV/ytRA2HlCiHjKAhol\nqFdDydpgBtwEA6SLTTsCOhlOtMwzrrdo7q1g1yJop7cgsiJ9S6u7n8xarUxG\nmG0UGDbeGHP829a+j/7KLkIMCeT7EoJTa8SelsXq7TMAcbhJUjYrcS5qR+/h\nUsfC\r\n=py8g\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBR3H30HLwfnR/4JBl70xA/KWGRsy78KMgR65/M+eVAzAiEAqabFgXrp0u6INbOqRenwViN8yoyvOyfu8OtsK4tGRl8="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.1.1_1602340236566_0.5401769455788012"},"_hasShrinkwrap":false},"0.1.2":{"version":"0.1.2","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.18","pridepack":"^0.1.3","tslib":"^2.0.2","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"6c548b7a55616815d71853e024ae7acf48afb65a","_id":"graph-state@0.1.2","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-dsPCefqtOJm1GlDttbUCpfuYxNWBV1IP64GfOsFPaPO4E2kpGDAjd+kF6RoJkUlWG4RES1bKgq1zx9r1Be3Njg==","shasum":"d4e22ae27c93f345160a17bee8c7752e4764842d","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.1.2.tgz","fileCount":52,"unpackedSize":362182,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfgns5CRA9TVsSAnZWagAAzfkP/iMqGzupk7DkLfMFMFUt\nP/9kDoJ6HrSoT43Qr81dEouas6sk4BjEYTlAf18wKdrmLrm/WoAE00gzyQId\nYxsnaz6uJ086N8gVce6Sj4R/bVrQpgLyRwadP9y+00w9HmYYBU2zW7sdBHcW\nw5tEofen6Bp5n/bZDA04dJbdM0Nrc4maCMCubnI2sc0WVIpspt41JDsK7CK7\nS0SKtQ+jdAD9loa99eqUIMiRfVipAWb5w7zueS5Vu1+ygXAeTUBWRvxTyQue\n4osu8Dw7wDi/3oJAXCdMAyy0MPwAkSEUTPaxGJo653+HcMooOJLAazcMnxQ4\nv0XqwSJBRjgjIQ680wR/q8cd3NHPc3vE+xPMxiB6+DJ/bi1Tjwc4XPLPTEex\nBJyjOQCwGBdCZkmQu3MlL/AYXzVplHLrDHikke10gMfU1Q8fVLVcDCwBphjx\n08N7TGgs8zkijegGJJz2az4mW1Jjs+/YzyLWixh6ckMIRsYLpi/bFE9kLjWz\n6t8zBqFtuAB9Qfbi7O1v2OefC2XdDU39mInRt4NT88NaYmJ04sk2WFwbe3M/\nSzAtR44pYR5t0LA2pwt924s4DqH8jD3wll9OtHbALgAFpdEUn8bdxlAQ+2AC\nrnFIsuu9OE/yTi065T6LDmzxSdGQ1Icf1ZYsZeT87kHqiquJ5C9E0I+lXXU+\n1LOY\r\n=mntk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDO79WF+qnYUYjIdkLYH7uSe7Ida1ce7CqEu2bsyqcrbQIgRA7g4Nb3HXMZgwqBS6wepkcalOy+2A3cjReXmZUagJA="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.1.2_1602386744625_0.670167736677608"},"_hasShrinkwrap":false},"0.1.3":{"version":"0.1.3","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.18","pridepack":"^0.1.3","tslib":"^2.0.2","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"56bb42052502b6930e0a407ca43f620d25cddd63","_id":"graph-state@0.1.3","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-XPUNoPgMDMQlquKowQSu2KYrJGuM6uhOcZIfatjoN3ke69hynHPSDJDmMfFZKhyA+MnPtsFXcLVqLv2t86uptQ==","shasum":"781853089f90cea766424f55929db5bce310cabc","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.1.3.tgz","fileCount":52,"unpackedSize":355959,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhFpaCRA9TVsSAnZWagAAVpUP/3Aud1USNa8IXxUS6RLp\nP9Wak5AmS5fSMSFpIjyL4aSKxZ/rpC4CRrRJzpeJY+h9jXZUFtb2X7VlEBST\nTMaDgW9CYJ4mlHpXS/ACvedhoX/H/wLqkT18rbsi9XQU8NOGAiREZ7fKj7Ah\ndbxmTez60jBYJrZLBlQpMQGemMG0TCSRHrnWUKuU8krw4n3UtESKAa7yoq7p\nGVYqTcxmgSRei//oq3rJ5j8CqgokjnfI1nHJrAeCF5GP0DxS9EEoy7mFa8Ao\nl8ss8S4UevEDdwhCieaToNH6sTt4rJ7USwXqxV1qCb1qN9cEqPKvACvxmT0z\nbOZpEEDOO5xMnzmQ413TCYulOs+t50tafyfNEvgE+bjla0wG/97WOy6zspS+\n5IHwkZxZoweFqy6ffXiSp8hMcnP8lisXvli8CnFdt3STw0aHm1l/3dX6uBEH\nFGy22mlpNDjqq3PapH9SeVi+IMRtiT8Px2AkcvSMx2c4OmKXCg4vOQj4X5Rg\nzWha2RBQ00hVf7GTLIejTbtsLmbQ8WV68DbJ3awEGmFcmUVihm7Dl1ZSFlrK\nS6QNo5M2WE2RIm4g0wq+POn3Zv6SOLAThV621ghnfJyAFVoT7qN2JcSezh4Z\nO2Zfq+TVCkjPoy5criku/X9lCcFfBkwY1kvjVBgu+/bmNRhiQES/XIEM99vK\nv7w4\r\n=72XW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDI160tro+BWJTCjvsplmoKP/W2yWcg61FJ/ayogvmGLAIgAk14JNo91E5xlN2BLIcgkP1RHru5k9MDvR7soW2gBWk="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.1.3_1602509401462_0.8997010814966337"},"_hasShrinkwrap":false},"0.1.4":{"version":"0.1.4","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.18","pridepack":"^0.1.3","tslib":"^2.0.2","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"a02445aeac6789ed7754044a62f6b23d2f16bcb9","_id":"graph-state@0.1.4","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-zWcRx7ohX/Vf7socWjtCZEHCr/DJ6WyRv2ClHAY0+8Y78VOQpvClAq/g/F6hCEvRx4oYc1EzoOAaKtEdOGcY8A==","shasum":"0642337aef1022738a0e6e300d5f415ed7a1a1de","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.1.4.tgz","fileCount":53,"unpackedSize":358010,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhGkNCRA9TVsSAnZWagAAXucP/jXh/07Phitv2cmFB+8H\nCAuIvO+61ymlXghhT01VV5BhJugff/995iBcG8icc5SARrWWG9J3/O3dQWuk\nWdqNRD67twLCOs3uUZv8nkAfIi2IqUkFO8emlUZ1fccgaifiKRQvxRhM6he4\n/QtuLZfAeYPgYk1SJrn/oVg6XwjQQUxNOKKc8ICvRV3+8zegmRyroewLIAr/\ndq4Hqe7ZVvdN+yyUbCaYgB42W/zigDowjmgsSNv0RHlc9RoE8Fttr7lpy+eo\nDuPlZ1epXGP/WegDT/ebPzT+6w3RMYi+WL3SfinlesiFwdMhFPTp77lboyVK\nT4amEP9T2L0ih+cRwFt2TS7yFCwV3fLiEOdWUVdePPUHUhGfvf+9xdNBaWtW\nRudVmzRG5Oct2teYg/YtsEOzLKcW/KfDTcAXRcQ5f7PBW5N9imG4zoDdcBWW\n0DG9bM7cszEHnB6TleDXZNSe0GDzh+fIJ1M4HZ5w7QeIUMEP9ADQp3C/43xB\nr2cHPFxgBTfhqffEWMnCAJeq0ucYaxWK184wMlerBxmFjD33zbNlvOhxjKAC\nbhP/i1x5gJaKRKIm2wv+YDWNQlA896m8McMJxXVr6bYDS0iF/TTfAlgq0km4\nrzieYqVdYPHhguoPwXQkuxdtrs2LsaenrKF1lWUQKV+c7GeZrQ7ue6zGdUFR\n+atX\r\n=/p2e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCJFMrWzyqb1NawLG4oxrPPUF6t6aGg1cSjv1x8FCHZwQIhAKJy7PuzVo4XG88epBxx1OPoQaW2cVAYd0xgnMPLKRJh"}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.1.4_1602513165248_0.5024654701258813"},"_hasShrinkwrap":false},"0.1.5":{"version":"0.1.5","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.1.4","tslib":"^2.0.3","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"4958dcfbffdfe24d8b2e58d35435088e0088524d","_id":"graph-state@0.1.5","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-V0P4FxvY8pO/g9WHryD4NqtX8eAeTxRbZNvfnYTuqz0aM2T0j0rHDvb6cvXLfcxfGptXEZNjBZ21G3SP+RXtpw==","shasum":"c4fd70b5ab2504b6ad1a4be7d437f60db3181366","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.1.5.tgz","fileCount":53,"unpackedSize":358341,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhRu9CRA9TVsSAnZWagAAQp0P+wftILDX4mGk5f0uSzuo\n36W30UI1tCStPuHmEifaly67SjYNAHHleRFeKzn5DEG3hmENsSfKgVZn+ujB\nyQE2ujmjooM8b4wSzsJPBrKkB44YUySGylWe/xGp9s92n58pxMKKHwqjyAXz\n9My8q3uPPjWnBxW8CfinDPaOPhH72gKIcRJZQA02BvVVg/Z/xpxj5koAb0ua\nwPNeIu8wMKfOaw4xztStiYP9OZWzr0R+1tF0wBkzQejEgyalMMZQmze1vbFi\niuvTTEUAuJB22tuzMuG2oX+dJxCDVpa4u5RO6VjNCxrhvF+XMD0TBObsH2e6\n1L5NWezSCQkKf7s5J3wXPJSO3tnKWS8gPMSt09GaMswNVdnY6CAg20AYGEvM\n0qKwpmzfkUUI1AWw+dS6ttyDQT70xXkWm7NOG2BXvy0w3i0KjuW+wVAq/nsl\nmR+EzEVqRQvwe/EYdLPKHsFWthmBXvrIYRLmRM5+0WWxddPUnjAd4t+yXudh\nhytqKnkTjLeInLcr6pOTRDm9nQOSd42aMkLxJrYXRsCc+i4tLiry2vXl0ox0\n8Bee5N/b7HCPkjqoEx28eH+qQIhuMi3g4oRsqovVIaehwR9LLi5G5asSezdG\nygTD1+bluj3bYqQD2SKVWPcpv8mQqxJa2RdTeY4PE8fXqXi4MsWYu4CE4Wzj\nIxD5\r\n=q7Pv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFxpzMlQ+VwzhfgLgpTmsqlHIgIoUecjFoixW+JfOhnPAiEA+HJocNqBkMwXDa+O5CVIk96P9EnQCpilTM1rOgPjSfk="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.1.5_1602558908594_0.2913623027405541"},"_hasShrinkwrap":false},"0.2.0":{"version":"0.2.0","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.1.4","tslib":"^2.0.3","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"9f6c5f3f7ac1f0395dcf7be62c660cc267fac45b","_id":"graph-state@0.2.0","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-bxqbUwIVipbh18LrLbpb54BdC1zvFdcpFoTlSEJKMg//9MPGP3N/kt2q1e2ipCjR0xkpc+NteCm9YfWzu7hG4Q==","shasum":"87602970935c1a3801d31835fc6756fc978f2d2e","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.2.0.tgz","fileCount":53,"unpackedSize":361603,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhXzfCRA9TVsSAnZWagAAcDsP/0td32/S4R17wvgChdOl\nV2Mlue809Au5ICJVNBPri8Rb1UHY42g1lWxKj3LnKihhQeoWumVWyHw1voug\nsCiBmFiH8HF9Li/5615w3E9h2shxlpthvwJ/YRj1ZXRswacap39CbYFTN1A9\nWevmjo6oTUfbXne3XJTFuTZJHpwKvotdgv9FYEn1IidWz1Zvl+g7x9kQcJEP\nUfMfT9tO88VpJMt4GIoQhD/b2I+bS0pBIoluEQtBqi8hy/S4RXSiT4PQGsI3\n19Pq/spf5VLnFhiEovys55VPyjO6kK7Gq7F+AWmHNC10VJ9w4FAf68s5n6PC\nwhfDIUG2WV1VtA2Qic2PXkblVR+DFAmwFFcYRyEiBSOdQDw6OUVgC/olZMYm\ne6z0UzyHV4R58JfhdSrWWC9ZDifHOwS6qfzacDwoUNDZgaIpOEGO6EqFekke\nFNeF3a5kFiPsIT/3VfGIB8clwZ7Wr86Vnxt0b17Q4xwrpYd/6IL0djPutpAx\n96wCc0Xz08TvN/c87/H/KZsTra8aiWzjGVK5kxJ2gGfbRr8aErglcBI/b+G6\nO3kWoLvdVUr88ieYy1fNTEeUZ45swWJ7jgSutpduOCflnzMFV26VuJpDahUp\n4B7gmR6VfpovnwLbtvlKX5kKIyQ+noUdNLTTikskO9Z9F4dZZrZIEjpAbFAL\nzqsr\r\n=8KOL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFqili6WdSTyOiHVTTEnoOIE3N/homyui0Y1QS2ZiLXwAiEAmpCplmyLx8+QEMO5aO404xjwkkqukGXhw3WKtse2uFE="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.2.0_1602583774690_0.5784602999070736"},"_hasShrinkwrap":false},"0.2.1":{"version":"0.2.1","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.1.4","tslib":"^2.0.3","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"90b9e88b06026c52a062cc50df13ed65aaa59477","_id":"graph-state@0.2.1","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-qwlngVE0Kls8l1G8W8UFdqgYlfhtU6IJsReFxEBGrP6JZmSG/Ff4c3iArIyNY/URu5yWBwJBdUdNp30oMWcMdg==","shasum":"36ea7c50af03e7dd6e424a40dbe198610a794a47","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.2.1.tgz","fileCount":53,"unpackedSize":361783,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhYEwCRA9TVsSAnZWagAA2+oP/2AYYBiQ2+TGLQ4Z9HIC\nJ97YbiEbdC3QWzci+kWQ+1vpB2kHtJWQ9yyVnnsJoklElNR2YYuzXO1zYRVl\n0S1RzKB/IZ0eIm6pGTq0woqHDZf654GYnsRfgqb8sQmutii6/7lU6HLEX+Xx\nTeZd/tHn9QOPsbTLWgbG6ZpK0vjAgxqnqulf6qSkMQ5CcwoCoGFUzeC8BMY+\nCwkst9ac82El6nxS6c8RA93UQz2888Wm7p9su2PH6Guay6UznG50pKxN+KrG\n1m2bJ+svTNlVk6zjkmreQqQ6VaBycbuaLHW3wcFoKkmndNm7GyCuraMkndsE\nHvnEKLM7n3vlH0OTs6Ypz49lxw7OPbRBp2F9pIjcX0GCG5d7ATrcLg2h0ML5\n9fdrpqIrZWPdBszuc0z1swmuzvN7Ch4mh3BAxhHlBh6dpcgdZEeq0/DzbWGL\nbzAtxPLrNnc2MfF8712XtVZ3Ti0FJHuqJ0w3SrkG1YOBkmBDxYchgUiVpw0c\nsmveZEhmofMzGHOrNHG3CG4EcieHafSN2ApYlq/zB95nbuxCZmticrKWSxk8\njM/gL7BVeN5+uCI+msuL/Rv7D0b6ga0bYGM9vtAZCopcRxyEtQC4uHl/yfUJ\n+QKms3LpegzSfbnXUcHumWgZUhODaWC0a52BZCzaN6c62kQfT3+jDMoSpq9o\nQZoI\r\n=ETm2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAxQMAE0pZ//5nyItHp8VUTWlaC4p4fdxX/vQAc5SgGMAiBDsxYL4M7SZZiljIK7PO2VwpFFzyMWeJ4EZ7MsbhJaYA=="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.2.1_1602584879665_0.9953784540125918"},"_hasShrinkwrap":false},"0.3.0":{"version":"0.3.0","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.1.4","tslib":"^2.0.3","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"0a547f5de2e3c16483fa10c8ef86bd7ce0051aa3","_id":"graph-state@0.3.0","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-pFHx4I0E5SK5xVeTrF88c6/Znv34jOSZFpWzYbbcP34PnFqB7CEoDaUE/R9mjXKsvA4j4ZhCFu6Ix0H8xMdm/w==","shasum":"e6b077bdecb6dc8451876dcf7265cbf73a235531","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.3.0.tgz","fileCount":55,"unpackedSize":374767,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiDknCRA9TVsSAnZWagAA4ngQAJqMk0rXWb8pDTQlT7Rb\nO663H7nk8S4i0CAZSYuX5gZT6He9VzdvSQu1c80p3PK+6SjZqYNfDMBT6mmw\nqPK2sc46ihkyLbIevdJbHbnCrHb/BHz7hs5Nj9tAHza1rPiGHUF5c8SbEI+l\nlL5sKO+hsYdygrVRaR8fhfdcLJijnRRwNf+KgbIAopc2tcvwImzf5RskHomL\npHLimmWtX099kkGasWQ4K+MOl8992GP/xGHZ24zr5fDOSiRGkehTbu0+16TJ\nJV1yGHGSsJkcSxgVxm7qH0wN4gtWdT/sxqeHFXC5dtUzRKZo/ETOpMWqn+yA\nc3xWr9A9bmhCp3s1Cx5fVXL4obt0cN3HYuexgF5XdhFqvVVnet6ZN3F7n6FT\ng5ozPn4ltAYOu7vPKCYjp542apIZKWH9ecNWaT6d6SNzRQ/yJo8TcxfG7OGM\nVcW6kgzvlCVjs6j6ZSBgt7NJoBiP/kX4Sl04wqrjTAiGeED0DKjIF6nQWVhQ\ny5kmXhR3v8vw8Mw4mv/tSXocR8KvXMfrwRtEh7N/arAMAgM+AHF9pDYhNQGb\nnylAGJU0v2UfYHTPSGRRMutup0HccszLQucGHBWmZNAh8MgBK3jvu4t3uR7l\nNgawGfOvUYD3/LJqrCzsFl00uTUbyOP0J6C0v7/r8zkSMFNwPBbKBfTguFX9\ns/Da\r\n=6Lx1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFJGQ2c4np3ii8wAeFFdVEjdOVFr2GVUrOvjBAz8+m7OAiEAsENFjGQA3SFn/cGheRm3pJRXdpIUyXxcuBbG7afx/cA="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.3.0_1602763046521_0.1825878328696806"},"_hasShrinkwrap":false},"0.3.1":{"version":"0.3.1","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.1.4","tslib":"^2.0.3","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"82903a7ce27603ecd584191b5258cfd428d31fe3","_id":"graph-state@0.3.1","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-NgQ+9IgpJm10XPIEH6XIBrZRwMWcOi0WP/nCRar9MXlniZmW7VNXmM5a4xhYmC+XKf1ZzEVfTnN00gG5I+Eu2w==","shasum":"901502deecc0984dc209e5be2aa066e02cd8e99f","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.3.1.tgz","fileCount":54,"unpackedSize":371471,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiP1vCRA9TVsSAnZWagAAHq4P/1QzUBEkLZ+ns1zfGTdx\nb9V30XMdtHVrSjxtZOc7nU0/0vJtHWQK8zKiUGEbYyTDH3IFaULv0RaGuPcv\nUFE8VQoUbkFTcjbZjWjQ6ttxWisq7prMmpFDlrZoSCEqoUaHlsDHbkFmBsHk\njLrQKdxRMohaBJRCVMQzPfUO3jM4w+3f8H3xk2uSKylMre2tSjU8R3aMPtzd\nDSfCoAG9b8e1CKPN5mhRfEnhApyC4kGrbAGAUrn+tiZrupx1Z/pSFaBqVQqF\nm2nt+6uUEcW5S93LKxpidmBiv/f/VFs/XDVvajqlZB21Iy9cA+6pQ0PDs65y\nrnd9asV0c+70mItRd0c9gPtZ3yOLr+9OXa4kWM3naZ4/Bi33p/Mwb/4RXHtF\nnXwgIyWpQHqYDztZv+unZHMXyfXoFUBOL0Ssjiy4pEZpsOy6EOBnLWnNKodc\nfXQKIMqRAVRe6EZbUbXRQdEzBJWQMWj6uZ3I58dcjjE97hQU7ZhpJBcDB7wp\nK0nhUTXHVy/yLKdvIet4wq8ebXW0YKuY0AbT1afE3hHrITaM/iiBmERrCqud\n6Gg+WxJqKnLZ2Y5fxBoi0/j/3D1YXb0IfddqeCtLXJgNvjHPLKM9Cn8pM/U+\nTb+FbkJ3aX5Q5bsBo9ahkmAC62Ukcy7ni4jNZvotiKy3L0EqGrmurPt++hCe\nPRht\r\n=Lp89\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCd2khOPgqlIi9XIpFYVahseUTo35vUakObK3+K3KdXPwIhAOopNoLPgMQEDStkDghJQIQ63PzGKuKFZCa6QhlGJ7P/"}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.3.1_1602813295341_0.28963149005293265"},"_hasShrinkwrap":false},"0.4.0":{"version":"0.4.0","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.1.4","tslib":"^2.0.3","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"6fb6a09fdb8bf55195ef451f0cdf174110cb31e1","_id":"graph-state@0.4.0","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-qpe8Xo6xfT7Mj44VN4uE/VDpWdqaiJGKN0pOsPuIZ4PO3uLUbd9rZwrbDwx/p3K94rW9iF2lUjxUeCcp+GA9AQ==","shasum":"20950b794bfdf371d49b94cdc1cb9fcbde417238","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.4.0.tgz","fileCount":55,"unpackedSize":375844,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiaNMCRA9TVsSAnZWagAA+UwP/RA5GIKaqcOdbO3Snt1X\n+0IqX1JP3bjEqgAl0l4tL+yWQ5BI16F+r/3ndO2DWORMu6p7/FrJZniQaCsS\nB+OpZoK8T8SgyJH+BwQ5U8CRmEjpIwa8Wo0Vj3GNbb7PNO86y368Ze6WNpNO\nfUK3TVIAhJrehNRsIqW9ECLvFAhlpm5sdnhnhOmioPzGdjnhkuu2PcCYZet+\nq4FCX+/v2dB+Y2zOnhu/S5gj3HEc2mG72waz+gjV8nbG+1Ids0wNf2qbzb0e\nCbb63zBtPPI5VMbyBqrviL18FpSRgD7fAU9Jruuqc7A8Dvwgw583Q3sTyv/W\nhXeydA0prSm7ur/oEb/ux6Pfk5+LxCihzi1Y/h6UMe8qx/BlJw16wvrYGko/\n2qvqrbuabjk89zITW5h2/thAUS1UO9w3KZ8616Jc7SGypq0uQboe6LOnsIu7\nwebZMMIHJFOF5R/EmCNfc2SLgBsYMmjKPgknwQ33O0U9XH4aaRIFcQj7aKa8\nRnV9ts2l+/5C96ZFn6ugbOkSfeFfvMfNflEqHMsURohX93aKIm0I6oiQpkGQ\nEX3xgaClpkVLZOl2fHU2V+5d6pw+7d2PeRH4t9Xeb/HgN/WtBoXgbRl0Pwho\na2g7PzIC5B+7n/KIokq3hunM6GVXNfvK+Vem1Cic/x47299k68qqxqTXzJaD\n3PLj\r\n=Hfg3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC2crjVCl9Hj3UeDNZu8K4gpXEFil/xFqCdqSM+e0BKMQIhAI2+JZWXZWYeE9SHTWBijJQiPTA/caHZ8qqaSy9VOLdh"}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.4.0_1602855755640_0.045657761346751924"},"_hasShrinkwrap":false},"0.4.1":{"version":"0.4.1","main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.1.4","tslib":"^2.0.3","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"gitHead":"eb9740172664924207d8d95dbff52ede3f288327","_id":"graph-state@0.4.1","_nodeVersion":"14.9.0","_npmVersion":"lerna/3.22.1/node@v14.9.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-43W3Wj8wmeIh2tC8hbErO7RUriNlyZn+mrZWs9Ja5HK60un7imM2519FKZikIbsQr2ZzxOkLFYEuwbmqgTDNYA==","shasum":"d9edf5542dacf26c738e2865e41dbaac635aa325","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.4.1.tgz","fileCount":55,"unpackedSize":376373,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfi7sMCRA9TVsSAnZWagAAcJEP/iFfSMYDqvAvEFaXQi4X\nQPsQlzbd8exT5jRFvhvbLntPoJU5Z9JlAxuSQQuCWnHS1JkocweGT/wLVTPA\nF8kuy08/oz9fSN+/rdEBbL562LNfAV5CuMFys+j6KA7+tPC/UPSiUAQQVXdh\nuPjQTHZBw+MFukzmqYzz0E6eGTsIgr3fFS9JlHmG3BJ9YNK5U7sJo9dVkAV7\nuBO0okId7R65p9NYGjaTNnsuBs3vvMXo453vHeMzQu5EsU69VIorMHn/fxFt\n5LpwxOmJBC6bHKcpaQSUmmeLbWwsfN1+836rEh6gKoWbw2SMQ2zFdw6MuW12\ne83sJoZ3dThPMxz3ui0GigBnL9QZU1kzB1dVi8za4SGDRPHDsCMtGYRxDlcl\nMKcfqfAUiv9dircqP/oCmkLB6zstMexLecv/VrCggF+0GUAXJ8L4oaQXE2D/\nP5+J8C2uZysOWsnk5GhTSe6o0mVH4JwcyKLE3SncQBbfumbNL3uuoAiySl7d\n0T4a3s91yODbdD1S8JMg7BZdAiYToM3+7u4RrSrY3g4H3GR7qsEy2woiJdb1\nLzhSFdCAtaKNSx3gqjISzeEAmA8DNfz6wmVZc58RslEicSO+DSwsX6V1Q8Ul\ntD4GxKNsBnwrMoxXz0yiaWeI0QHbqfA6VeucO5/5oaWK3b5fVkVEvKJdynAZ\nXUon\r\n=JQwi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICU161vHPxt7A7j69qyaXJAjJq8cZKtUiPUAAzmVGx6ZAiEAlsJz+jjGwuob8Zb1571EqUuSimJJ3t8eIX4xuNRs2zQ="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.4.1_1602992907238_0.49578414906285273"},"_hasShrinkwrap":false},"0.4.2":{"version":"0.4.2","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.11.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.1.4","tslib":"^2.0.3","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"b0f57819df144f195c40ef01c3025e5f549241dd","_id":"graph-state@0.4.2","_nodeVersion":"15.0.0","_npmVersion":"lerna/3.22.1/node@v15.0.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-6iXENXEjFTgG+O9MTvEHeZel6+uSVABOnWtfNApk+1ox0nfu8+k1+ica3K2Kz3yp2JZ1un1HY9WxmhRa7aafog==","shasum":"2af9dcaba42b8f1ae3752a3647db94e66926813a","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.4.2.tgz","fileCount":55,"unpackedSize":376617,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfkr4FCRA9TVsSAnZWagAA158P/RSjdt5B95thyBa1BU9n\n75ItFYDuscQI/UOHPi4jPkhYcrKDp+iLBaKFMTBg+l6+dHAoNO+z5J3mTE9I\nHvoTBrZ8WEFxJsAYZ9vShV3gH7nhk8EX3bjdDMvVwKVFjlp4JlDPIce4ESH/\nGSph1MX2hvzQrLt7aaDp7qf1NjcLGLyGuysbyk/ogo0+jT7/EbLPDfrpVYos\n5oUe5Ta/9G6KUEtsjG/8qs2usZb9A49IHauHIUcMyP/iGNgKDfEBWCM/Dzqh\nHkg0iUYzTjEZ7mHJ0LqKyGee0cN9Ki5+yc316GyB7H6jCsDCSVPKt8cgyILI\nsbrZBYQkTbpw3rsvv8yqc3bNB5ijhzLsczwpFagdKMMXmjv1JnZKohrTcSn2\nzsi3fkHXxG1E60qa5+ONYBt9t/mCWkWAKm6D+n5pREyCvcL+Xf+0mFgf6kdI\niyuxJMTciAyF5fwvHK+dG1Yy/B8XInothJzpXu3iorexJWevi71+MY3ygDL2\nMi6cdmZ/QbO52+zijY5X/gjtyzfBzh5iIE7JD30yE1tyK/+0TU948+MrnBO4\nlbRVPxii9uTtM7EfNk4ggoX+LHvrYDYNhJU/NL0PaQMmFhQaV32X7o37srhc\nnMXdxD3KaLIHggs9ELYUBIuDGKJQtSHQr0Ta8Y4q5nAG+Cb3gUReuWmccQBw\nK0By\r\n=lI7F\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIARat/t/Jlowk2devphrEhGoE2DvxXVz/TCunCejSLixAiEA+dEtxnOcs4VeRGdG8pv7jk0ZxCRPRELhl36Zdb+Q2Po="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.4.2_1603452421382_0.11145825393302333"},"_hasShrinkwrap":false},"0.4.3":{"version":"0.4.3","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.12.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.2.1","tslib":"^2.0.3","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"373efbb96fe6852fbc064d83a943eb21696bb775","_id":"graph-state@0.4.3","_nodeVersion":"15.0.0","_npmVersion":"lerna/3.22.1/node@v15.0.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-cbbuqFeZu1++uiFPzv+Se/hMHMVCGkNhyxF6gdCshlGwMOHH0DKGGpbLkvBvo8i2ZGsEjoOZBa9+KqrAiZi1TA==","shasum":"833db79c0fea9b91a597ccb427f0b00556e8fa30","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.4.3.tgz","fileCount":55,"unpackedSize":375022,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJflB4QCRA9TVsSAnZWagAAAtYP/jTu2mJi6Y2Qy3+uSpML\nO42tVPDLho3oBa2DA6XkT/UoZNgkvhlIVyRYlm+SRDlAvNZTDkaL3Iunt+Dc\nvqidvEPuiUPnPVnntR65EUcKFAtYdnB3vuOcfVLKN/8+Rw839mo3HrvzPraN\nqLLhpBRu7xo33EaMEaJRbbmE6gGlXSuM7DQB43/KDpmtGkSPilTTc/YtZsG7\nKgdXS6DR+WmuhkiO0Q3m2hKFoem1r79NZT/kk8wWJy7A143rxVaUXpD8oMo1\nuVELellXfmujfMb08/LYUfkkBQiD5BcxUBhXjEksg1dJlfri0N0xJbX7g71W\nnsRCfI0zfUU2YN5S4TEfTJGyEV0+LOapD8uiLNdNqYE0dZYt0NUnTdEar5AW\neFzIgKaMTBT2K3Rfs7PccIGCpS2SvKl1yv6sj6SYq5sMUpIcU0hx4NcczDNX\nMZ6bVAePQNz+hC6wIG0E7YlkZHcJ7AqDAtJvM6umVHS7ZTN9O1PUyIkKpiSd\notfanYY5FQTJiZm4ZpQC8pWhGZLCnacAwdYOF0SiW93JYalnFfb4xCwh/+/l\n5rQVDLcSWyIYOvd3fGiFbFDrcPNyWCjUH7CBlucEfWucCRTHM3Bi/xrOZDCW\ngY7uHdDSfzMK+PVkvKH9XXbFRGmVgewj0ifqyoymBYFaCKSVVLTyIji9v/p9\nFxkx\r\n=iNRz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC+jjlNougMg2pZXcUEaHryyoWCg1EwvCEMK9P++eT83wIhAIPK2X+rkM3+q01gR0v312TYpsITG1oYS7AGB6PfpwOg"}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.4.3_1603542543954_0.12394387586846478"},"_hasShrinkwrap":false},"0.4.4":{"version":"0.4.4","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.14","@types/node":"^14.11.8","eslint":"^7.12.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.3.3","tslib":"^2.0.3","typescript":"^4.0.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"8b107316d9fc3587b815161f1ec6e412f8ec780f","_id":"graph-state@0.4.4","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-lCDnngQ+NfJpLgSELBKeEJoKVxV/ixlv1Tk1oJad299QPgd8lTtS64J99IVtGC7lh1Uq0MdenFqj0M1MQUUAHg==","shasum":"59b3252ea1478b894c3bee2b757a218648b00b42","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.4.4.tgz","fileCount":54,"unpackedSize":372784,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfoDUdCRA9TVsSAnZWagAA9dIP/jQXbLmMC+n39zvv8bcD\ns35p3/mZ+NIa8ZOPebERWcswlQhccznTS0yoOoVCBeI5gAVaMwG5Z2JuYfbg\nGcrYmTJYU1a75whivHJFOIsh7XPZOTMJ1nU08DPqS0oQVaapj9Cizjrt5Sck\noPPxJF5jXjKujcqxKJ6LsiH8/y/iQdTWANOYb/1ejRmx3/78lZ5lTqsHAfPp\nQLr3Pp2pdXh3NNtMaMHJczu0jx4CVbSSbsXJeD31Y1ShgpfxEioaJKulo4ez\nC52v6RRXYNcckC9TYOgH6TnoDPXVgymDlRq9qg8LWRsTZOOuvjJziKobyUFM\nkwV2Zvnglp33j05urwBH9PQdQr/h2JOM/n2FpgUGjQ5JmtkxIcZdgVm+avwn\nuOZd/DbQWyMymjZLorZLEWbAOkWhPyNwQ0LCm7JwkTEi1Oe5AH0ZAHlX4Kls\ns0DTQGCftTs7pXfrfyhBuCDwdO0zpYXhUZUyj0ejbc5O0s7JGuQmvb38mgNI\nKgHTi1ZtxVM3sKhtFcpt+4yjnVVjx58pKFFpP2/oReTk/+DEg62g9XLTMNDS\neQZpi0qpudT2D535ozPF33QKVQo32yEwy67PzPL7xCnETtI7vdd3Mdu6zTCC\nBIZUXA4ihLWRvzw9WyjcXAmVzVDd1QmZhBlVcc1XxL9f6jfC492Mq4SPqvKM\nqfHP\r\n=aTs7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFg88/jBCFMzx5KEaUkPgl6BjOhYIdbJNpwaQNz+PWAQAiEAq11E8RU/wXO1UXQQ0Uz+fvwk8cIhZlmG0PjrpBcNpHU="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.4.4_1604334877353_0.07855425969675123"},"_hasShrinkwrap":false},"0.5.0":{"version":"0.5.0","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.6","eslint":"^7.12.1","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.3.6","tslib":"^2.0.3","typescript":"^4.0.5"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"8325bdeb70c133345269f6081f6254620153473b","_id":"graph-state@0.5.0","_nodeVersion":"15.0.1","_npmVersion":"lerna/3.22.1/node@v15.0.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-7zVWkcLQr+RBPm+oxunDUXOYbPGAWtE6xhUDReL/R3wApzV2bHYXGi7d3djI78gslmsQQi2La8XqqdWhe8iJ5w==","shasum":"9ffcab22d29a42b202c6f21e56d7388433dc50d0","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.5.0.tgz","fileCount":55,"unpackedSize":390128,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfoTY9CRA9TVsSAnZWagAAE9YP/RU69JjFhQA8PwI0y/vy\npndLk67rQh7jLD7dmB6LNhQ2Y3skYWTChEvoDTH+R0bkbUmuIgfb/U14+xk1\nTwn2/toHJjG3MFuirD+Zk75p18BjTmIfZbuGoNdJEPwnGO90QcgmIZUHGrqV\nCFW2UdrdarOTm0pu8qBCyqr+HhVDWrZbk5Qgj9gttP6eMDDvG6xh/B8Ke8Mp\ntibIMNOcFRpxbUny41Q6Fd2dMzbzBdabhEtnY1uhiz2YpFK5aiZDmRLhDjvk\ngo9uf4p6G2NNwDdyiQBw4tSkPQCEYu8wgk0rjP5X3lB84y+2s2xeLuyMghpg\nOK8EdUIPM1PsEJZrqm+P35BO7gfbZx+ZC/aweJOmZPo8eDQWDn1ClJGLW9//\n8pbIzXcThmgf7+G/0/uNIlHRFn23u8FEQvI5104uaM85xfm1cGanshRAPWIE\naNTtI8p5BuRE+KByPQiglKvDjRoEf6gSfDeL608wnySKZUH7xFUFbRuJYgIz\nbPW/1DupIU7lgt2B0zQLVqHUGDmG7EMZe8WHfJ0aippWyzt5GJ3xIgJu8dKB\n3bIRE80KnNPuyVFlpG01HymH/q8HEvCKrA1le4uNjuBs8HmnGZLwZN23sGBX\nhDwTApec/k+x0JhnCSzzjZv95XatUHemcnoGWsPMg2D+l7P+r52YkHPfAfk0\nwYNs\r\n=ki9j\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCV1WJKttu68bRMnuSFsMTF++6imTXDy8oGkiRO1XpzTQIgNZKvDW7C0DQqOGltA1hC9SdDGUt0y+yM63l3cfx1L4U="}]},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.5.0_1604400700836_0.17752471388040214"},"_hasShrinkwrap":false},"0.6.1":{"version":"0.6.1","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.6","eslint":"^7.12.1","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.3.6","tslib":"^2.0.3","typescript":"^4.0.5"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"6fafe28402a3ccb38bd842d20fe81f36e55e53b6","_id":"graph-state@0.6.1","_nodeVersion":"15.0.1","_npmVersion":"lerna/3.22.1/node@v15.0.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-dSKQYgOuS38ZJMfUDAPV269QM37MoF+IwhlNvBYy+bCMzEDO8dnZUE439CzV+IQLPZVTKHGzuiKAOzJWmsN2wA==","shasum":"27dd23dd4e14be859878028c98aea83ef7c4f523","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-0.6.1.tgz","fileCount":57,"unpackedSize":407315,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfrPgZCRA9TVsSAnZWagAAwFAQAJG3erbdSZxIuItC1VKs\nM6Y5HcjgWSEiBnemXCHZy6kp4d3oGvu6ElO/vruktz5x9JXzt8s4XzyjYVCY\n+1mC3CJ3M1x/1eYoY+5j1a8THThtqdj0Oc+sdtcnI5iC3VisnKXZzyGIXTvf\n4c/HpPIOW7a0ksHFyk2L4Vl/SKHGFQ5pqpK6JNdmpL/ZNErEoDb/tjKxpz6S\nb/1un3RNZf0Q8ie2a87a+XmAH1c2e4YAzrQKqUUojl8gYTYx2G6iYo/qZLPH\nQZelGMYbnXiAY9JVJPJUsW37nw07zJsohSioL5FNCjHvZERcN3czx3C5uIq6\nGtUaHq7lMKVa2cgQxYT8YOtxq6LTh9RfKkojLZJ6p529cxNvvESpFZcvv/PV\nzp4KrZYjKRLBrorZCl87B6eTVN/eAvB1w0lOpNBKBIwOLfCKZS7E0pF3wdHm\nyQcWkPBivC2UhoTD6p6QKCHh6ljrZ2re50oMwr2KLHKsjxXqqDjfW2R2vMWw\nxIhZDbGicpttOvcjHzKZsBDOmsjzUMnoIoo4KTgfjI3FZxiBUhhoiiuRnmy7\nGs4qGP55VcCm4JjQYDxJX2yrzZquZDHdieTx2evEFSvs5SbJybq+5zbTgFqa\n9L+0lcS7lxIAozukKt/r4v1bAIV8E3DGq8SmMsB2UuAnDRtCUKmv1kLLvt/L\nCEPL\r\n=l8sg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEw+kDWutsO57XO6spv3EgANAsOiyMwAKaxwz0B2KqkrAiBN1HAdBH/A8U3Lyh71Sa/0B3IHivD8jMeG2PxKgEi1HQ=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_0.6.1_1605171224754_0.6041683466392365"},"_hasShrinkwrap":false},"1.0.0":{"version":"1.0.0","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.3.6","tslib":"^2.0.3","typescript":"^4.0.5"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"641eefcb20a6566f286af44274b804d833c516be","_id":"graph-state@1.0.0","_nodeVersion":"15.0.1","_npmVersion":"lerna/3.22.1/node@v15.0.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-OX5C0ANy5qh6akVwqlvBbigCNXpkyeCydZo3rwkmMGm0ZieqMAtnT60oys2Rw9RdDsOz+ZNmqt3Ob1SbycFDtg==","shasum":"aaa369892d056c10ec3c035593ff303aa0a0f8d8","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.0.0.tgz","fileCount":57,"unpackedSize":407336,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfrodVCRA9TVsSAnZWagAAJrkP/RPOhkgcoGnLc4D50Zs7\n4xsdBESkARCTXLSLMwYtLd6QJkHxNvXPfGUtPaN4eLIFVmJMosGUd5sLwg1k\nSCv1UjuqW4kJBlreNoUIEqCEFqg1saB2wF1WnUU/kysq/3wHxA4VGna8BLsO\neqz7oJmXktoRAtbdNrgv4u85g4csBIyJExNrH5PNbvOXN0gd77UJQQ1JyEPE\nC4kKPbKg6jAVrrLHsuV0WHQwDOWbClEfpyPisloS08HdCTP6AQqoO4zRMGSf\nI/FMrsNllBVQaGRd/Sy52iI43D75ZYEbH3eKGsylrpMCJkalw/0v+Ab5g9ud\n4Lt1GhBf25oAkjsFYVG05COhd1THHuLG8odENhOts4O4ZznBmKAvjzCpnOD5\nEakhG3FswRYOi3d+qvCUlc//aUm3zhEoiT/a1EJ+3/gocqf7i0qGYERuD+Te\nNV7OLgeglMSoO/WpVz7XHCu7daCZQTL5ltgN6VrIPKEJma/JVxc3yj6lIUEw\n+BGMnMDq4eEcG0m9agD663l4QnRA7CTRD63g/ts4f8juAD3gHKjoecNEqdzP\nJoFcLq5M7IJJAwDuJGkUi3pYr1lwZ3GPsxWuANWR8VaJ4S2a4iHhmSPqoOgi\nczRw5URpoow+b4kgvb9S7j6cmBDL0408IDzFbo+HU5EHHsdezYmQRR6phXyI\nB+32\r\n=ssZl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAQKidugjXKj89zOmI/1sb8y9eIGODkdro5itvx4Ng2AAiAVHhfCrRUy9Co/cP7HOjYE6FqSYPxeVGZk8w0MWlU8QQ=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.0.0_1605273429441_0.28239440061302923"},"_hasShrinkwrap":false},"1.1.0":{"version":"1.1.0","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.3.6","tslib":"^2.0.3","typescript":"^4.0.5"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/scoped-model.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/scoped-model","bugs":{"url":"https://github.com/lxsmnsyc/scoped-model/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"1c08f2cc0a4796e60f94432db2075f201253e8ff","_id":"graph-state@1.1.0","_nodeVersion":"15.0.1","_npmVersion":"lerna/3.22.1/node@v15.0.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-a0eecG1r0P+oVMsA8HeFiPoj3edPKxENEyw5unkdLGODg61BZMyhaYLQbH8Za6DeL02BfT8cwJIDd2H8SeYS3w==","shasum":"ace465b5865e2a0c2ec284d66de0e30b60da7962","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.1.0.tgz","fileCount":57,"unpackedSize":409178,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfsAsCCRA9TVsSAnZWagAAofMQAIt5uPH2fz4ceDIKxl1e\nLAzHChlAo+yHo4HRCnE67FCOCuxZG278Cl3P+nK0erNnI6Ma4l4SqBxCYyAZ\nrAfEIjpYEQ6bQHOvKVLW02D8S1WPQDBzUE73NLIwM7EPAPbrpiymQKMLMjHb\nk3dMCT/iIWprZbWIa3gLBQF0TvL1uUYL98TJ6Pcyq6hEoKnHMaHYGi2cywie\nf2E4ZVXEBQ+N1+02KELDbxdRwOJW2UHtPkS7XzG1iv0CUtxQnTqh0AjMgNPw\n58YaETpKLe3/wggOyKVErpt0Z9JH5iWwhDLzRheSGlVaGDj/mt8mgGcGjNql\nvn8LW3I54Obm9X2bYlL2MORqxZSqNbYSoxt8ahezWRnrbWLEISgwFny6uZBT\nT70tmBwBmFqC4UM7kSVnT8v/C4UIMbDWHASbG0QNA9UVfZZU0ctWFA3WC8Jw\nmQhtFwU8wmSkWULsjLnkzGMNBECBoacfm2rdkjbErKzIC7Dh0ZTD6au3gQvi\nFZJx72loqwyt8UISG42Mr93YVyoZhlnY7IjALBoKqLuVVbyonLJ9fZk/unL8\nQSSKSkstoKGC8rm6+tRtL4+wiQrmIhQ308pCHWAmn0IxH7b2geKb+LEeJNSi\niJe6p+rkwoPf6YCLEcyCs91E4vhjjF75C4JwwZF9Af7S8pAT273Z/7CRZKzq\nEnxc\r\n=srLc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICXtoqeBR2P9x7v8I7o9rBxE67VekoT/W5Fp94Ib/9zQAiBvWbkIEZ1ETWOWnG4TrWDLHLMUCe3QjhMPuYA6p7/jFw=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.1.0_1605372674235_0.5315632593822248"},"_hasShrinkwrap":false},"1.1.1":{"version":"1.1.1","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.19","pridepack":"^0.3.6","tslib":"^2.0.3","typescript":"^4.0.5"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"065028826a4b1f55a5ba25cd3fb1153becae2b3c","_id":"graph-state@1.1.1","_nodeVersion":"15.0.1","_npmVersion":"lerna/3.22.1/node@v15.0.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-0vjXzre13H2UTGMmm2c7ylMK6DnF0idDGbEiBmTN2ejxsJjhTKkWyHsoYfEOea4fihBm0DCAbwDiHKpIgYmzvw==","shasum":"808a028b988d8734881a8cbff3206fd8ba65d9c6","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.1.1.tgz","fileCount":57,"unpackedSize":409175,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfsJ4BCRA9TVsSAnZWagAAz70P/ja5K3oeYvRj49HAbe1R\nZWG9TilvppzMKB7zumSBm9yLvv3atalgUJUaq9MpALIdrJFnrvItISnzfUmr\n+Vr2m/Zok70eJc1MhdH9u0IKebYvVfuw4egasBeiaJKi3lRKPh1ObtyGufh7\nbNrfc5kpw07ED8ehj9NQl9u0GGTTEefwTqsSEXXv84lrVGOvMI03Mq5Nt2Jj\n1aAwNEkH5yShrqvHOepcZJsk1axoS82zcuxP6QqosxwjXzkei2roIvTb9cz0\n+j02QNwFUD/Xn0cx4BUMAK93VLuSv4ssaESa82a/uDdLBajOwxBz0HB3Y3EK\nHalkv/VjjaHmbuqTVw+sT2eKTP6HSq/7BiVCHopW7NXENP2qQLN+1m5eVATT\nufXVEcwxVk+WLCrCoopYI+d5nz2ZNeO9+LOtSUWAdgZSnP+Lo+mEoQ7sF1nN\nFggJ7AGtqL7oOv3ArVofazhn6nYmYCmt7NvMxciXAFqZGG2DMbIYFmC9SV1U\nUOMINZRu2vdU4q7OfA+q1BxNO76EFO/QrzyUIZGDn38vFX8GY+1LzmgcVJtK\nUYK+DJMLf8Hch3osx/2rWS7itMID38vwtxRAg9Q/+hxzU4bcK+PACq5HajP6\nfsm4WMa4ZFXdTFLa3zcAxOMKVmNk5mYQvpCVgyQJO0bz2KdTbNRe7i3+bCtr\nIQ19\r\n=mMoL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDnflP02NsjKa9TQabX5V+QZwzRPUJ3quLZqcowZkt7zgIgcjKV4mAm9yYMh7SIrPPTUQ3y8hzlpYV5bLHslX7Yszg="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.1.1_1605410304832_0.6265424308480638"},"_hasShrinkwrap":false},"1.2.0":{"version":"1.2.0","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.3.7","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"becc0e779e7cc3d4fa9f4f8225d95508ce31566e","_id":"graph-state@1.2.0","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-3KmU+bObjrzWwrze78nMeo/86azpt2dGXp3wkDT1728KMstyYB93rQlgqwfQym+7mPR7v2YNSviVy1/nrKjJhA==","shasum":"c9401806f57227af429a9b82f83bc7ff1b37ace2","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.2.0.tgz","fileCount":57,"unpackedSize":409127,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfwSduCRA9TVsSAnZWagAAZecP/iVg/01Lq197A+Y/4SjA\nI7275ZH3KBOeKklUfJ/JDcZXP3RtwVzLKGPCyVyWJIDp6Jdpm//CCo9XnJA6\nuZ1tvGfL6Us0OnGFwu0urfy7+b4zLnAS0sljnql+PF2/JLF0FsMbP90OFmTb\nrC9FQ0YWmLyRP2c8WnuoFl9xzcDpiRDiAV/NgXkZXWJOdVfPaGMOx3J7xnfI\nvYEpDNPcglAMa+bM93LfLeb8oX7XxUJZr+6IfyNvd6lyNhYTDg9xO0KPwq4L\npnG2H1Dfd4KcYT4Rgax/wQrldo5wQOPsBElNLREMyAGj3lnqpzRE0FvliXyR\n/g1LCZD82WYqgEI8nk8XB1jsC2YMgbFoBBK5tYfZqG5AT8+bul5QQYkshajk\n4OGyGnf9g1OO6IqPyDYDpcv7C+AJrDMftEDdX/DlzIKexJFGuepZ9awxoCWl\n5svR8l1DIM3pJAqcKNlbhyAKm5+stoNVyQ5B8bD9HQH8KMYH+/t1WXXS/PPK\n8a0iqiR2lZCNgPK2dQFUrcu/8ALs0LnFtkJCq5Z3ORvGTt0MER7Zx4Ju2lru\nzUSZl6n5dP9iZZ7JBFiu1z2BMoS+oL8V/v7I6TJDViljHreszQhHBji1unGv\njrGICe/5iQULsn7EJu6J29dwbCGSGQXCTAXlMG6FyrQKzBEKgPk2FOPV9Pd7\nfF9w\r\n=Cg5X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCkCEdfWDz7t8TFzNd50WYa8w8q19iappL/gg55EENACwIgfarM5UG09JruYrO9Qd/Cm3r4jQP3dekenUKOPUpDojg="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.2.0_1606494061678_0.5849261673758357"},"_hasShrinkwrap":false},"1.3.0":{"version":"1.3.0","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.4.1","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"54988921e85d02c54ae71bddd7ddca744622774e","_id":"graph-state@1.3.0","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-caHXWIS/efi6n86YX8uhDogvyiKICBawZaclbejxfQNhiLOKhEbbP0g/vZh6UZOK2AWBA1QfQ1O2IGi8rX/uIQ==","shasum":"7aa9e3751f6bc43007e8dadda6eaf64a7f0ad385","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.0.tgz","fileCount":57,"unpackedSize":409157,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0GOfCRA9TVsSAnZWagAA64MP/A+hGNIO52uPdQo5xL6o\nIEP5DrsdWvOip2I81q4hRoILXLfa7ebCU0VP84oMut1+eZcYr7FdqnBUdTu+\njdXAtTOwoN5sviC0E0CtmmL/pI0Yh+xtj035BEneY89DxQwixxfNC/xXwZVM\nsYbbk98kiZHTWMAR5z+YVU2fTiI66/34Aohuml2UU6XhBygVH7Y2x3cr0Pzt\nanc8ayxxYegCh8wso0zyATDzTZKtXpiq9rh44+N6oWK+zn8u+1usD8LXJG+L\n2s3PUGRj4w1upDbQs0b2K8CQYOd9KMvQKGoc2qK3fpHN+sO8fk3xdE/FIT09\nxv17Dq2j6ioDcU38ma8BRycINnSpCWwt2gId5PCxM8CBKP+nCa3omzwrUdg4\nXPSbEwzAuTrbl9FtaE1LiRc/RqiyogLS/Dt0VXda2mqojg9pUhCRV67rtQHY\nVO4gX5ig96J/7dWgCyw86UVhYcCXrxYQa+eg8HBAUyH7sfXicYdxJlsF3gb0\nDhBu3zb4YZsjCKANaFLtPO7JWRi/hgverOv/46EScV7FApq9YC1bH61LY2Iw\nGRZ39YX8iZfe1fHmTo1u1oM3JQgw5CyEn6w0dZUNu9x5nL2yxIBFSD6tFG5m\nqyEc6c3w0iCkRyXdjcceZnJH4lh2FSXz7Kf6jjqXMthuiMFpZ2ndiLgvKtV2\nXFCx\r\n=ATD5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCaFkOh07RYdCWcm17/3uIvFs0Kqe7Q2TBspMEzdO20kwIhAMclhAmSP9+lPQpdtCDMBIXELO+t6WbSon8T7VcEDm+3"}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.0_1607492510962_0.7626764083746347"},"_hasShrinkwrap":false},"1.3.5-alpha.0":{"version":"1.3.5-alpha.0","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.4.1","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"b4db839906dd83d153d8257f5a15670c7db82a27","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.0","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-a4wGK/ftDGDrzwDxO0uBlC2ImCYj6SvYueY3ccuICJ/6zo3MU3z+2mLjwWb+qQJ9AyLcia99CxxkMI97iHzuZA==","shasum":"46a5dd011c529647ad5952d0f41d8f946ac8dad2","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.0.tgz","fileCount":39,"unpackedSize":228449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0kRACRA9TVsSAnZWagAAXCYQAIWk3scTmqGBT7RPn8PK\nwNNdtvGM4JpgALzPClq2/Y7ZJB1+Yem5E06Wj6CKSBMu3XDgpKhIgIUv3EiV\nSbs27Ig83U35sQcb3xgyEXVIyu9T8NNHt1SCJEOR6nMkKCQ0GidBLSX2H1aT\nK18zR02o8cdSJQ0p1nQmEiiv/YE24L00zeb/Iq7N78QtdtY5jvv8c5bJ9TmR\nlDC1lMDBsNCVC4aZ9jKPzj2r7+lPZe4ARIfSKydJOKsWlLNdZl/4CgRNuPqt\ngpUlGH0n21l5oJNLb+SNiZ1K9u7v6i5sC02JUAnhfelMJUDLOyh1FjioE1RO\n/bz1K7wNWtozAObgoN/xSu4eMhUyhna+vbo03PmD3dSbuyeBwYzODF2p3HTX\nwqD8jPJGs0+ljcIzxiHJaoRdvLd/VxMHh61ywHAYu5atZAtRH/nCFgyD82rL\n9QzGJWIrQto4i9ZBrSqImE4FNMVN6cT+lVtFARt+k5d976NC0WzODs5pD64o\n1Yk+qHsG/iJG70eG+3HbX6bs9a+ZhcDfRc0nu79kMekEMtCXqFnZtbyqahZj\nlMnTorBpgle6mBJ0LOvA6bOADmuQ9172ryvTG+NlLxFP7GaGnGOedYz9WfAg\nPP46fbupL34/Js0QguODnNpQ5u0kitgaSM8BZGC+HrU1uFojVqwdARYFfUWi\ncZJq\r\n=RW4z\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBgPgPTwQxbKYbAUiJtUlQQjHSJt+hWqcdsb62rkVXSFAiEA+D2ithGCKvrpRqPKHdpifwTIo1F+P8uBwat+5t4Jf2g="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.0_1607615552103_0.7022691283119489"},"_hasShrinkwrap":false},"1.3.5-alpha.1":{"version":"1.3.5-alpha.1","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.4.1","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"592fdb5933a33e49d0edc7d87de215e937611f53","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.1","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-Wj/KK45jjnt2nrwWR5MjySVZW+U9vZDEPTOYBNu6AwfcmhWM5sy3xp+hhyX0m7X5dMlGWbIFeaL3L9frcUFsvA==","shasum":"58f0562988c12e8d519ed1d0841c7bec2559c487","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.1.tgz","fileCount":39,"unpackedSize":223972,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0wiJCRA9TVsSAnZWagAAMHoP/0cJpfz9VIfvE0LOKxpO\ne0vtVixCOqFsMSS5SMT+IgHh08Sp1AcHlvCsbSfJAhTXz9Mwah7gBV4unyMN\n4XdZ19Ndt7e1oaAYYye8mUGLNo+SKXGf8vGYgQUihkoGrZCEDJ5HOfC7LVYQ\npGJuQ9UcAbMe0xgsCHy/jU69CEoQ+F6buZEG8N3wgzjVnh7rM/9m9gPPiqYb\nlR62qF4J72rMLAlFFXz5/f08ea+rFZOITPLG2fIE3BoSsH90QGDyipK5SCR+\nHtzx4uBvC+cS2Hav9ZOgw28yxJU5m+HY/DonNP8BYbZiJlphQGEfxTTboqr9\n7ogcbEXkR3MBtvsZW+BdDHV7yq5gkxKfyp5BYHp73e6l6hBTSpojbZKEGGnY\npIvHGrvGQpkUvT6i4OKSIVDeUL+UswDBr0wEsQIz6IzqFsL24S87wMWujett\nygw6JUZUcZOqNWejwV+Zk/mxjYPsMvsJS1Vh7SUyB90kYaCo9unJ0tYYU+Ii\nfXN2WJMiQ0cIm0x0BfByqzrRZvQsCLyxG25xbMk0+hjjPgBoWrerthe5X0+c\nqTJDkLnWi/TD0Wu0nOKROXKII5S2NLLMvYwKOePnn5BIWCILmZrClya4vHbC\nvc1AKS97BLkSFSKyG5ExQ8XfkWjIFfVCbnELuR3vsFaq6Vs+CYLtk9IGBHgW\n7ozi\r\n=o5e1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDcoK54rk3lIY22QaC5Umeu1s6Ey09z46tZroFte+0AqQIgTrq29l4gHzX7E2KNOj6W+2ZAmhdkShP6yKbr2B1r8SA="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.1_1607665800987_0.8248977307542174"},"_hasShrinkwrap":false},"1.3.5-alpha.3":{"version":"1.3.5-alpha.3","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.4.1","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"9dea32d3e93d42511daa8ff9e8cb27dc8d8c28c3","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.3","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-fThAqmKgQu9MEHFF+sIV6DArscjHNQx5P8ICL4Yo7dk7no0UghrvbOoy2JWfoXcrmUXG5xLP22qgKosnpslMoA==","shasum":"9ea355e2c4ce42661f891169f39027284c231851","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.3.tgz","fileCount":39,"unpackedSize":223548,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0wv0CRA9TVsSAnZWagAAwXQP/iU3hU86lEO3dJ1tpjrs\nyjR8KOWR3qsBBovPEANETz6r1mDE0Ndw7InK3PWuzkNPneX29yInxeSRRb+r\nd5lvE30sRQwWsptmvHf/sUal4nFxjNbXr9kmAp11G0Y9vMOAXcimiW8mkw9Y\neER8Y6RkY9pACHiVrC3MqbaPFhRFDkAj0tRH69i++JELxRY5Y2EmMjlyIODL\no5Xd5S3K6S3bCgwxwxg09NXb+1nVFxz3cSqovqrsdLCKf0WMrRyqu6rhRmls\n1ETJLwF+CZxffUaUKggNzyVVeEpXMyzzkZC5b0F+GiFhpv0ftb+6U5jcidJn\nmhwW2m6GqQaNe/e/JKTn/YSqEGqPUfN0yWplUgbWr31HTtbv8gNKs3mVz9g4\n3wvM8bsRyQCj6lsr2rVsPemTMu5PwUxSAJaVO8nPnzUp6eWTy7SOdKX+hlNs\nR6Ds2MzuPOT7GK4x8i8VJHRhyBlcrZ1e4v1q4g6NImIzw4dXSkSrV5RLrpNR\njyeIcK63bitibzVJlQqpIvcON10XbU8b6/exraLr5gbqYzMz6YwsFcJ5r4Nr\nbYHPYLymc62YQ/6Az2QF60AUfytyOqbnej23J0RW4gd46UjlMrcUpKUn3G+L\ngBFM4iGK980wWCSAdPaLaxTLMp8CFF/DOA/CgMcAO1A8IpYHFS97HO7uoeOD\nF4g+\r\n=60O+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICu2xI5iPk0tFK1nzVdFsdSs0Y4RzElZPkixhwnfHpfMAiBbf/kJfH9+i4qUn3e5fJCZCg+vlGN+VIARWTNLUBKQAw=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.3_1607666675809_0.30888355224708186"},"_hasShrinkwrap":false},"1.3.5-alpha.10":{"version":"1.3.5-alpha.10","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"2fedbcf880e4fcbbee50774ca0727fd1dcc91aea","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.10","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-RP8WqfbRN4oGptE9DdTJWRoWAHNA9aJAqjgNFh7PM00tFKY1Ww0aZQMmDb1I5lg9AZJ0v/C5qlRUzYMqXPudOg==","shasum":"68ba4db1ee1a0c134c542d5a1c87da4ed6377aea","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.10.tgz","fileCount":39,"unpackedSize":224221,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1EpnCRA9TVsSAnZWagAAl30P/RRmLDuVg5N5vWZDgJes\n846vHJMZ6ZjB6IGNt3xdJLkNypGts8ezM5RWNRK++nCqzDpWce6OVSXzHVNq\nxHV4MUtdx4TisHiyv8UKYUXJb26zW71OyR2x2GH+17yJdW8chzSmJ+KURyY4\nvCqww42zryhG4x4j4Gr++rRH1gwl5nmXt71+Y2OD3Xb0R5XMzbZPHQWxUEM+\n14C+cJW4+5bQLRIHVoaDWFz37ExSqPj4Ke0SkkCBNnJOPai2Iwhd06YhZA66\nLul+gHaqVwguzc+H2Hzax4wtBHvzLpczYWSezdW5DOq84gfdT8BGvwAtCCAr\nl5YusymE2W3O9cCMVHT+PLf09JqOUJQj9vO8CfX/l6hbobMwkljqLBtOmpbD\nfAcc9gh2pJCz2TWN9YUtUmBZtoHYXc57Ph+a5fJ7ML7f1RF09qI+RQ6EFvhu\nGSZAWSGox44dqzdspR0IMGGJrHzrG+VgbmMkrFHnrEiJGRbXKBTueB3zhyuf\ny+Ft5uMnEBhMwWWOI+AfBZmhNppsdc4r8VKCqL6C6HW3jx9tqWfVfillccXf\nK3QeLlsWN5SDdEE83kiiJ+BzzleJSViRPdQlBSiL5j+yrUqjtcy822WbNS75\n7ebEiNZn7GzcSnlO6aX4r/g8DlA2mMxNpxAd6uNprWxXU6kOA8lnzmn/0Df4\nnVqh\r\n=Cu9k\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDzAJMkB7awn3OWvXK4IT7bBInLowFAlkzh7xYJLUTanAiEA4kV+PbL8aZ+RBVO1H12P/j2K/ZlFKk6z5NhMMdamx8c="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.10_1607748198911_0.9508367621620444"},"_hasShrinkwrap":false},"1.3.5-alpha.11":{"version":"1.3.5-alpha.11","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"ae579d2087b53337b0f900f508784c15ab7c09ef","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.11","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-1Ym8FPlKnfiKSVqKF99fKXHgD42pG2XjfU9XKsRxnziPeWitGeJbRPL+gho5AzckMIPJJLG7pwAsSYAQZB1J7A==","shasum":"938c4dbc94e797bf25c0aae0a05086e51211c482","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.11.tgz","fileCount":39,"unpackedSize":223575,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1LttCRA9TVsSAnZWagAAw+8QAJIB8ecooay6rOaVUebd\nPxVwe1Zp1AbWM5ztvJulMammRzCSTb9wwPWXCG1XSBoWVEWDNP6pbqsdESyJ\nuGHBVHUyWZXseB2sMj3FDugk9NzweoG597NXDrRvHLHsD1O5yafHuNJoa3Qd\npCzClUmCM+uDsu3BlY4yBzbvxKPjS44OzfQugxAsGVQfR5TOljBTH0UYJjbS\ndWgo8YntZMx5P0MDHN/RtnKmEU79G86QZdqI8eiJe2ayFuZjt78QZi3iVdeI\nZ4+ymFotBXb3WwEg/24ttQyMkYZGDT8B+AHs/a8B103NchullZPV00Hoes+M\ncB8oorOimn3GcL8cb3KXnn1NsiWxzyRhprmxvgerqTjK8HlDscdsNhtVF+O/\nMUKQbua62h0qtDLvo6LRl/LxSd2v4mXQ/nlAnc8677YgWtCoqJINF1NCxKnP\npYV/c8ckeFomGR31TUcKFzQ3oieI1v2NKOghuQCegcjqzWBk+VaD2alXODqq\nqSrgHwFAf7lkxL6HybmXh0jsyY5N/INf5AChLEzRWLdBdEk9/Lc8peUb+m24\nej++XiZQzJojYVTRD87jFS2aY+taGiyfcO1VNPNDuq88w2ksnnrnapUAz98+\nFycbqGqoFuib4I+kDZ1lpJBU2EKQUVHP4V9u/KxgQDGB2eo+ZaWO7xWXiHyb\n5zuB\r\n=5qaq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDxn1e0meelQQCBuvV7IfATiorObiZg5oHsy0FJAYGGEQIganv1dJq0/s7g50Rh0SMVRhanHr1quOdWmubt3C/iigs="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.11_1607777133095_0.12350068593691321"},"_hasShrinkwrap":false},"1.3.5-alpha.12":{"version":"1.3.5-alpha.12","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"d3655c2c61823a379e29ab2204b010c329f04cc9","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.12","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-8n9p+hLtzufqBNtn/u6Zl7EmSOZfOMnrXPR+VFtuSwLZz/DDeyW6ybXqq9K36cdKwkItD4YgKcslG2J9dnRksQ==","shasum":"743d4135867adcf91ea40d5cbf392a1405200093","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.12.tgz","fileCount":39,"unpackedSize":226891,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1MPmCRA9TVsSAnZWagAAzO0QAJyDr5FC3TBuyx7mjY+z\niBKUYKlr+aqfnlZ65cbNG6AFNq9BOFvvdEVp0xdaievjt0MYxKBEpvmOPLGr\nXYBBed7ax3asxIRiQCjfotv76og6s80MmUHyMjErhB43ZPeHQu6H6GxTx2nk\nbLFqAkZJIutJAXPGJbPEzMLKpO9HJyp85hDotc0WYBMLiTeWImSiu6Hm8ML6\nlvYPgsmwgG1UQAhm3nwSYGx7QFL9j6q5FRZKzmv1NNpv377OBdUZZP9cSoCS\n4GnUV9BLbRMiwrexx8InEqMU/nwkME9JXD6KEfDhhlR/QZB7hd+cujCRHcg4\naEhLWWDsGLWa/+eZ27JQvPr7b/ZxPeHD/kas6+zKOXGbL6eLGzwg5qwA9EUZ\noNlV5DMBBP89VnJG6U/fxXZOZvKBRYJD888tQMx0EzF2/mTadjoyA2foVlTx\nECZn4UKeEJKwYHPDzKZP2S1sZLpWsIZC4l+qhLhiy5avtGxAQDsMoc9dcbm0\nPqiwVsTzjqyhoAnHA5E7O3Q+7i4FJ4nD5cNgcS3JrGYuOQvPO+sZo/Kxlx+T\nd7vmmpw1voWrDYzNKiJcQfxnMy80b9lI4eawPNTrvVcBqh/31JTMgxMwZrQg\n5pp6GLrwroawqBsBXql8CjmJ8+LsaUlbzcyHn1Xl9CEqpfi04692e2gF3BYP\nhsM0\r\n=xgG5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHm+Aiwb8COxwrl+9EsBMIjZR+hiS1onFdITPN4HfwSZAiEA+0E5TjseT8tdj3qsYYn+ITqaH+idOLvFB2Xycr30ZDM="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.12_1607779302303_0.4337875964900004"},"_hasShrinkwrap":false},"1.3.5-alpha.13":{"version":"1.3.5-alpha.13","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"20c9bbe341d83ff0c1abfef19d0a1f0a040d22b2","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.13","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-kjxgxpR55Nt6wBpY0Vff9yAEMLQTYR3nrN6YoNKhjOYcDpEZwbo4JCOEmkpQ4QT2HHmoPGG4XymSzG+j85Jd2A==","shasum":"49e07b412a61d2e2d710a83921f0e28e99e60016","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.13.tgz","fileCount":39,"unpackedSize":225833,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1PIxCRA9TVsSAnZWagAArZ0P/Rm9inqQlZB/x1zCmIwl\nt/SvkIRIPPV0v8rosGAFwuMECWkfpNeXNyQslBBSGd7YjYpRLOpmV6TFTcPJ\naWkJxzpm5j5BH7cpH4LJPPq0LyxDxz7XK+MpFrzJR6waW2niWp9nhedZjfK4\ncN3tiL+GdDDfyeV3mp77uGuw84c1HQUMSD3hZJUEVtV7LOnNSzaZmDqFuxTt\nkK06/Juu4FoNSds43b/XLtu/Er5gCgZZCzYrEluO+xVU3I4e9/8kecFXLP0f\njI/KR3a8NfFU7AzbG7a9t9O9l15l4NFND7Ea6XMYqeGBS3Lv/wTcp4iEYnBL\nxW42nfe8ZtZYeWyjJeqUnZrJM4t9dhbRsHY0Q/2OzMvzB5FIa8Qh+sxm52Xn\nPUfBEPnbAzt8/Dpgfg/dLd4/0a/J7qJ2M29OuFOixB/h62UMs24CXCZHa2B0\njGB3c0uzaZ/HPQin0ySaZYm9u3BZaQn6djw2RxJ45sjyqkm1jhz6T5zx90Fl\nLxovVKcYVazFaR2LB4X0j+N8ThdOLYJUwZU2weoIxwHiK9mV7TqHQ8soJynA\nzYyC+BmeLQIytdSgn+cUlItnhQqJw2ae49f+H+TPzOZpdWLC3BxXDfsVFHNZ\nAyBCDmQpISdcBwDJE3gml11R202HaWyrDVnOcO1RjIET5BuiDvKLL0Ua3ToS\nL9gH\r\n=4CFm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEJutvJVW4IX7/9QqF6F+3JPg7wnakstimo5XCuiinMMAiB7vuSF/0gT1KZWO+RJ2m+td3zKBwcaoyjwQT12tCPlaA=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.13_1607791152785_0.70126007367535"},"_hasShrinkwrap":false},"1.3.5-alpha.18":{"version":"1.3.5-alpha.18","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"8fae3401226ec1af30ea31e1d268bdcda7565af9","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.18","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-JgEn+zIptqqJS+UvDRzJ4zhgcQS1yPdnk7QQWI+pxY9bmxYVWBPwBAdgJPhP3pQQACyd0COknbGlA98d1Ek0vw==","shasum":"2102a396ee59fb7d5e60afc2e6c38a47b96cc5af","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.18.tgz","fileCount":39,"unpackedSize":224653,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1Po5CRA9TVsSAnZWagAAgnMP/09tVOTBoSiiuRXX4mMP\n8hybScGfCeig/uho7tPz/HzJ/EkxxQ4P3G7qkCvhxsdeA1GrtzOhFtu9BJPQ\nHszUn8u8mjjycAz/K4wgTE0LBUluz8TTu1Hu6/fdJhGlpOp95lJLl5Ae5tYj\nmGQFTiWJQtDFR4u6npPxuN9IAtNhXV6NA9lsXwPSEDxH0h/roD5AV9GeSvCp\nDZvXzwIJiSo3xxProOq3LvUoUiHoBT+AfaT8tuG7OzdwfGp2PhFTDvcd/ZsV\nAotMh4SBKy+kJpb9HxPpwjmAoisaWhEIUw/dkS4Wv/rSwZ/dUMJnYjIdO7wh\nDGwzO/iF8C+KYJZgdInTZwxcbFrWg/2V3Rm4sZ+S044Gk3KNjG2FG0PcasNN\nJhYwbxSR6INjn2xCTT9FKsPnZ5KJcDC6kcosX6RQ1YS/Q6kDqY1isABnU8SM\nsQabhzLqfkLrwPve9iwwe7jTgvJEbDanZbznkTz3IxdCYcfjhBaU93ftZo59\nHrIeZNFqxrSl2R7P/jn0vBKS9Qq8Afc2q5U/oBxbcitDLLkQVTRlvYlF1Y5k\nSYb3pJyIMaB2D8OmtzaK2VNLvCL11P25P/6jBHre4i0gNXqYP2BObWNkKKsW\n+3zPiKGJ9McqaDOr+VisClLSkreFVpw6bR8JhpZe+DkQ1OQn4SeaY0XQEL6P\nabqi\r\n=xjpR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCnbM0wyMjOVUoIL/KtAfAUnw4JkjZo5GSbxKknFtwe/QIgXvIEMF4QMbvEDoS5MWgyk33BnIm62HcZFXekX4bXnew="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.18_1607793208984_0.19556325842179634"},"_hasShrinkwrap":false},"1.3.5-alpha.27":{"version":"1.3.5-alpha.27","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"b5b305f1f5d3c6973a2f2ac711361c61d44d5aa6","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.27","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-5iXgJZ0NjbvBBaWxYb994vDspKSc7PKXst9pkwG8RAxBytNNgKZpRPOSyKFXwovYrDtyqvojRxAF1SyW7tUU4w==","shasum":"5141ab1368b07f60e71d64c55592643d7cab4f66","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.27.tgz","fileCount":39,"unpackedSize":226757,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1iM3CRA9TVsSAnZWagAAwZ4P/2J1ZLpVahT6sxxAKifB\nashrcO0Y2HJF8pd+5g43Hw3SblvjsHUkcSQ1/T7c4CeBfDgD+Q3BMwZX8/Jn\nUrFpcDYvkWUNG/qm1WKaEPv7oIXbVjNJM0R0fCOBDcZn4/olSntdPmyZKz34\n2q4RdziqphHYtdm0qPxTfXDlREZ71J8QJ0F+PbdbHw/Cwo0oiz8fj6Gc1qwu\nW5ubPv1n5iFOxlVRrg2umpQZNkl3w9Pda0zt5ECL2U/hJnLGCEfhRABmiqk6\nzRsLH+mFLAxz8R7zqXYJCn0EvgNnLlRqzSd35LRov8lXgLLKsLyH6OfyZlrc\n0lK64TvKLWvZAkEy3KwjcOn5/hrH+XW2LhlqU1P3FUDTXx5+nEhgdTWkHC9R\neL+yM0n+5jOQ/H/Qz+5Gazf5Wi9pSwSu9Y1sTwb3c+c9gmRb5aWGJ4eMMmqP\n7VM/fCSgzjK2i/qvi18dH1zYN2rbr3mk3HY7Yj59aXVV1zzSdTx7Eq3xbO2b\ne/GTe8WxCp8DPzIGKkyjJrjROZL9OgJknFqT1ecRNSXrCtJtO34n2S4Myg9S\nOHGJ9GcHCCo5x1SSxGkDtaqklc40y5M3n7vFWdHkxZ+iGs3mk0NRutzwIk4v\nXloQYH20ocibXPzSQoXjK+ak3U10FwATes+j3IljM0usvYs+d9E1u70xJDcZ\npPaP\r\n=iWBQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGmAzHyw3pfKIUt2uORMw1OlbAWhYcK3+nXg2J9PPPyDAiEAxjlJu1u41vpKdKt5zq8mBgOQLgxhrKR1NdmqFJVWsEI="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.27_1607869238986_0.8800585290053844"},"_hasShrinkwrap":false},"1.3.5-alpha.35":{"version":"1.3.5-alpha.35","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"6613c08dd23e8b2a3af5efd7b02a1c18408e4c88","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.35","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-DixJCMXvdxXZQIXeauFcvbW4WVMVvJbHsGrjiSXCBqk77Un1VhBcBsavcNU1YgNYS8io3Rv0Z2d1ToXkQRIzVA==","shasum":"43b14cb7aa351beed0dda8843c3f18976a0b0e04","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.35.tgz","fileCount":39,"unpackedSize":229654,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1kUvCRA9TVsSAnZWagAAo4YQAJPhGEY+tdOjZQNEuEkn\nda5NpEZM1GQt3G3reaMt6+nTKhftyeejN4tBpv+1XZZWxRB+PhdUyvYJhuyW\nDJxTuOrqn5bmoIX4mUK+tZvJSvnyc0aU97NcnqtmC5o5utNeCVmSZS/VfUOd\nmE49M7zUYczlHggYRJHmvg2lW0fNkJZMhCMRZLDcxM0iNRa7gdhUdXsFeUDB\nWmkt1GwusljrG03vUWzAkoVhJBBjCSHpQaLMeKT+L4Iv11qRvr7fEHFmNYA1\nD0f765VDUMUC66tcUtWpBs3Z9YQ85Qse/Asm6z4UQdtE+0BJgDHHVQD/5TXb\npvQ+BcthR018S9ZlYcKvgQUBhKTsqCxiN+SwUPMBR80f9WDmMpBr0EAoMIhj\nLRGBRYisnilxfuoRND32DM2WNzlTf2alF40+d5Z5+fFtzxAHPnb54XNEFUqG\nIqef6R+5qF++LWOIeBcofVYS7xVKHUO5rtTPlMmEg4aZbzmJs1QJYj0Wi8AU\nlczvO+iXtuk0VhyyVopCGxt6Pu3s+0bnj0KyojZAGZa+K8s5fJjfGZEuvxit\n9g2XpAS0xbOxfW8O6qkUCFVb5e8Va0GOWbnc0sH+L2cweECUPoXJaEalKk3I\nuQR6v3JgZWVaa7bBI/YzEMAAe7EOSwFgftdYUUnpKsVFlF1vtLUNyTp0fdJ6\nJ81a\r\n=+g83\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDy6R6LddXbqf4DxyuTUoIJlZEqqZ/syu6AV3miIR8JKQIgboSv5gYr/eF+OnZtdNrNPZmykihe4wRJClRBrHFAHGE="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.35_1607877934746_0.0011017452363666358"},"_hasShrinkwrap":false},"1.3.5-alpha.37":{"version":"1.3.5-alpha.37","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"e482a1b64c12d2bf7fe9299c89a92034ce5c4f5d","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.37","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-lHbKIqC6C9qCe9Yip9syX/ZpCUGBFmCoIBz++AjcnhzQazehjHyKL2kLvDib2S94J0UutmlJ/9BtkejCqVSqGw==","shasum":"ee7c06a4e4a212e87cdc9dbdd73d3b03d0e5ea9b","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.37.tgz","fileCount":39,"unpackedSize":229770,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1ksCCRA9TVsSAnZWagAAMUQQAJ6zkN8KSI+UOLk3trwp\ncaUS0dqkUJj0ASN+n6cDMlVoB9j3KzqOFhFeT9XbYTFJYPnRuf9CoBCzzo1Y\nB9pZTXI/Gn4piE6/WRGUX/JgSlpJPJcuwf00NXpxPUvqwtynwnxdVpAgzBGi\nF9tW4TVSyC4P7iMorLIMluM0QMdhdDxeNNVJ3wDOs4U3BXE85iFqulfI/pvC\nmlB9wpgqXZAgrtsXCFY7pTJNSh+4bxX3orTSrk5D2Es7XEKViecbPNzRqvYV\n0xBUhoVwLZk3dALT5pjbO5NoCgNXRm7/eWx018CvjZnKqPrFN3i8i/lIX62Y\n906zR0VG+GjSKiv2X9eMoUqwyuiuqxnMZN2d5xuUKAiT0++biFuH0GquZ9QI\nnbvqC5d7aFBc1p8Iabl21trLsTVeYuCiJRZaGGxRKaYLRJ/t+STDPkDKtsJC\nrHeBmB6GCtdTg7e8UUoVxr03trAQuosED2Zh+P4g9MwlzlfZqfvD2ibCQgs/\nkwoHnFieh0B+HhMSi7c35kEAO7IBd0lR7GlEAHNCO1XV+40hnZ3vSEUNBKP8\nS3Zs9Smyy9eMF0MYSzB5u7stMES9vSoZ+mInpv08WpmDkOqYzsnHDUD6VANd\neiPcSgsrtMuLMysr068j1NdRq5J+tmhMuNbmTiJsRyjh49CaTCVCzIZxctjf\nPmgN\r\n=kkPQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDjE9NwQCB0piDJfNUW9FgQqYtl75Y466l9IN1aYgw9kAiEAjjfvffH2/ypVhVNP4gNYBDunPuIfrdSEhNoRz4x/cp8="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.37_1607879426294_0.26604400417876195"},"_hasShrinkwrap":false},"1.3.5-alpha.41":{"version":"1.3.5-alpha.41","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"7d72043ca211166eaed16c5f6b7d37b00486aadf","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.41","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-AC6AC98MV6/fIzwSyrNPLHxgpzQw8yuyre0PnE5DVOswrvjpaP9HkpqYyJlGNjQEOe9A9DFwRkF+hKtliDIYlw==","shasum":"b5401215b8fe75574ef9ef2b5de25913cd8f5f4b","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.41.tgz","fileCount":18,"unpackedSize":195693,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1lWcCRA9TVsSAnZWagAAGn8QAJCNqn8kK2/Fs5ux581j\nnbRa8dNE9cIYt1FGTV88Pg/6pzykwKLIWjPoGh41up4tiLw6a1uWtuhqrsfO\nzJcRiqCJlSB2ejigm+uMQreM+1c/4tTuyFTU5jozoF9QIxj4kq8zYfxLUN5g\nF6v0NCcVoLomPiwKZKO5G0m2AYneJ8wBJvwzQLzHbbYWYi9uT9CwJ+fJsJxb\n7WRQLjK2qIqzLIyJSjKyDH8ixfrU2A9doMuVqqEzduvXFEiod3oHmNW6SrSH\nL+V2FIqXGlxFilYo1yrLqDEMPESlbAVdTsHc/TnIpbiBkk6o7lOOrpu2ccvs\ntssg0zGlSe7M+NdquXs/6iK/qY7PmLrNANbBK3tQX1f47XLdAgd2Cfp8mxZh\nEdhrTKhzESwyX6Um3hEwTHlVFUxZrlI+zNRLHpgdbfN3crExgaTXgaeq7l5A\noJDrIZZWDQywU8IGhTheDbgBNtamxkkjsLF7UJeiWbCreR0iOb08QQZ4s4Nl\ntZ7D96gKtcvzsVxxSKUg8o/v2Irm95DvIRc4rkg1bCKaEUfcv0r3q35jSdDw\nLJuRuGoU44zTLkXOdv5Bfmnx0ZZR6oDK++8zObmYXh8lDYy0dtXUHBx5uX3q\nt8SHdKckhCUZsjHMzuGlIrV/2i35+/jONGvjx75ECQSjvCQnu/4VSxrAPJug\nzYMt\r\n=gOtV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB5tOauJSe1/OU3o/HjDydftLLDi8+E48LT4Fm9rliXsAiBGvqJfhqBbfogOPBAa0DNI60GrXMTtiFNmWZPovv+UQQ=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.41_1607882140054_0.4058676830117882"},"_hasShrinkwrap":false},"1.3.5-alpha.42":{"version":"1.3.5-alpha.42","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"601e30b6692e172e57c8c58f32d7dfbe6792f93b","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.42","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-57U0Ky17IkRfFFsVPs2VvHmp/kK2/0RWC40B8NKBAY817qf2hAyhUMjXt4VVTIXT7LnDcIQb1a8jSjZ6bDvnBg==","shasum":"3b0016f4a7dd7fe7de0646039e85b9288fe0f96c","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.42.tgz","fileCount":18,"unpackedSize":196752,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1ljQCRA9TVsSAnZWagAA0ckP/1//Xu2sxFpdmLlIci8T\nt5iVuov2jQ2vBmWH6IiIV39d0B1dkP/ztBDVETBfnxr7CUxYIn7sG0tc0Kmk\nlXIqMncUQEFAK13oypFjPdLoJTbUZaGIYJviAzr4t0RUxaJgUrsCjQE8S5w0\n8dvsVZNo//m6Eu82iuHI0cI/jOBa0h+kUZek94yf6Z0fS8TQSD2m0E0RBiTq\n4lkcwfijxplDGoqChqCgpPG4yBqgAp77HDSaBwuIXO3N4iJmEVWDwSpaCHUE\ngX+G7Xvb68jnRT0suunj4NQXQc5SgLVmhzH1DceFRNwNinJKqhDzUOaxbCCN\nJJXXE6xGnnuz9hj3X0txgYzwd88CAPo4u56jsH2x3UBpjplyrYWJ6zajY+Zp\nHTLM7q4FhHZkBd2uVPHvXAEhVyuFXK3lpH5wMO/z+192KNQ3d/e/r5v9/5bf\nwF70jdAQgZBvRZaZ5qz0kTFqh0gMLaAc4+Lupf6jkvCStBYWvJJK0t4gzXt6\nBVbPixhBOx+gb9xb1VOOvnURce/RiL9n9LEqah7J1D2g6CZrLyZVjJhLQBQp\n3qHg5hG4xa9+F0LFj5HrDNthzaLRhoJFvNaiegL/x7lidhbSsNDJIUSOU6Jd\ne9/nhB0ppI+S/T7AEWxYnWmrtUnZG4IBkWgskZUDbMtQizTIELPWnCBiAgii\nxrHt\r\n=X3F7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCi3XUtQ+TsewK174nA6XuazJL7ERVsCJWFSdTA5vu11gIgd9vS0rN8ndbTrn6w38t1RFxug1sXJvKX/0Bsn0+OwyE="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.42_1607882960560_0.9484403288850345"},"_hasShrinkwrap":false},"1.3.5-alpha.43":{"version":"1.3.5-alpha.43","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"c8089a4bb44c4398fbe86d2cdf7871ca1d67983f","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.43","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-4jpda1gwW/cpXVnprPYdWO9B9b9FjvsHX72e/U73OnWEYlQTk+jc5UUCNMB+5gFp4eVytsaXOAoLmn1CgACBsQ==","shasum":"e6ef6c972e04ad5dd1da3c06650888b382d9ffb9","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.43.tgz","fileCount":18,"unpackedSize":197057,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf10J0CRA9TVsSAnZWagAALG8QAIo17P/k8IoRn5r6l3EM\nGPZJ22BGwH2y8DK7M3uqN9m93uCq5dK0UnBPb+Hc4pW1K93agYzqSigNvaMC\nFpjYwHuNB2bKqVEGQJR7CQotTdoNkuLBarYPSnmhY15X9lv73gd4U0ylM8fo\nOJa8M0Vf/pdH27pU0ommBiSJ+gLVYo9+vgp4hXAp6AgmcVuQyp7ci9zQYtsj\nYXSf/K5n6ti8GPBJB2owQ+4/K6fTvCWrTB4UrCISI876oJsg5ChQXGECsmFx\n0iAQFXpMt4F+J3mP7yis7he7cprHRrpjnsAZaXw4LcRzZuidWZlVixfTTV6k\nafRWESWUBV3MlmQYU5j+gCPvLxdWHvj0oJlpGKZGzR0WDgm++wVIehQxcRnG\ntBC8TtUfgWilnIGQWYx1+dQqYXWONiwfMCsGZoRJreUQo1cgqtLBiMhgV6ue\nn1CjOTfciWNAiHKGuYb/6xxgbHnioQlG7kws6lnJNtUyA1z4fSAlr9C2gBGD\nWgZldrUIKPvj5/HrCQLwJVrlxT6Zg8Pjd11eCS8AeCTpHD3Jt5MNzsGeh0WT\nz0I5ybncIz875AxLTD1hbyWsRT6hdPOPs/OtAiS5c/M/j41AgkUavwOdH2BC\nblsIA5P9H79rWVuwUGRlvXt1MynoFF0dmZLx4Ou+exiLFIkxzMF+U6nBRfoE\n7kON\r\n=o3Qe\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDvmFvTzyZ17O5bXWGDkqtE8FXihJiLQMgHgIW3nzIUcAIgN/f3GcME8+/xky2dgYyawTJWdx/81ZhvTQmyDeCe0L0="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.43_1607942772389_0.632992739916959"},"_hasShrinkwrap":false},"1.3.5-alpha.44":{"version":"1.3.5-alpha.44","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"31a156c67e1a4681ecc1df7f945237c1026ff0ce","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.44","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-doLIsGGenL9wRCHd2F0zNUVz6hN7/GZvGJmwqXhSZevH47tIZ2Q7NzL/OS0CbnxhSlwgmdZJYnEjUiDxZYZSMQ==","shasum":"a1b5915621f0d80f3b4f96249ddba9984b021caa","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.44.tgz","fileCount":18,"unpackedSize":194245,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf10TJCRA9TVsSAnZWagAA5jIP/jPcGfdQXTk5xElm+vZM\nosekqWCgc52IoNAAMGsEPp/jBNWAWi4u8oxnuGyPZW9KRaLBFRQH85GjfXe4\ns5Vjkz9EUPBJ+nC5jOaZZNZnpGrtsjy8iaIGsB9CUEO1Z6I9hKObvBrioUsD\nEztTb7LnSnRU9Rel22iTWNxaiGDSR2YsPekJ4NgVIBCZEwSnWtZZs4VpUqSc\nWhcS4YFRzAvpYPGnAifoPQhwW7yxN28/XPdAlGPzollLCd2KToabhw6bOXAs\n7maDcqskqsOQUHtLDY7sDYJaojCiuptozDJPfBuMKj5k+vWX/bUaeeRqdvEU\njh3YJv4HpQ8kkPQyq8nOFNaGUYEHyu+KQlHsVAvgNMTj25NzxVpv8u3+cWGW\n5puACDb16KiRIUnuKavOMJ1L2f5gu4NVVEHMmESdBtaCjUuiKFo0UwVpgOwy\nj51ik9MedwH4a6sTRRi5+ZYk80SDDFEWMIt/1wvv2naPFVfeXKV84o/bTQzj\niwnyZvw1MGuD5Ag0uIU8O+QxJ3BSPEtAsgHslGqdk5GT+72rf2mxDEq04+Pn\nlLHejNNuUaIgQqRXffLf+Mm8gYWsAHvGN6ibx5QB1zCymjVLSbsT4ViYmLaR\nC+X3LrjoSRpPKjFrm7+YBQ1wukPNqrUnoSsc40NXSC//ZfNJ/Xw//rwZhE/5\n/LWq\r\n=osWP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCCE5yaK8KsFVfGEIhl/QnJdmGAFzH3S1J+12u/y4f+hQIgW4ZIGisw0HsgNFLV0Vonqi1Rf/e/L900Z2r3Pc1o7iw="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.44_1607943368819_0.7209225149210259"},"_hasShrinkwrap":false},"1.3.5-alpha.46":{"version":"1.3.5-alpha.46","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"610aa0bcd732d5f2ceea32a25d2fc3b916d3acf1","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.46","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-Flybv4n7n0vP3fMZvf1Oh/HFuLOjvaDrRkHPmTyze+FJPvmpkM/r02Rl1kSNpNhcrWp4S+c0yHiyv4lbd493ag==","shasum":"f9c32c0657ad040eee0b5d697526531dc8edde01","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.46.tgz","fileCount":18,"unpackedSize":194307,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf10ZpCRA9TVsSAnZWagAAGQ8P/2KFhgc2VpagwEAc2W0D\n18PZGgLWy5MVVMnYNbjeJEDpc9EzYRfizTLFTgz/GHTsuO8Bi63Aidd9mtdi\njGTHY510yFh+N9zJUWCl5mwfrNUDFW90KfMd/bRiJGj2zGQWTEzfHImg8vIN\nQFylTCCtvFAfpe2mtYBS+VfAny4pby7RzGVs129TgINqLHcZ0wbc6fKI2Ewg\noUQhQVBvGcplzOgmjnZ2afrShd+F39aB9wGo7TJnBsrNIgwcBqh79qN349yJ\nkiGJY7kfzn02zfW8LxXUkdbJnhFS9fgkyBIMu8XO/3kkBD8sbPQHt046o9Hr\n9hktIaNy9yFiJf4uPXMrTsWIffJ/okusSaU9QwMmKBqw+Xj4qmEDnIV9EdJ+\n7x+9E9SSrM4VuRf2kwR1g2gfForxjYFTWJMMD5xBIzdnmSNY4dWaUMmRxLyn\ngpiSnOkZj3b8qw68CWqX6T/lUqwybJEExi4K1BE8CHwofXhjPmt5jUO9DOn2\nHDeDHI65Wn1I51PGCQ+D8Vib1ji4hQwvdoa2ccfqKaruXQYUOGQT+gcrKhBw\nT049CcznDyXoO0Ou0VfRicOC8/25sM8s6PgbdA4cmhQIV5XbJ6Cl5yvIWT3Q\ngXPbti9jHisIQ2eoD6Q3frD+Jt1AjczwixDNrtL5NGIkbaYXG1LHszEdJL4o\nBCht\r\n=2006\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIE4PrqDBVhzUNekhZ+JddgYPHJ2H0g1eEO6TpLDZWxFkAiBU5YyMKwZsnY0e4EZ24GATW3h/L3GetyZqYIu/rV9+/w=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.46_1607943784613_0.9776840397133733"},"_hasShrinkwrap":false},"1.3.5-alpha.47":{"version":"1.3.5-alpha.47","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"258ca1869cae94c794c293bc9258ea74a6af6440","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.47","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-Ieq7gwPDXBgy/rjNLROpWvjB4q1EUmICsVCWgx/Ra67dKwL9Jl+LCJEQZSWhD8Wu89qQ+0vafBpspnAOHgGBuA==","shasum":"d932cc935ac8e7ad5729498efcb9f41b44081f25","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.47.tgz","fileCount":18,"unpackedSize":194067,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf10cWCRA9TVsSAnZWagAAGdsP/jza+zXhOs3Fet527KqD\nSx6LLK/8zk27bUbAhfVVAU+0WonANZO6/uxq7fBQqp5BRf6k1GczuXImJFdw\nAzz4gjgfepNqDfLeJI7al1Fb7r6pLYViiQJVGEAPogbbifMzdCEkQVC+9GA1\nZ4SUr38m/2NfD+LpnLJ9HuH+rxHyVwwyDbGLG2ReIAkZ2HCPaqrL3h0/o1X9\nzWcpYh81RCiozNytUV3ue1p0g3WUK7RnUnWTPF1NE1kzliSqM23Ijf3yFkSt\nCRmBkw0jM6JatpEEgsrGlUwiZ65wfoF/rNAk+iYDS7wfoP7bGDfS1BySpxFG\nSmm2iKkyJqchl8wF9H/BB1VXDwFXPS7P2kgWPeRkkOuu7jrJmW4k1fHEGhMc\n2b6z5hD5EB3qIx1iMTkudSVvQ8o3XHMAERtro+kB2g6W/+5Oz3EgoJy7zedh\nhnti+1BDRgjpVCroGtGJpfLORo3I0OIOpRQhwxgtC50b6mj7QZ5/tb22QUBQ\nUVsd354mm4sPfnVhV2tHk2DuKGpOMeTUtDoTUSLTPdHiAJtfaXB2l18+MSoN\nZaO2PlWKL6rcfR10RtdQUcy9bKqvG5EYje69vnGwUc3KnDUJgbiBhrCjP9uI\nwPTv6R2tWnRrd9VOhhOyInCmLqNnojJZm6snJ4mxaoocf39OvMOwAA/+qnQi\nfuuY\r\n=a74K\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD0s8Yjtn4jYF09jDWfzP6Zun64WAm7rwinXwLlMZ3JoQIgVhPJBgLYTucqVMSfK1RZxNxjiJWpmNHO2TRRrHsq1Uc="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.47_1607943958114_0.20925540194792291"},"_hasShrinkwrap":false},"1.3.5-alpha.48":{"version":"1.3.5-alpha.48","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"844bb075cef3e7a3183ed5ba9caf247adcb79b40","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.48","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-bOayfvSJ/jOSC9jTD92eSYsU2aPoYXLOY+BRwC/CmU2NT2HrdVkVAPXaS1YqoL/aynxCZuTKE7pthThUk1viYg==","shasum":"76f291e2c25f3542b2c2d83a2613eeade39cc47b","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.48.tgz","fileCount":18,"unpackedSize":192217,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf10jvCRA9TVsSAnZWagAAHD8P/RSD05oJKLnGHi4HAl+A\ndi7u2OHM+mlz1HqbElRj7+ueGOiTNiu7tNQ0J8xxygGrmz2khKgvbNUvLxt0\nPYPkXDJ3HJoIsrqoJ045IYwpzq8aWjHm1LbQHJqiletrwQF8uCIcxY+d72UL\n4O3Q6YAVEW0S4ljNVl3LkmyIQPbqpDmvDbyg7sxt/UG+bKyGbW1JysVv7Tdn\nXBPwEjUjxbs8TaCGambahVlRj3TR40BYcixqZtex7V9VhOkGPo3bYKNmut+2\nNh8GaWgECRw0ItijjK7mNmW4SBEQgurBf1+DaJ3yOQmiLONEln/OXPWhPE8s\n17CqEZvYj5xNQ2GmkkfhnFdB3bumVTJkTFm6VI1Ewso5CD4TnYNbqnX/jEs0\nGWwmgr2+uDwHOEyL+D1FTyVkOdPxMrnhw4F/esp4isW7Jk5QN3jGZAJY22t4\n7kkcGAMR5m3IOAFqxk38W1d3jZ5ozi+sQFX39I0YSmdBm3I/u+ckRWvtl6+R\n6i1cHxYFs/uupVI1gW+vynGUBAWAfu35MtoFJ9e2cuP1t79FqaXRRZiTb0RJ\nG/V72slV/+zR+PSmPGN19MEwDuxfvFn+7/Q17Q5zDhoRWoYEE0ppabfuHZpN\nl3W6depwYigc1Rk532bmclHUmRxjd8ESjz5nJeye2CxLsIWJOugQUKwhJjcH\naILE\r\n=sJd3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAMEDXQqA89NtC9tlpJufthpUNJEqjtmomomsQXVAip6AiA00LUeq1I0MUY+hDVLva7V7fNl8Ocq/+t/7yOCJZlzZQ=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.48_1607944430753_0.6796657293917161"},"_hasShrinkwrap":false},"1.3.5-alpha.49":{"version":"1.3.5-alpha.49","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"3562ba7e5318ffacf6d7c8057e787a10dd71b42f","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.49","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-19yCDwxTCTgwzVZrzTwSZUpD6BiZ1Y7crEWW7+hrItgnHF1bWrRHnLtMZjzsvvKzTXlOO71M3CBS3GWOTqY14Q==","shasum":"43c99675495ee0563b58cf98204ea38173fcb90f","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.49.tgz","fileCount":18,"unpackedSize":192921,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf10rZCRA9TVsSAnZWagAAiegP+wY6bAWw53/Zb3d/xZUi\nWe19Uo+P8VAs7+JDBI7jMHefm9vPSAg9Yi7r/o81Q/oNqD4Y/a2W7LrD6Hpb\nbzuE82dVhcJ63hOhUHuwVpBmfZ5PvDr1pHuwSQ+2Vkr0sVmQj8QegFcPJI5I\nxlvxO0RoXYO1fnhKiCEPlP72kjUy+/Jh60UWz0ppeoUJ6b1iMQoZeywHpwGQ\nv2rRMLwVWqv8IBHWJAxAuqXypwJ+tJJoLLg8/L7KAzqk/yfXuiG9ot1VuMdK\ng35CI4oK9Dn7ME7SrnD/KBDR5zz/vkeENOIud6iNieTeOE+iBfQsuIfePSnX\nIkIetVZ6Z47nBrAjXkya3xPWTYJf3NZWXEYrX7Av1IUZlkPXEYqinkwxEqIC\n+RtTgb7rEciJ6osFdZjt37MtuMGPK+ZvBu6cJsS+rQIdzq5gI9Dc4L48cI+E\n37SjvryJxRFnXw3MwittrlkKniGdMkVpKiJRIwadcbuvAcJOAQzdrw9uQ2Mf\n2cFshqGABwo8mYYXZeBv24vd4+Mn7zoS4houiVI0B/10I1AemmvecZJ3q8XI\noIzJgje7PUArc5zJ6PVT50mE7H9jVUlpIPEKInT2CWTbNKHXrCcdcF/gqOq3\n13MP6UHc726+vB8Grp2IfeUvaigEi5NAW+o8O3WE6tomJ2c4/TJl7mPFWPQX\nWBaR\r\n=Aikz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD88tOaGH82FTGSKpfIon8eIS+G5zL2Ajq9xLE92lGhGAIhAMdhL9cPmG3g7VzH5ORQzdDM3PP8elB4hWE012uYgkX9"}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.49_1607944920550_0.8441245345442994"},"_hasShrinkwrap":false},"1.3.5-alpha.52":{"version":"1.3.5-alpha.52","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"1b8142cca9f3595c48c93df21429a415f10ecac1","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.52","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-HaHy8VNwFyzhS6GgCJokB53IEvfBVpUjgdKU5grujgvj2tTxu6k0yU3hgk07YmOOjJ4IiFl0DC9qF+63+whwrA==","shasum":"a50e14d89adeda51aea3bafc20d6fdcba0c7a559","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.52.tgz","fileCount":18,"unpackedSize":192984,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1064CRA9TVsSAnZWagAAYDwP/j/SFBFWvD5ZWrUGKaF0\nuvd9z2SlLFwWCxWJbRvADNcvywRvcsrm1tWOSkiHwVWujy12T1YydJXn4z/d\n5mIPxSYtaOz9LdXX9oz4skJR9HK8k8cfOsVvrr0enXHD9xTJ6Kfwh4xyUM7z\noUG9P2+b1bAwp0HG/RqXWWZUTWhs5uBCJAgZ/9mo5pLeL/Bxeh0jv7boaZDE\nssVSJSN5wDDUipp4PQUE78FpMT2X69PH2xqAFeXUw+x0mZbYyW6fEHKyWBIP\nXP7JvhkG7lILtSYFSxtAhb2+j9MtNrmDvN9oEyhYer3p8przxyQbvjvA6XlE\nJ9T8Ks9x0/BrBa3eS2xHQqELZkzbN5mY5lvH43H7wcb2pCucgXULhFgM5tqD\nA2lUre8zBPDcf3ZDs2XUaFdBnkkqJSn16aQew7EixC/NEgHvwPRtvo3sLBPI\nHer2m/dftHG4IzaX82/DyVNIOFcJrrImwraTlqt+rzvREa1hWLPE1iEYWnPL\nCyip7e65ZCcKACW4wIS1zdw0hD3q8/J2Hpr8tRgXJGhLmXlw7wuECtfXkX5v\ngp0s/oJJsXJxNFF5ESIhsMq3hKu1MnHk9NU8Emo1JQT1yfOREAWk6/EWcgnR\ntRCpzryk585eGBvo0JIMi2OlLVAyv2qUgiDt2h7lrGDWnugPrmkcJV3J5Qaw\n8mGS\r\n=v0fi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDO3hKAw5kNfSCjr4O0fJZPXWjl4PpfkcMR7po7R5Qe1AiAA7d98osSRPLQT16nF3y3mpnh7jk65P3ajPDP45Q0lGw=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.52_1607945912455_0.36081018376521246"},"_hasShrinkwrap":false},"1.3.5-alpha.55":{"version":"1.3.5-alpha.55","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"38fbca96a69a8ab153c6cbda853b97c179c8ed33","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.55","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-8Ui16TE/8VT9Hm1QtP6FbHmTUT10b/akBK2ZYaOTByTW9KRlDUVA1Hw/zJdNrQW33slBnFtX6LtKUhz0Kwgt8g==","shasum":"6d10524208ae077f4fc1c40741605c02fa46b6ea","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.55.tgz","fileCount":18,"unpackedSize":194789,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf11MSCRA9TVsSAnZWagAAIgMQAKKOcsjVvpoqvBtQcG3l\nWyFVOQhqsyoFZlB3bvWb+NOP7sImcVEg8zYye1DlBC2PIj7KCBXdomCt9T1v\nr86mmkOEyH9x7MgxKfzS7gPh07zUIgePWU5tm6l8AEf1OfKEzuie1RcLFmSg\nH/LPC3DSKKf5n48g+F+i54zjJW5vcLuOzBRIlFbMvDIftGepp2zU6bje+sw+\nM7i7mwBTyNZd5ibY2PTJu2OfzShuAXDMS3qSbxAeKzU2tm3suGnkaKaFLIZn\nsfh5jeRfUCgQOX09SSowMZbw35rSNO6fike0Yvx3/gXBSpE7Jp3B3AFSWUem\n/MzVxzco0BakE1HSExwbWch9lSnxn0k+V/GqHD3ggE+gaHx/kHsvPHJfTLfI\njY06D66LRfAgM6lV56xSbEyHXmaCIvkzlOy+XAEO9lxJ6hUadUFGTOAMKva3\nA4oGYVlYVX3NmDGWQgX8PiYpI8siT6pijIOR6o1qFa1ABR0Smz8/v2Vfgm3D\n5/6cNXQHvmTM+1yiIXwY6OM9kylLL2JRS9IDyT55wAGCQrHkdDsqikSu5OkK\nAR3iMNsD0JMq0t1DcwmckiRCal8UGBDi9E8eQtqM0L4jr+4YktLjhVok9/+i\nJUiDgwlNXZXdDH3CnAO8JskmC2gmRQWZOz5YTk2C3MYzBZ0DjiOopQvjiN6z\nJW0A\r\n=/wnj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGaM1uQGIuNWnvmFUiAPZqAMZZL41iM3I7cp0JEeRIe6AiAkVZj9Fw1renKA9rRvKR1cu6xfM1h0ajyC4nW+3vm8YA=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.55_1607947026144_0.17645525350356972"},"_hasShrinkwrap":false},"1.3.5-alpha.56":{"version":"1.3.5-alpha.56","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"d006ddab67df6bc1bd5971bf7c9bdd2704ccc8fb","readme":"# graph-state\n\n> Digraph-based state management\n\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\n\n## Install\n\n```bash\nyarn add graph-state\n```\n\n```bash\nnpm install graph-state\n```\n\n## Usage\n\n### What is a Graph State?\n\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\n\n### Creating a Graph Node\n\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\n    invokes the `get` function to recompute and produce the new state.\n    * `set(node, action)`: Dispatches a node.\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n    * `reset(node)`: Resets a given node.\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\n    * `set(node, action)`: Dispatches a node.\n    * `reset(node)`: Resets a given node.\n    * `mutate(newValue)`: Sets the new state for the graph node.\n    * `setSelf(action)`: Dispatches the self node.\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\n  * `newValue`: The new state for the graph node.\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\n\n```tsx\nimport { createGraphNode } from 'graph-state';\n\n// A basic node\nconst basicNode = createGraphNode({\n  get: 'Hello',\n});\n\n// A dependent node\nconst dependentNode = createGraphNode({\n  get: ({ get }) => {\n    const basic = get(basicNode);\n\n    return `${basic}, World!`;\n  },\n});\n\n// A self-updating node\nconst timer = createGraphNode({\n  get: ({ mutateSelf, subscription }) => {\n    let count = 0;\n    subscription(() => {\n      const interval = setInterval(() => {\n        count += 1;\n        mutateSelf(count);\n      }, 1000);\n      return () => {\n        clearInterval(interval);\n      };\n    });\n    return count;\n  },\n});\n\nconst temperatureF = createGraphNode({\n  get: 32,\n});\n\nconst temperatureC = createGraphNode({\n  get: ({ get }) => {\n    const fahrenheit = get(temperatureF);\n\n    return (fahrenheit - 32) * 5 / 9;\n  },\n  set: ({ set }, newValue) => {\n    set(temperatureF, (newValue * 9) / 5 + 32);\n  },\n});\n\n```\n\n#### Graph node rules\n\n##### Graph nodes are immutable.\n\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\n\n##### Graph nodes of the same key share the same instance.\n\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\n\n##### `set` and `reset` are asynchronous.\n\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\n\n### Graph Node Resources\n\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\n\n```tsx\n/**\n * This is an asynchronous graph node. Trying to\n * access this node using `useGraphNodeValue` just\n * returns a Promise instance. Writing hooks for\n * handling Promise state and side-effects is a\n * tedious task.\n */\nconst asyncUserNode = createGraphNode(\n  get: async ({ get }) => {\n    // Get current user id\n    const id = get(userIdNode);\n\n    // Fetch user data\n    const response = await fetch(`/users/${id}`);\n\n    return response.json();\n  },\n);\n\n/**\n * Let's transform asyncUserNode into\n * a valid React resource node!\n * \n * This allows us to receive Promise results,\n * react-graph-state already handles race condition\n * and state updates for us!\n */\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\n```\n\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\n\n### Resource-related constructors\n\n#### `fromResource`\n\nConverts a graph node resource into a promise-based graph node.\n\n```tsx\nconst rawUserDataNode = createGraphNode({\n  get: async ({ get }) => fromResource(userResourceNode),\n})\n```\n\n#### `waitForAll`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAll([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\n```\n\n#### `waitForAny`\n\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\n\n```tsx\nconst resourceA = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(1000);\n      return 'Message A';\n    },\n  }),\n);\nconst resourceB = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(2000);\n      return 'Message B';\n    },\n  }),\n);\nconst resourceC = createGraphNodeResource(\n  createGraphNode({\n    get: async () => {\n      await sleep(3000);\n      return 'Message C';\n    },\n  }),\n);\n\nconst values = waitForAny([\n  resourceA,\n  resourceB,\n  resourceC,\n]); // 'Message A'\n```\n\n#### `joinResources`\n\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\n\n### Factories\n\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\n\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\n- `get`: Function for generating graph node values.\n- `set`: Optional. Function for generating graph node side-effects.\n\n```tsx\nimport { createGraphNodeFactory } from 'graph-state';\n\n// Parameters for each factory field are shared.\nconst userDataFactory = createGraphNodeFactory({\n  // Generate key based on parameter\n  key: (id) => id,\n  // Get user by id\n  get: (id) => () => getUserById(id),\n})\n```\n\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\n\n```tsx\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\n```\n\n## License\n\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.3.5-alpha.56","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-MFAlbBYF/03tLMvuOcFxK4Efx++e4+0E6qi5jBBan3j+KYPtE6eN2Pv2f6FoVAU7yXy0pcx/EWiVSKZt3cbchQ==","shasum":"08bd62299663e669c77ee8d87e8e753b3c454eab","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.3.5-alpha.56.tgz","fileCount":18,"unpackedSize":196039,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf11OCCRA9TVsSAnZWagAAHbAP/iRL9Lwyvt23kTAldl95\nak/VUR9vlgeqmwrvZ9Nm6Q/t6ZVdAj401bWUxC5auxVP7i9H2vSjzQQ0WXNo\n/M2FVAtHaMbD0ZdjfPR8DjKHaZ2Y0gCsEv2J/4l3ND823AyFO68kylqaf2e2\nXgEew62Xi6oKwqKphOFGUAJl6Ydyi9Lg97vhG9A2epcoIbntzJTgtsN4Ux3a\nq+mjmSkDLKnwwGV5CUpoYXM0cJ8T6WfiHKFU3/kJ52tdjqzKYHluXbw32yHj\nZVBA6MFrJN4qGcsuRkMQn/QAdEtiBTwI2mT2nYCk+cc3/g0/jntenEy28vp9\n3tg24ZLiWhXeUQ67JEJN1QYkdNZS40PkX+JlVV1AUZiAgL4gjQs3CJBnXr47\n9xUnfrISGICaLoluhblxanFeTYw93Q/ZAVllpzVhjE2r/o60feufwGVd7FSz\nGUsXEnwCTdtv1xGQrDCvD+eBqPcpSgdxdeWFmZOdIbkA234harMqVTVRJd1b\n6IVVVeEe1JmlznxyuLc41bbojot4ksiVblBRhJWsmxUDdL2X43aG/qQgSj2X\nmU/LpIVRjY4J+XCbd9keMi2HJPvrRjRq9BYuu5c5jEwffMvBmHfnd4yiplGa\nDssyMVFatd+pykx6KSvujkS0P5XbVPp/rhUK2ozxwRpLDehO8EV7UaxYc0Y5\nk8qU\r\n=T4yN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID5uTx+e4cBdx7APB7OCmZtZ7tDrI/LQbV8Moy7gmTn8AiAmm2KwdXAVRh3vVxoJJleBCbnDmyBpkA1ZExjbUTd5dw=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.3.5-alpha.56_1607947137815_0.9419812778565966"},"_hasShrinkwrap":false},"1.4.1":{"version":"1.4.1","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"9838768fb6b7b08334145246fca111fee235cf16","_id":"graph-state@1.4.1","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-s9w/Fk1SNI0wiN8A0R67fApXU3ZUsG0v5tGFlAiAChR6xjkhZKzszxpbtG/YIt4SS48rpw4tBf9cYHRZDHOS9A==","shasum":"6fe706a4e48e257664ab71fe0aeba13fa6d68719","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.4.1.tgz","fileCount":18,"unpackedSize":196264,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf15QGCRA9TVsSAnZWagAAH+cQAJSyG2mAVrY+dOUEK0Qw\nWszd8AQidiilmzyLBr8CL6qL0Jpt0ZKNHmNDJ1LuXLvqAusdiumGuOAYsm8T\n9lChcBlw2vWDbYmNbdyU7iZ2DZJc8e/yyM5Xa/spDNGYFa/K6bq4x5RFJW2e\nCLslDhEM5hnBM5OzbLmkrCWuwYw0Et4VbQQMLFhOz10G1kvyKcjj7Zjh0Usk\nEuG2LfgiUgEzASvb+JH3diX8yUO4eBnP5JqmZ16irIaXbdLoE1MJZ2X+0wlW\nDVNPfxVlLHHYc/oGxk/Kj1wF1EpN9YzTSnvogrU+6HhhQLJaXySbCvRyAt+t\nElXHgHeMHxh9dEnM7oKxp1thPAqQQ1vpH/jzwNy+CVD+P8r7xGUrRodvL+Xh\nEzh2u/qeU4T0ow1LbOXixPxQl35Z2Ybmrmq3YlwMhVgMqJeNUv3e2dX4HLpC\npEYEg+y4xj85jg9JZoMOcX3O5Z7kbv/+XePbRmwfR/fJ9bGDBcd5UA4mKSxg\ngg9m/CHG+hYF84bwogDcKzWc0T/kixh/Il9sR5ZmmJBdxJC0ldzBfIdOHMO+\nUMPnwcsIPPTURTHpWzxbr0+csUrH4PHY6BNmCq2hXEcbx7XbWSQ2+200iyOr\nICzXkGzkKeZcLx6X+dpqQ5sPzWo5+D5B8NHKLGp4bjy1JnFranyNH7iSXZ1s\nQIJY\r\n=TfAx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE570fKdVp4EGf2DEydjcTpDiR44fCeRn96zUX6PZ1FLAiEA9SQLhZwUsIN0E4eeOsBo+iHW+q45zaW99aITjWO9ZHM="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.4.1_1607963653800_0.8684472238376455"},"_hasShrinkwrap":false},"1.4.2-alpha.7":{"version":"1.4.2-alpha.7","main":"dist/index.js","exports":{"import":"./dist/graph-state.esm.js","require":"./dist/index.js"},"types":"dist/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","module":"dist/graph-state.esm.js","devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.7","eslint":"^7.13.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.5.0","ts-jest":"^26.4.4","tslib":"^2.0.3","typescript":"^4.1.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"ef404112b718f0354f86adec4c8dde627cab3a18","readme":"# graph-state\r\n\r\n> Digraph-based state management\r\n\r\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\r\n\r\n## Install\r\n\r\n```bash\r\nyarn add graph-state\r\n```\r\n\r\n```bash\r\nnpm install graph-state\r\n```\r\n\r\n## Usage\r\n\r\n### What is a Graph State?\r\n\r\nA `Graph State` is a kind of a state management structure that aims to build a container states that behaves like a dependency graph. The structure are made up of `graph nodes`, which represent an atomic state. Each `graph node` may depend from another `graph node` instance. When a `graph node` state updates, all of its dependents react immediately from their dependency's new state, and in turn, updates their own state, which can go on until there are no dependents left.\r\n\r\n### Creating a Graph Node\r\n\r\nTo create a graph node, you must invoke the `createGraphNode` function. This function an object with 1 required field and 2 optional fields.\r\n* `get`: acts as a default value. If a function is supplied, the function is lazily evaluated as it enters the `GraphDomain` to provide the default value. This function may also be invoked again if the dependencies update. The function an object with ff. fields:\r\n  * `{ get, set, mutate, setSelf, mutateSelf, reset, subscription }`: An interface for controlling graph nodes.\r\n    * `get(dependencyNode)`: Registers the `dependencyNode` as a dependency and returns the dependency's current state. If the `dependencyNode` updates its state at some point, the created graph node reacts to the state and\r\n    invokes the `get` function to recompute and produce the new state.\r\n    * `set(node, action)`: Dispatches a node.\r\n    * `mutate(node, newValue)`: Sets the new state for the graph node.\r\n    * `setSelf(action)`: Dispatches the self node.\r\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\r\n    * `reset(node)`: Resets a given node.\r\n    * `subscription(callback)`: Manages subscriptions to external sources. Callback may return another callback which is called before the node recomputes, allowing for potential cleanup logic.\r\n* `set`: Optional. Registers a dispatch side-effect. When defined, prevents state mutation for the graph node and must rely on dependency recomputation. This function is invoked when the graph node is scheduled for state update. The function receives two parameters:\r\n  * `{ get, set, reset, setSelf, mutateSelf, mutate }`: An interface for controlling graph nodes.\r\n    * `get(node)`: Reads the node's value. Unlike `get`, the node is not treated as a dependency and therefore `set` won't be invoked when dependencies update.\r\n    * `set(node, action)`: Dispatches a node.\r\n    * `reset(node)`: Resets a given node.\r\n    * `mutate(newValue)`: Sets the new state for the graph node.\r\n    * `setSelf(action)`: Dispatches the self node.\r\n    * `mutateSelf(newValue)`: Sets the new state for the self node.\r\n  * `newValue`: The new state for the graph node.\r\n* `key`: Optional. Uses the provided key instead of a generated key. Provided key may be shared, although `get` and `set` functions may be different depending on the node instance passed. Use with caution.\r\n\r\n```tsx\r\nimport { createGraphNode } from 'graph-state';\r\n\r\n// A basic node\r\nconst basicNode = createGraphNode({\r\n  get: 'Hello',\r\n});\r\n\r\n// A dependent node\r\nconst dependentNode = createGraphNode({\r\n  get: ({ get }) => {\r\n    const basic = get(basicNode);\r\n\r\n    return `${basic}, World!`;\r\n  },\r\n});\r\n\r\n// A self-updating node\r\nconst timer = createGraphNode({\r\n  get: ({ mutateSelf, subscription }) => {\r\n    let count = 0;\r\n    subscription(() => {\r\n      const interval = setInterval(() => {\r\n        count += 1;\r\n        mutateSelf(count);\r\n      }, 1000);\r\n      return () => {\r\n        clearInterval(interval);\r\n      };\r\n    });\r\n    return count;\r\n  },\r\n});\r\n\r\nconst temperatureF = createGraphNode({\r\n  get: 32,\r\n});\r\n\r\nconst temperatureC = createGraphNode({\r\n  get: ({ get }) => {\r\n    const fahrenheit = get(temperatureF);\r\n\r\n    return (fahrenheit - 32) * 5 / 9;\r\n  },\r\n  set: ({ set }, newValue) => {\r\n    set(temperatureF, (newValue * 9) / 5 + 32);\r\n  },\r\n});\r\n\r\n```\r\n\r\n#### Graph node rules\r\n\r\n##### Graph nodes are immutable.\r\n\r\nOnce they are created, they can never be destroyed. Be mindful of your graph node logic.\r\n\r\n##### Graph nodes of the same key share the same instance.\r\n\r\nWhen creating graph nodes of the same key, the first one is returned. This is to prevent polluting the graph domain for unnecessary creation of node instances.\r\n\r\n##### `set` and `reset` are asynchronous.\r\n\r\n`set` and `reset`, although synchronous functions, have asynchronous effects and thus, if `get` is called, `get` will most likely return an old version of the value.\r\n\r\n### Graph Node Resources\r\n\r\nGraph nodes can have synchronous or asynchronous states, but having raw asynchronous states like in in React (aka Promises) can be a bit tedious to handle specially for race conditions. `createGraphNodeResource` attempts to leverage this problem by turning asynchronous states into reactive Promise results.\r\n\r\n```tsx\r\n/**\r\n * This is an asynchronous graph node. Trying to\r\n * access this node using `useGraphNodeValue` just\r\n * returns a Promise instance. Writing hooks for\r\n * handling Promise state and side-effects is a\r\n * tedious task.\r\n */\r\nconst asyncUserNode = createGraphNode(\r\n  get: async ({ get }) => {\r\n    // Get current user id\r\n    const id = get(userIdNode);\r\n\r\n    // Fetch user data\r\n    const response = await fetch(`/users/${id}`);\r\n\r\n    return response.json();\r\n  },\r\n);\r\n\r\n/**\r\n * Let's transform asyncUserNode into\r\n * a valid React resource node!\r\n * \r\n * This allows us to receive Promise results,\r\n * react-graph-state already handles race condition\r\n * and state updates for us!\r\n */\r\nconst userResourceNode = createGraphNodeResource(asyncUserNode);\r\n```\r\n\r\nAccessing `userResourceNode` using `useGraphNodeValue` returns an object which represents the Promise result.\r\n\r\n### Resource-related constructors\r\n\r\n#### `fromResource`\r\n\r\nConverts a graph node resource into a promise-based graph node.\r\n\r\n```tsx\r\nconst rawUserDataNode = createGraphNode({\r\n  get: async ({ get }) => fromResource(userResourceNode),\r\n})\r\n```\r\n\r\n#### `waitForAll`\r\n\r\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.all`. If one of the resources updates, `waitForAll` returns to pending state untill all Promise has resolved again.\r\n\r\n```tsx\r\nconst resourceA = createGraphNodeResource(\r\n  createGraphNode({\r\n    get: async () => {\r\n      await sleep(1000);\r\n      return 'Message A';\r\n    },\r\n  }),\r\n);\r\nconst resourceB = createGraphNodeResource(\r\n  createGraphNode({\r\n    get: async () => {\r\n      await sleep(2000);\r\n      return 'Message B';\r\n    },\r\n  }),\r\n);\r\nconst resourceC = createGraphNodeResource(\r\n  createGraphNode({\r\n    get: async () => {\r\n      await sleep(3000);\r\n      return 'Message C';\r\n    },\r\n  }),\r\n);\r\n\r\nconst values = waitForAll([\r\n  resourceA,\r\n  resourceB,\r\n  resourceC,\r\n]); // ['Message A', 'Message B', 'Message C'] after 3 seconds.\r\n```\r\n\r\n#### `waitForAny`\r\n\r\nWaits for an array of graph node resources to resolve. This is similar in behavior with `Promise.race`. If one of the resources updates, `waitForAny` returns to pending state untill any Promise has resolved again.\r\n\r\n```tsx\r\nconst resourceA = createGraphNodeResource(\r\n  createGraphNode({\r\n    get: async () => {\r\n      await sleep(1000);\r\n      return 'Message A';\r\n    },\r\n  }),\r\n);\r\nconst resourceB = createGraphNodeResource(\r\n  createGraphNode({\r\n    get: async () => {\r\n      await sleep(2000);\r\n      return 'Message B';\r\n    },\r\n  }),\r\n);\r\nconst resourceC = createGraphNodeResource(\r\n  createGraphNode({\r\n    get: async () => {\r\n      await sleep(3000);\r\n      return 'Message C';\r\n    },\r\n  }),\r\n);\r\n\r\nconst values = waitForAny([\r\n  resourceA,\r\n  resourceB,\r\n  resourceC,\r\n]); // 'Message A'\r\n```\r\n\r\n#### `joinResources`\r\n\r\nJoins an array of graph node resources into a single graph node that emits an array of resource results.\r\n\r\n### Factories\r\n\r\nGraph node factories allows you to dynamically generate graph nodes of similar logic based on parameters.\r\n\r\nFactories has similar option fields for basic graph node creation, but the difference is that these options are higher-order functions instead.\r\n- `key`: Optional. Function for generating graph node keys. If not provided, keys are generated from encoding the parameter array into valid JSON string.\r\n- `get`: Function for generating graph node values.\r\n- `set`: Optional. Function for generating graph node side-effects.\r\n\r\n```tsx\r\nimport { createGraphNodeFactory } from 'graph-state';\r\n\r\n// Parameters for each factory field are shared.\r\nconst userDataFactory = createGraphNodeFactory({\r\n  // Generate key based on parameter\r\n  key: (id) => id,\r\n  // Get user by id\r\n  get: (id) => () => getUserById(id),\r\n})\r\n```\r\n\r\nFactories with Promise-returning graph nodes can be wrapped with `createGraphNodeResourceFactory`, which automatically converts the generated Promises into Resources.\r\n\r\n```tsx\r\nconst userDataResourceFactory = createGraphNodeResourceFactory(userDataFactory);\r\n```\r\n\r\n## License\r\n\r\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)","readmeFilename":"README.md","_id":"graph-state@1.4.2-alpha.7","_nodeVersion":"15.2.1","_npmVersion":"lerna/3.22.1/node@v15.2.1+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-YqyuAxsEZtPYL5erQvVxfKdBcaJMMCSf1Eg8lgZwQSHTDE53dOtLUxWruGPDdCgsIPxhUHvhej3s9bguMrRQGA==","shasum":"9d23e56f97e5fb5973f6e5d36949ef8c0b00076c","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.4.2-alpha.7.tgz","fileCount":18,"unpackedSize":192101,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf3z1+CRA9TVsSAnZWagAAUEIP/2/rq+EiLFxZ2HtsfQsI\nw1LhCtErMdlEG9lOnSf+H+OLA5EPY2OlDej/tnq2Ray9GEFTAGPvYuezAxLy\npdtBAwiSlw+rpMpvpkqpXu/INPhFUCv/GeuufPhTBqNjWmojoHmWbCxtge0a\nfgDn2W+ztqwQHgPgkeo38bxu9eeQzXQw/ZjQbEwaQUWfZk0F7IZJsKbgT4FF\nyicwYcmMg9xTi10zfi9ie7b1Yoos0cT9erXPHc1QQqr3ChDxuiGO3/1Kjs1B\nlUNWi8dvDe0ojCMofppZ0zABSlmZaqhdh+I3mXNIKJr7SShBVlwcjBLdw5Y4\nTJlryelOWS4lBvTG8mBELniCoGjZT/xUiH7MBGy3JL87nKC/oXHPaU28Qg4T\nvXXuXd0DNlFiOHWYmXfAJb+PSCeIFLcfs5wK0gdnpZN8hkgRx3W/kEUfDU5I\nwFJ5PTdjjcOYxw6bX08wBPcgGwda+BVl7lMX8fDf4KzHuBK8RT9ki4BkWrkk\nX7cLL1a0dpX/9DqGw0KK5NiHls9opizgSP+exXMrV90EB6oCOt7VxtB+t1rZ\n3xrOpdZl1sy3tovVog5tdZvm2YpR/tGcmVKD7GDmImjvY9UH6DyRTGhV4GAO\nDymd1YhM8CwblCIwrG21ZybdgDnB3HJ+Gg1SpFJkd3l+rxX+5LL2a1b9A1ZP\nInqt\r\n=qLIO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEsf7kkopoOAiaCNbq/fDH6gn6vt7vwFCVDFMElqHud6AiEAtHcqG7O1MDZcXPOkzO1F11b+PKkXoQFiDoKeachz/b8="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.4.2-alpha.7_1608465790143_0.8649558091401579"},"_hasShrinkwrap":false},"1.5.0":{"version":"1.5.0","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"8cce82394a9383be900f26be519567ed1da5aee4","_id":"graph-state@1.5.0","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-QquqCPIpLq971Zv+gud1xzJkfjxu4jfSpp0aEUr2HbT3SGn8OQPTEkgl7qeTSKC0lpEbcesDNPx6BS/B3SZeKw==","shasum":"6804d71c50b1f873694053b265138ba9bd8f7f7e","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.5.0.tgz","fileCount":18,"unpackedSize":199251,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgVd73CRA9TVsSAnZWagAAWHMP/jbrVuB6hooKxBFLQjGs\n6O1UkJQBOJHaaF0OyIA/gIHYy5pX6WDNMBoUPZEolJVtIPvyxlh0zeOammqo\nNHbuvT1w9uqzmrM+4MYKDbFOQtyNfkm9inELJilCwlxSouMwIF1iJd6vX26J\niIpFxO+t/YUt3PMYyQ8akOKjv0jUT4TfhTAxe17ceScgFvkAo87sz4r8EW0t\ngB4g+DZCoSF+e87wxSttbzxUANKbQwfWyXF2Ewc/1GUaWFaJQLTyWBFR6GOH\n5OFgnJp1VWnOLNTlceKsZzzxKUe8ergiVevlI+AWTeUVbTT8wV8phVyu5Jyn\nBc6J+dvBLi0BrcvHu7AMPzyAi+IxGIzMFTBL50YTB9T20TqpeT+y6UzXgYtx\nEffZyl17lUC27Vvpwnvrq2HGQcSJcYn+poOzmr6gqxP6PipIklO5KT7B1dNK\n9j+t7vgReeYsD/N7E8WTUUwUWSVbq7NREETd9KcBgHj+l1FZUykyUzCRBpDy\n5vcPpAuTo9ihqw01azcsM/UzlzP11bxBYZ83E6hbTALGA7BqevdNqAzE3ZFd\nad0DXM1rR1tN+GAQgmvZupiZMp/ChpNdq9ZK9nHn3SvrokWVehuX0gnS6kP/\nnAjMUqB5WyCLH80BddfWZxj2O5uE7zG4q/OuTvhP19vkTKfzrtf1OnvW7PPK\npCgu\r\n=BPPI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCX/zCYNR0wXnP6cu9OeysUdUia/7OSgjyqJVOVQnA/5AIhAPPXKbna6aM+1q8tc0lGBQ4zCpvZF8CrYTc0+092gtE1"}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.5.0_1616240375431_0.8459465174768204"},"_hasShrinkwrap":false},"1.5.3-alpha.3":{"version":"1.5.3-alpha.3","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"ad77419298df1bea1d76c9ce9824de5e3a2d259b","readme":"# graph-state\r\n\r\n> Digraph-based state management\r\n\r\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\r\n\r\n## Install\r\n\r\n```bash\r\nyarn add graph-state\r\n```\r\n\r\n```bash\r\nnpm install graph-state\r\n```\r\n\r\n## Usage\r\n\r\n## Features\r\n\r\n### Think atomically\r\n\r\n`graph-state` motivates the use of granular stores, or we call them \"nodes\", that is, nodes that only store a single state.\r\n\r\n```tsx\r\nimport { createGraphNode } from 'graph-state';\r\n\r\n// A simple graph node usage\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n```\r\n\r\nNodes can have either a constant value as a default state, or provide a function that lazily computes the default state.\r\n\r\n```tsx\r\nconst randomState = createGraphNode({\r\n  get: () => Math.random(),\r\n});\r\n```\r\n\r\n### Dependency graph states\r\n\r\n`graph-state` leverages the cumbersome process of connecting stores to communicate one another by seamlessly connecting them. A node's `get` propery receives an interface which can be used to read other node's state. Once a node reads another node's value, the read node becomes a \"dependency\": whenever the dependency node updates value, the dependent node recomputes it's state.\r\n\r\n```tsx\r\nconst greeting = createGraphNode({\r\n  get: 'Hello',\r\n});\r\n\r\nconst person = createGraphNode({\r\n  get: 'John Doe',\r\n});\r\n\r\nconst message = createGraphNode({\r\n  get: ({ get }) => {\r\n    // Read the greeting and person nodes\r\n    const greetingValue = get(greeting);\r\n    const personValue = get(person);\r\n\r\n    // When greeting or person updates their state\r\n    // message re-runs its get function to create a new state.\r\n\r\n    // Return the derived state\r\n    return `${greetingValue}, ${personValue}.`;\r\n  },\r\n});\r\n```\r\n\r\nIt doesn't matter when `get` is called or how it is used:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  get: ({ get } => {\r\n    const cond = get(A);\r\n\r\n    if (cond) {\r\n      return get(B); // If A is truthy, B becomes a dependency.\r\n    }\r\n    return get(C); // Otherwise, C becomes the dependency instead of B.\r\n  }),\r\n});\r\n```\r\n\r\nWhenever `get` is called, the dependency list is rebuilt, so the timing doesn't matter for a node to become a dependency.\r\n\r\n### Lazy Evaluation\r\n\r\nNodes, even though can be created on any level of context, does not evaluate until needed/used.\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  // This function does not run until\r\n  // example is read.\r\n  get: () => runExpensiveComputation(),\r\n});\r\n```\r\n\r\n### Keys\r\n\r\nNodes may accept a `key` field:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  key: 'example',\r\n  get: 'Hello',\r\n});\r\n```\r\n\r\nIf another node of the same key is attempted to be created, the first instance is always reused.\r\n\r\nKeys you define are dev-only. Production environment will produce a unique id in place of the keys you provided.\r\n\r\n### Subscriptions\r\n\r\n`graph-state` allows managing subscriptions for side-effects. This is useful for subscribing to events (e.g. `addEventListener`), timers (`setTimeout`), etc.\r\n\r\n```tsx\r\nconst timer = createGraphNode({\r\n  get: ({ subscription }) => {\r\n    subscription(() => {\r\n      const timeout = setTimeout(() => {\r\n        intervalLogic();\r\n      }, 1000);\r\n      return () => {\r\n        clearTimeout(timeout);\r\n      };\r\n    });\r\n  },\r\n});\r\n```\r\n\r\nSimilar to `get`, it doesn't matter when `subscription` is called. Every recomputation runs the cleanup function returned by `subscription`, and re-runs the callback.\r\n\r\n### Mutations\r\n\r\nThere are two kinds of state update in `graph-state`: `mutate` and `set`. `mutate` directly changes a node's state. `set`'s default behavior is similar to `mutate`, but if the node has a custom `set` function, the custom function is called instead of `mutate`. This is useful for building actions.\r\n\r\nBoth `get` and `set` received interfaces has functions that allow mutation.\r\n\r\n```tsx\r\n// A node that mutates itself.\r\nconst secondClock = createGraphNode({\r\n  get: ({ mutateSelf, subscription }) => {\r\n    subscription(() => {\r\n      // an internal variable that tracks a state.\r\n      let count = 0;\r\n\r\n      // Subscribe to an interval timer\r\n      const timeout = setInterval(() => {\r\n        // Update our counter\r\n        count += 1;\r\n\r\n        // Perform self-mutation\r\n        mutateSelf(count);\r\n      }, 1000);\r\n\r\n      return () => {\r\n        clearInterval(timeout);\r\n      };\r\n    });\r\n\r\n    return 0;\r\n  },\r\n});\r\n```\r\n\r\n### Actions\r\n\r\nInspired by Redux and Flux architecture, nodes can have an action-receiving function called `set`, which overrides the state mutation of the node. The `set` function accepts the same interface as `get` (excluding `subscription`) and the action being received. In contrast with `get`, `set` does not react nor connect to read nodes.\r\n\r\nAn example of a graph node emulating a Redux store.\r\n\r\n```tsx\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n\r\nconst reduce = (state, action) => {\r\n  switch (action.type) {\r\n    case 'INCREMENT':\r\n      return state + 1;\r\n    case 'DECREMENT':\r\n      return state - 1;\r\n    default:\r\n      return state;\r\n  }\r\n};\r\n\r\nconst reducer = createGraphNode({\r\n  get: ({ get }) => get(counter),\r\n\r\n  set: ({ get, set }, action) => {\r\n    set(counter, reduce(get(counter), action));\r\n  },\r\n});\r\n```\r\n\r\n### Memoization\r\n\r\nNodes have their values memoized. Once a node attempts to update its state with an equivalent value, dependencies don't get notified with the new state, thus bailing out of recomputation. `createGraphNode` accepts another optional field named `shouldUpdate` which is a function that receives the current state and the next state. By default, the states are compared with `Object.is`.\r\n\r\n### Concurrency\r\n\r\nNodes with asynchronous `get` or `set` may produce unwanted side-effects whenever both methods run immediately after one another. To fix this, nodes, internally, have built-in race conditions which allows further side-effects from occuring by preventing `set`, `mutate`, `setSelf`, `mutateSelf` and `subscription` from further evaluation.\r\n\r\n```tsx\r\nconst itemsList = createGraphNode({\r\n  get: async () => {\r\n    const data = await db.query();\r\n    return data;\r\n  },\r\n});\r\n\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    return applyFilter(currentList);\r\n  },\r\n}); \r\n```\r\n\r\nNodes also accept a `resolve` method from interface which wraps a given Promise such that it will only resolve if the node has not yet recomputed.\r\n\r\n```tsx\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get, resolve }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    // Prevent from resolving if recomputed\r\n    return resolve(applyFilter(currentList));\r\n  },\r\n}); \r\n```\r\n\r\nNodes that return a Promise may also be converted into an ADT node which emits the stateful representation of the Promise result by using `createGraphNodeResource`. The resource node emits an object with the following fields:\r\n\r\n- `status`: The status of the Promise result. Begins with `\"pending\"`, and changes to either `\"success\"` or `\"failure\"`.\r\n- `data`: Value being represented by `status`.\r\n  - if `status === \"success\"`, `data` is the resolved value.\r\n  - if `status === \"failure\"`, `data` is the rejected value.\r\n  - if `status === \"pending\"`, `data` is the resolving Promise instance.\r\n\r\n```tsx\r\nconst listResource = createGraphNodeResource(itemsList);\r\n\r\nconst example = createGraphNode({\r\n  get: ({ get }) => {\r\n    const { status, data } = get(listResource);\r\n\r\n    // ...\r\n  },\r\n});\r\n```\r\n\r\nA valid resource node can be reverted back to a promise using `fromPromise`.\r\n\r\nMultiple resources can be concurrently handled using `waitForAll` or `waitForAny`, which correspondingly behaves similarly to `Promise.all` and `Promise.race`.\r\n\r\n```tsx\r\nconst [name, age, email] = get(waitForAll([\r\n  nameResource,\r\n  ageResource,\r\n  emailResource,\r\n]));\r\n```\r\n\r\n### Factory\r\n\r\nFor producing multiple nodes with the same core logic but varying values, we can use `createGraphNodeFactory`:\r\n\r\n```tsx\r\nconst nameFactory = createGraphNodeFactory({\r\n  // Similar to individual nodes except dynamic\r\n  key: (id) => `/profile/name/${id}`,\r\n  \r\n  get: (id) => () => readProfileName(id),\r\n});\r\n\r\n// ...\r\nconst name = get(nameFactory(id));\r\n```\r\n\r\n`createGraphNodeFactory` produces a function that passes the arguments provided to `key`, `get` and `set`.\r\n\r\n```tsx\r\nconst updateName = createGraphNodeFactory({\r\n  key: (id) => `/profile/name/${id}/update`,\r\n\r\n  set: (id, defaultName) => ({ set }, name) => {\r\n    set(nameFactory(id), name ?? defaultName);\r\n  },\r\n});\r\n\r\n//...\r\nset(updateName(id, 'John Doe'), newName);\r\n```\r\n\r\nIf a factory returns a Promise, this factory can be wrapped with `createGraphNodeResourceFactory` to produce resource nodes.\r\n\r\n## License\r\n\r\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)\r\n","readmeFilename":"README.md","_id":"graph-state@1.5.3-alpha.3","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-JB+IZBrd86rKGzR8yYvGV7wwJ/JUmi8/ziY1Bf9x4xuYFrUT7mD1zg1QqtNGgD63TgFf1A/DwpgMKgtaWc5WJg==","shasum":"987fd1e1471b7f6222c92fdf7a1a382e681ed43e","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.5.3-alpha.3.tgz","fileCount":18,"unpackedSize":200421,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWao/CRA9TVsSAnZWagAA8fgQAIkDbqh5eMCEaj4t+YHl\n6zzZ8EJBV9k2ijlWrgxB4CgrzizQFkRGgFsqJ67ups7EclaZcygTDzRxsY8i\nNncxlfRpBFpU17r3TgZVAe7M7Siq1RLIDd3fIdIf5RLb2uXx+MUtbUw0bvSB\nz3HuJ7NaiXqRdauq5Ng/PqcI8Yx7HO0UBpiT1wR1/HD2tok8jx6vp55P4SVR\npisXy2p2nftJJsrczppK8PDMxaZzTIDzmA01adhzMd1wHM4mVRryLcPB4bSi\nMTY8JrkClAMP2XlR9i3Sz+QqQnpBBfLBmJWD75JLWa8kog/XZ1gyGWJXKLgZ\nONFPtLpkwiN6vTyBYQrxr6eYbhmaOI/PbPCj3yMIHdqVm8pzVkQY5BmZKQZw\nZckrvnWfcwkvXkyBbbArz7R/6b1LXLBmD+PFdWe4IZFUeQAStxTcMf+8qK1r\nbY9VKUfpW0M1eK5cV9DqZ2GDji5B9CS86lBlUQp7+nmphDTmB7Slrn69TZym\nN2VT5JkBmgSH823vn5bissaUtNHB8DkjMMS7sjbK76SlAS5i9eLUADT0/Pi7\nBNDYZ00wTPCrMQDQ0s0tAvMIcHT0bt1hg/uQT+Abr//0+uZsnZWwYnA0PuPr\nOt3FXHzVApLpTFD9tfh2qBflrmR5CBY1jBzDtGJph0HK8bnFZZihItojJsQC\ndSvv\r\n=quZx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDAH1SJWGfWZV4R3D7Xm+lqRJ43TDCddQuph0tUDbsT/gIgGIjYv+wDpigJdyvL6IJsAbEcWpa1YHoqf5PN5fBldxg="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.5.3-alpha.3_1616489023015_0.09891295154045898"},"_hasShrinkwrap":false},"1.5.3-alpha.4":{"version":"1.5.3-alpha.4","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"cfe37ca1aaa5e17d95dd032b6f5e7bcd8b49adcc","readme":"# graph-state\r\n\r\n> Digraph-based state management\r\n\r\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\r\n\r\n## Install\r\n\r\n```bash\r\nyarn add graph-state\r\n```\r\n\r\n```bash\r\nnpm install graph-state\r\n```\r\n\r\n## Usage\r\n\r\n## Features\r\n\r\n### Think atomically\r\n\r\n`graph-state` motivates the use of granular stores, or we call them \"nodes\", that is, nodes that only store a single state.\r\n\r\n```tsx\r\nimport { createGraphNode } from 'graph-state';\r\n\r\n// A simple graph node usage\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n```\r\n\r\nNodes can have either a constant value as a default state, or provide a function that lazily computes the default state.\r\n\r\n```tsx\r\nconst randomState = createGraphNode({\r\n  get: () => Math.random(),\r\n});\r\n```\r\n\r\n### Dependency graph states\r\n\r\n`graph-state` leverages the cumbersome process of connecting stores to communicate one another by seamlessly connecting them. A node's `get` propery receives an interface which can be used to read other node's state. Once a node reads another node's value, the read node becomes a \"dependency\": whenever the dependency node updates value, the dependent node recomputes it's state.\r\n\r\n```tsx\r\nconst greeting = createGraphNode({\r\n  get: 'Hello',\r\n});\r\n\r\nconst person = createGraphNode({\r\n  get: 'John Doe',\r\n});\r\n\r\nconst message = createGraphNode({\r\n  get: ({ get }) => {\r\n    // Read the greeting and person nodes\r\n    const greetingValue = get(greeting);\r\n    const personValue = get(person);\r\n\r\n    // When greeting or person updates their state\r\n    // message re-runs its get function to create a new state.\r\n\r\n    // Return the derived state\r\n    return `${greetingValue}, ${personValue}.`;\r\n  },\r\n});\r\n```\r\n\r\nIt doesn't matter when `get` is called or how it is used:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  get: ({ get } => {\r\n    const cond = get(A);\r\n\r\n    if (cond) {\r\n      return get(B); // If A is truthy, B becomes a dependency.\r\n    }\r\n    return get(C); // Otherwise, C becomes the dependency instead of B.\r\n  }),\r\n});\r\n```\r\n\r\nWhenever `get` is called, the dependency list is rebuilt, so the timing doesn't matter for a node to become a dependency.\r\n\r\n### Lazy Evaluation\r\n\r\nNodes, even though can be created on any level of context, does not evaluate until needed/used.\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  // This function does not run until\r\n  // example is read.\r\n  get: () => runExpensiveComputation(),\r\n});\r\n```\r\n\r\n### Keys\r\n\r\nNodes may accept a `key` field:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  key: 'example',\r\n  get: 'Hello',\r\n});\r\n```\r\n\r\nIf another node of the same key is attempted to be created, the first instance is always reused.\r\n\r\nKeys you define are dev-only. Production environment will produce a unique id in place of the keys you provided.\r\n\r\n### Subscriptions\r\n\r\n`graph-state` allows managing subscriptions for side-effects. This is useful for subscribing to events (e.g. `addEventListener`), timers (`setTimeout`), etc.\r\n\r\n```tsx\r\nconst timer = createGraphNode({\r\n  get: ({ subscription }) => {\r\n    subscription(() => {\r\n      const timeout = setTimeout(() => {\r\n        intervalLogic();\r\n      }, 1000);\r\n      return () => {\r\n        clearTimeout(timeout);\r\n      };\r\n    });\r\n  },\r\n});\r\n```\r\n\r\nSimilar to `get`, it doesn't matter when `subscription` is called. Every recomputation runs the cleanup function returned by `subscription`, and re-runs the callback.\r\n\r\n### Mutations\r\n\r\nThere are two kinds of state update in `graph-state`: `mutate` and `set`. `mutate` directly changes a node's state. `set`'s default behavior is similar to `mutate`, but if the node has a custom `set` function, the custom function is called instead of `mutate`. This is useful for building actions.\r\n\r\nBoth `get` and `set` received interfaces has functions that allow mutation.\r\n\r\n```tsx\r\n// A node that mutates itself.\r\nconst secondClock = createGraphNode({\r\n  get: ({ mutateSelf, subscription }) => {\r\n    subscription(() => {\r\n      // an internal variable that tracks a state.\r\n      let count = 0;\r\n\r\n      // Subscribe to an interval timer\r\n      const timeout = setInterval(() => {\r\n        // Update our counter\r\n        count += 1;\r\n\r\n        // Perform self-mutation\r\n        mutateSelf(count);\r\n      }, 1000);\r\n\r\n      return () => {\r\n        clearInterval(timeout);\r\n      };\r\n    });\r\n\r\n    return 0;\r\n  },\r\n});\r\n```\r\n\r\n### Actions\r\n\r\nInspired by Redux and Flux architecture, nodes can have an action-receiving function called `set`, which overrides the state mutation of the node. The `set` function accepts the same interface as `get` (excluding `subscription`) and the action being received. In contrast with `get`, `set` does not react nor connect to read nodes.\r\n\r\nAn example of a graph node emulating a Redux store.\r\n\r\n```tsx\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n\r\nconst reduce = (state, action) => {\r\n  switch (action.type) {\r\n    case 'INCREMENT':\r\n      return state + 1;\r\n    case 'DECREMENT':\r\n      return state - 1;\r\n    default:\r\n      return state;\r\n  }\r\n};\r\n\r\nconst reducer = createGraphNode({\r\n  get: ({ get }) => get(counter),\r\n\r\n  set: ({ get, set }, action) => {\r\n    set(counter, reduce(get(counter), action));\r\n  },\r\n});\r\n```\r\n\r\n### Memoization\r\n\r\nNodes have their values memoized. Once a node attempts to update its state with an equivalent value, dependencies don't get notified with the new state, thus bailing out of recomputation. `createGraphNode` accepts another optional field named `shouldUpdate` which is a function that receives the current state and the next state. By default, the states are compared with `Object.is`.\r\n\r\n### Concurrency\r\n\r\nNodes with asynchronous `get` or `set` may produce unwanted side-effects whenever both methods run immediately after one another. To fix this, nodes, internally, have built-in race conditions which allows further side-effects from occuring by preventing `set`, `mutate`, `setSelf`, `mutateSelf` and `subscription` from further evaluation.\r\n\r\n```tsx\r\nconst itemsList = createGraphNode({\r\n  get: async () => {\r\n    const data = await db.query();\r\n    return data;\r\n  },\r\n});\r\n\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    return applyFilter(currentList);\r\n  },\r\n}); \r\n```\r\n\r\nNodes also accept a `resolve` method from interface which wraps a given Promise such that it will only resolve if the node has not yet recomputed.\r\n\r\n```tsx\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get, resolve }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    // Prevent from resolving if recomputed\r\n    return resolve(applyFilter(currentList));\r\n  },\r\n}); \r\n```\r\n\r\nNodes that return a Promise may also be converted into an ADT node which emits the stateful representation of the Promise result by using `createGraphNodeResource`. The resource node emits an object with the following fields:\r\n\r\n- `status`: The status of the Promise result. Begins with `\"pending\"`, and changes to either `\"success\"` or `\"failure\"`.\r\n- `data`: Value being represented by `status`.\r\n  - if `status === \"success\"`, `data` is the resolved value.\r\n  - if `status === \"failure\"`, `data` is the rejected value.\r\n  - if `status === \"pending\"`, `data` is the resolving Promise instance.\r\n\r\n```tsx\r\nconst listResource = createGraphNodeResource(itemsList);\r\n\r\nconst example = createGraphNode({\r\n  get: ({ get }) => {\r\n    const { status, data } = get(listResource);\r\n\r\n    // ...\r\n  },\r\n});\r\n```\r\n\r\nA valid resource node can be reverted back to a promise using `fromPromise`.\r\n\r\nMultiple resources can be concurrently handled using `waitForAll` or `waitForAny`, which correspondingly behaves similarly to `Promise.all` and `Promise.race`.\r\n\r\n```tsx\r\nconst [name, age, email] = get(waitForAll([\r\n  nameResource,\r\n  ageResource,\r\n  emailResource,\r\n]));\r\n```\r\n\r\n### Factory\r\n\r\nFor producing multiple nodes with the same core logic but varying values, we can use `createGraphNodeFactory`:\r\n\r\n```tsx\r\nconst nameFactory = createGraphNodeFactory({\r\n  // Similar to individual nodes except dynamic\r\n  key: (id) => `/profile/name/${id}`,\r\n  \r\n  get: (id) => () => readProfileName(id),\r\n});\r\n\r\n// ...\r\nconst name = get(nameFactory(id));\r\n```\r\n\r\n`createGraphNodeFactory` produces a function that passes the arguments provided to `key`, `get` and `set`.\r\n\r\n```tsx\r\nconst updateName = createGraphNodeFactory({\r\n  key: (id) => `/profile/name/${id}/update`,\r\n\r\n  set: (id, defaultName) => ({ set }, name) => {\r\n    set(nameFactory(id), name ?? defaultName);\r\n  },\r\n});\r\n\r\n//...\r\nset(updateName(id, 'John Doe'), newName);\r\n```\r\n\r\nIf a factory returns a Promise, this factory can be wrapped with `createGraphNodeResourceFactory` to produce resource nodes.\r\n\r\n## License\r\n\r\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)\r\n","readmeFilename":"README.md","_id":"graph-state@1.5.3-alpha.4","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-9KDP/xlsMQDQPTlEtFaK5pKu4fXSYf5yqaI090z1PkWGy8MeFzxE0pfVbfKnyFSiFKNSH88G7S9QXIl45Opbgg==","shasum":"a9c31c1d516277807436c9f5b0e368fc00235428","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.5.3-alpha.4.tgz","fileCount":18,"unpackedSize":201147,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWa8YCRA9TVsSAnZWagAAGaUP/iUXSzY74SQTjZJrJGEd\nElIXkptGvuHnWiBJegggE9vyfwHMmGPtIuuCoceKpwr+xEvxzO7BIUvPzzlB\n3PGDrTQRQFcRdU4ITQJWOZcrLa0SLjUjuKi+Zmdp01GBVst9ZxRKvCpZtKoR\nYP/vq0S3bsM7HwPLmWJHfvYOs1AHQ5esz+NevwHloR8enAEFFeeeu3mltWCo\n787H35XXi0ea2dJN1zJ82pEVEzYnDkh3T8HXEsQoTekKeyJosJk53AB0qNer\nF+lNFr/WQS+2oWu4pUWH9uo7Tdl8xrWCS3zYpdNkLJxo1vv8hIW32DP0SwQs\npS0cEgsGAIQH6Tn76ge+ErkLUUpIWM0xpRaUOefIE1mFA2/KdxqQnKQxjV2O\n2/XoLxUMfekegW/TUCVQA+WiomWiRMEO4dgu/6trvx7t7KamrsrC4q1bh1wl\ndTrpM3q9ZDW/zADBf8zy37KCvZLWhkQFMwElaI1DgBKEycW9owJmRgz+YrYD\nxtR9dd6ucSmj9SKWmMc85DOOM/aKxK7ya/wrXp5bY0M0ypU4y7QJ/c/bLkmo\n9xHWW0JFiiNdLixPxYVq+o/RSDWE5r/fevciABk7/d9LMvB6hYimnobEX4Zn\n7l4p497EE6AVutGtcsdMWFKbmTmNkrIodZDqL59LuGw0fzWg5tTOOuvZm+NB\n0yAk\r\n=eY+A\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFiodbkPucgDGjiG1LhHRlbo7dTcZCJYSGYjpoeHogCVAiA9c/g8krdke0tsv/W+vFJOsH2IotQvNcqIskOakbe8aA=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.5.3-alpha.4_1616490264341_0.18850584605343945"},"_hasShrinkwrap":false},"1.6.0":{"version":"1.6.0","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"70bf200cae88ff745c7ebaaace96cc9fbbd922e6","_id":"graph-state@1.6.0","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-ra2waW3KV1ihrUu6ayB2Fvt+R1vKn7OK74/xx2cfKvGeDMd8sliPw2VYS9DCfpud2nhDf+5NurxNDY/2nDaqyg==","shasum":"85d13a8c1dde951fa52b8ff36a4c7578888f9200","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.6.0.tgz","fileCount":18,"unpackedSize":198673,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaIfNCRA9TVsSAnZWagAAxr8P/iWiWvpFtgEGSRd+EKAa\nov9H+gmNSLrWy9qLWD7+LTOY2hOorrS8NmnG0CUh35HhTwE1Kb8wOjgKjCt8\n3lVlE4w0iBDeF4cU//HNhWN4IJfMMBda2zDZyJE/1U/LZqkapggKmM0El3lO\nSihsyOVyW+RLULRZwjgLpm90sNX8LKkSQAzc1LJX7VSdpU9CaFdeWy83e/M9\n9DflaCpgzTTlEUIycTsTk1QlnJNUcO3kMBPuTv7TnDU4VQ0bRhiNNYPqVKVY\nEXtqqFtTD/BOaZDRiE+azawcBzSC5bLZtQzQXdAuJqUqbpari/X6zUHUf/ji\n61yEhYXvkhHRZ8Ks3aXWDBBoiEuEM9mJOu7B1C4C/8pleo+PrGstzNxPGWT4\nOudwpT4noE3X44FCVN0PSrX60IICpw6lXkdw9YXKOCHFFNnz24cu7+Muhm/Y\nQjA/URk9qV6bUm4SVz77CNj+iAYgI7nF8I6YAGsOaVDQ2wu71fHRlJmBTnW5\nhffGYjoaGq2LOThnk+RDVG4XjnEjX3gFZURNg4sn1U1O/bbqd3G+kZVOlNXa\n8j/wdkZpPg5bulz1MUVn344jed1X19KqfVxm74PHVSbPUsWvBlFG2ZlpIlOH\nwxfzMzgCJPXa7/28sYu7nr8Nhw1Up1fhGrrN6Xv9eVfb3K6CE/n8fWuiNGS2\nmuEz\r\n=Ht+r\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDywgpkHGWXbtuSXR8kWbcCSM0ODzicFzbwToa765dW2AIgJ2Wgf0O91pPQM0vrN3g0LKlQxaMc1UsLJUExe2bUg1E="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.6.0_1617463245157_0.39722046667983046"},"_hasShrinkwrap":false},"1.6.1":{"version":"1.6.1","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"ed30ee63d826dd53ecbaf27dd5ee97c6c2d37f6b","_id":"graph-state@1.6.1","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-lELiK8GOkx0SoSPVKY+PIgnqp4aCYryyWwZmox1ePM8a2I4yUIem3Q7SAJIZH0ILGAzftAF6IqKm1EJX5+Uw0g==","shasum":"90b352f588d17839e93539001515c0947105995a","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.6.1.tgz","fileCount":18,"unpackedSize":198735,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaItfCRA9TVsSAnZWagAAa2YP/2VNNosXc30r4Zyb73rs\nivMG1MghHban52QLKSJFRECc+P0ZH9gpbdfSniUjestq/V2pQTVFs6bsQVeb\n4/pHQQLgBvyPLoCWRwdhnifCip74RdNe0EKzKblYZDwV8NcEEWpzLbBldOW1\nIm4JBWqMulefjQggAe8kLLw8Ad9Fu5yMdUr/7hZU9hldttblA0xY4wDdZ+YQ\ncMzmspJp9aOWuRpIALxSS6JoImNad4+hS7QhoJ7H2Vfa3tg3RA+8+tOB/NND\ny3NH0nRwTfBiBdtz9r5PJTJnckT40JtUvy8XtV1xqFTUu1E0tAtfyhVHjptY\nNdWzmFphMuq+Y/VbD0QKZSxcoTqa99e9FkalJ2dE4QAhp51FmqMic9Z26sem\nttPHiatPr/KestOxtlkPAfiQc++RG5ULT6hd6mfzQeMnSbSy7zKuwUO1oanA\n6LbV94tHzx5OVN88TF4+xBzD+GUIZWaMgCTAWTBpDxgglRJZnER1YJcqIgiP\n5SabZ0TATBUyuOtHT8ddk4XQLz7U/4gbpg6LCaGJDzBnnMA+MCiRQxzKyE3b\n9FVFJsoR4diLlWIWwC2MRY0wggQO8zMto06NpwN5dR9tH4NvA3kK/SifybKf\nWvoV/mx+sap/AbiU6Vpx+XcSpcvwN5T5QBdpwR1cxlJIG3cUkA1ThxjO8hqX\n2txT\r\n=mJ+d\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFlYLNHbzJMQmB4waE5qieSH0ZbIK97XEnsrFaL1oTigAiBnGuYPpBUebKNZyYHPMpw6RHArwMnaa8flXghhIJyEjw=="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.6.1_1617464158943_0.5823331269660939"},"_hasShrinkwrap":false},"1.6.2-alpha.5":{"version":"1.6.2-alpha.5","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"9fef0454fa006fda4f7ed623fe42831e8f44c4da","readme":"# graph-state\r\n\r\n> Digraph-based state management\r\n\r\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\r\n\r\n## Install\r\n\r\n```bash\r\nyarn add graph-state\r\n```\r\n\r\n```bash\r\nnpm install graph-state\r\n```\r\n\r\n## Usage\r\n\r\n## Features\r\n\r\n### Think atomically\r\n\r\n`graph-state` motivates the use of granular stores, or we call them \"nodes\", that is, nodes that only store a single state.\r\n\r\n```tsx\r\nimport { createGraphNode } from 'graph-state';\r\n\r\n// A simple graph node usage\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n```\r\n\r\nNodes can have either a constant value as a default state, or provide a function that lazily computes the default state.\r\n\r\n```tsx\r\nconst randomState = createGraphNode({\r\n  get: () => Math.random(),\r\n});\r\n```\r\n\r\n### Dependency graph states\r\n\r\n`graph-state` leverages the cumbersome process of connecting stores to communicate one another by seamlessly connecting them. A node's `get` propery receives an interface which can be used to read other node's state. Once a node reads another node's value, the read node becomes a \"dependency\": whenever the dependency node updates value, the dependent node recomputes it's state.\r\n\r\n```tsx\r\nconst greeting = createGraphNode({\r\n  get: 'Hello',\r\n});\r\n\r\nconst person = createGraphNode({\r\n  get: 'John Doe',\r\n});\r\n\r\nconst message = createGraphNode({\r\n  get: ({ get }) => {\r\n    // Read the greeting and person nodes\r\n    const greetingValue = get(greeting);\r\n    const personValue = get(person);\r\n\r\n    // When greeting or person updates their state\r\n    // message re-runs its get function to create a new state.\r\n\r\n    // Return the derived state\r\n    return `${greetingValue}, ${personValue}.`;\r\n  },\r\n});\r\n```\r\n\r\nIt doesn't matter when `get` is called or how it is used:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  get: ({ get } => {\r\n    const cond = get(A);\r\n\r\n    if (cond) {\r\n      return get(B); // If A is truthy, B becomes a dependency.\r\n    }\r\n    return get(C); // Otherwise, C becomes the dependency instead of B.\r\n  }),\r\n});\r\n```\r\n\r\nWhenever `get` is called, the dependency list is rebuilt, so the timing doesn't matter for a node to become a dependency.\r\n\r\n### Lazy Evaluation\r\n\r\nNodes, even though can be created on any level of context, does not evaluate until needed/used.\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  // This function does not run until\r\n  // example is read.\r\n  get: () => runExpensiveComputation(),\r\n});\r\n```\r\n\r\n### Keys\r\n\r\nNodes may accept a `key` field:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  key: 'example',\r\n  get: 'Hello',\r\n});\r\n```\r\n\r\nIf another node of the same key is attempted to be created, the first instance is always reused.\r\n\r\nKeys you define are dev-only. Production environment will produce a unique id in place of the keys you provided.\r\n\r\n### Subscriptions\r\n\r\n`graph-state` allows managing subscriptions for side-effects. This is useful for subscribing to events (e.g. `addEventListener`), timers (`setTimeout`), etc.\r\n\r\n```tsx\r\nconst timer = createGraphNode({\r\n  get: ({ subscription }) => {\r\n    subscription(() => {\r\n      const timeout = setTimeout(() => {\r\n        intervalLogic();\r\n      }, 1000);\r\n      return () => {\r\n        clearTimeout(timeout);\r\n      };\r\n    });\r\n  },\r\n});\r\n```\r\n\r\nSimilar to `get`, it doesn't matter when `subscription` is called. Every recomputation runs the cleanup function returned by `subscription`, and re-runs the callback.\r\n\r\n### Mutations\r\n\r\nThere are two kinds of state update in `graph-state`: `mutate` and `set`. `mutate` directly changes a node's state. `set`'s default behavior is similar to `mutate`, but if the node has a custom `set` function, the custom function is called instead of `mutate`. This is useful for building actions.\r\n\r\nBoth `get` and `set` received interfaces has functions that allow mutation.\r\n\r\n```tsx\r\n// A node that mutates itself.\r\nconst secondClock = createGraphNode({\r\n  get: ({ mutateSelf, subscription }) => {\r\n    subscription(() => {\r\n      // an internal variable that tracks a state.\r\n      let count = 0;\r\n\r\n      // Subscribe to an interval timer\r\n      const timeout = setInterval(() => {\r\n        // Update our counter\r\n        count += 1;\r\n\r\n        // Perform self-mutation\r\n        mutateSelf(count);\r\n      }, 1000);\r\n\r\n      return () => {\r\n        clearInterval(timeout);\r\n      };\r\n    });\r\n\r\n    return 0;\r\n  },\r\n});\r\n```\r\n\r\n### Actions\r\n\r\nInspired by Redux and Flux architecture, nodes can have an action-receiving function called `set`, which overrides the state mutation of the node. The `set` function accepts the same interface as `get` (excluding `subscription`) and the action being received. In contrast with `get`, `set` does not react nor connect to read nodes.\r\n\r\nAn example of a graph node emulating a Redux store.\r\n\r\n```tsx\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n\r\nconst reduce = (state, action) => {\r\n  switch (action.type) {\r\n    case 'INCREMENT':\r\n      return state + 1;\r\n    case 'DECREMENT':\r\n      return state - 1;\r\n    default:\r\n      return state;\r\n  }\r\n};\r\n\r\nconst reducer = createGraphNode({\r\n  get: ({ get }) => get(counter),\r\n\r\n  set: ({ get, set }, action) => {\r\n    set(counter, reduce(get(counter), action));\r\n  },\r\n});\r\n```\r\n\r\n### Memoization\r\n\r\nNodes have their values memoized. Once a node attempts to update its state with an equivalent value, dependencies don't get notified with the new state, thus bailing out of recomputation. `createGraphNode` accepts another optional field named `shouldUpdate` which is a function that receives the current state and the next state. By default, the states are compared with `Object.is`.\r\n\r\n### Concurrency\r\n\r\nNodes with asynchronous `get` or `set` may produce unwanted side-effects whenever both methods run immediately after one another. To fix this, nodes, internally, have built-in race conditions which allows further side-effects from occuring by preventing `set`, `mutate`, `setSelf`, `mutateSelf` and `subscription` from further evaluation.\r\n\r\n```tsx\r\nconst itemsList = createGraphNode({\r\n  get: async () => {\r\n    const data = await db.query();\r\n    return data;\r\n  },\r\n});\r\n\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    return applyFilter(currentList);\r\n  },\r\n}); \r\n```\r\n\r\nNodes also accept a `resolve` method from interface which wraps a given Promise such that it will only resolve if the node has not yet recomputed.\r\n\r\n```tsx\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get, resolve }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    // Prevent from resolving if recomputed\r\n    return resolve(applyFilter(currentList));\r\n  },\r\n}); \r\n```\r\n\r\nNodes that return a Promise may also be converted into an ADT node which emits the stateful representation of the Promise result by using `createGraphNodeResource`. The resource node emits an object with the following fields:\r\n\r\n- `status`: The status of the Promise result. Begins with `\"pending\"`, and changes to either `\"success\"` or `\"failure\"`.\r\n- `data`: Value being represented by `status`.\r\n  - if `status === \"success\"`, `data` is the resolved value.\r\n  - if `status === \"failure\"`, `data` is the rejected value.\r\n  - if `status === \"pending\"`, `data` is the resolving Promise instance.\r\n\r\n```tsx\r\nconst listResource = createGraphNodeResource(itemsList);\r\n\r\nconst example = createGraphNode({\r\n  get: ({ get }) => {\r\n    const { status, data } = get(listResource);\r\n\r\n    // ...\r\n  },\r\n});\r\n```\r\n\r\nA valid resource node can be reverted back to a promise using `fromPromise`.\r\n\r\nMultiple resources can be concurrently handled using `waitForAll` or `waitForAny`, which correspondingly behaves similarly to `Promise.all` and `Promise.race`.\r\n\r\n```tsx\r\nconst [name, age, email] = get(waitForAll([\r\n  nameResource,\r\n  ageResource,\r\n  emailResource,\r\n]));\r\n```\r\n\r\n### Factory\r\n\r\nFor producing multiple nodes with the same core logic but varying values, we can use `createGraphNodeFactory`:\r\n\r\n```tsx\r\nconst nameFactory = createGraphNodeFactory({\r\n  // Similar to individual nodes except dynamic\r\n  key: (id) => `/profile/name/${id}`,\r\n  \r\n  get: (id) => () => readProfileName(id),\r\n});\r\n\r\n// ...\r\nconst name = get(nameFactory(id));\r\n```\r\n\r\n`createGraphNodeFactory` produces a function that passes the arguments provided to `key`, `get` and `set`.\r\n\r\n```tsx\r\nconst updateName = createGraphNodeFactory({\r\n  key: (id) => `/profile/name/${id}/update`,\r\n\r\n  set: (id, defaultName) => ({ set }, name) => {\r\n    set(nameFactory(id), name ?? defaultName);\r\n  },\r\n});\r\n\r\n//...\r\nset(updateName(id, 'John Doe'), newName);\r\n```\r\n\r\nIf a factory returns a Promise, this factory can be wrapped with `createGraphNodeResourceFactory` to produce resource nodes.\r\n\r\n## License\r\n\r\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)\r\n","readmeFilename":"README.md","_id":"graph-state@1.6.2-alpha.5","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-XQXv9OrJaxOGmu4hNpPaR3+4haJkez2dZEkLVOdmLZ9B6OVoiFWOAWhLKD/QP4plH8jHUtFihupoIVDV6Kj+CQ==","shasum":"268b31ab1e8a593d8b46478a0c041f4892d241c5","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.6.2-alpha.5.tgz","fileCount":18,"unpackedSize":195503,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaTWvCRA9TVsSAnZWagAAbeAQAIbHqO5wZwfTbhA5M4uG\ngDXU49/idRtCnINaoOwmBotZzErsimSUqmZhGO40hNcUw7b8dpZprjrk0R18\nazf8rdN26MQ/3bHdzG8XLvxfC6Lyu/FPnLHwLuRM2FJ9gGIfop4swwZ5WJVT\n9KMb9KSEsSOa9fml6yrF3ZfxwkTx40Nu5k8GmrvUaCyFWS1mpXymXDJWpL47\n6d/Xj9w87TvIfUF/AmadRZnYU9ZbROTSpvZd+ujAdch5szvEUmM7yPPCXp1u\nm6dwVZcSDefGMPMcdh5L7GHpfuBgk7YCO0oHF4Qk1gYzVWqDhK6Z9Mhmu1nM\n2A67D4sKgPM/SlfUcvsO14/BZgxfV+g5AdYTZJfbvZ9sJk4j/Ab+3stLa6YF\n4a1glRIBi56b0oHwhEF4bAA7mdOrUD6Y+IBw3rj9bNeMOGtqIXIm9Y9R5Lhz\nL9dq2sBVp9rZ4q9oykTJivuJEiVS5YsB8IdG/7trWakrumRXU/5MmTSNsqrL\nD5gn2tHK02SfIRngmVB79fsbDBRzeXwqhgFC9k7NxOfQnf9eEijmrKiJJrPu\nwYZbXCHU3ZTz+ImHB0JubeWPSkX75sgQjzq3toSMXvLKqF30tfPa5KOTX9rl\nfCy3Rp/vQiSGeA3xvccWhjScjRThKt6QnJr8jBYrfaS+TUv88QcjhoXQ7WkB\nYOwp\r\n=qP6+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCimY+uHhLd5F6234epjDvbUeEGgIYAr3npGT9OHwmcKwIgTmbGOv68PdD8V2mRxDxRhmnNe1eAcUe2Y1LtE/f9dTQ="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.6.2-alpha.5_1617507758532_0.37959833007560384"},"_hasShrinkwrap":false},"1.6.2-alpha.6":{"version":"1.6.2-alpha.6","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"67d1e918687f58f362ec6b9aad619e27f7d441dd","readme":"# graph-state\r\n\r\n> Digraph-based state management\r\n\r\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\r\n\r\n## Install\r\n\r\n```bash\r\nyarn add graph-state\r\n```\r\n\r\n```bash\r\nnpm install graph-state\r\n```\r\n\r\n## Usage\r\n\r\n## Features\r\n\r\n### Think atomically\r\n\r\n`graph-state` motivates the use of granular stores, or we call them \"nodes\", that is, nodes that only store a single state.\r\n\r\n```tsx\r\nimport { createGraphNode } from 'graph-state';\r\n\r\n// A simple graph node usage\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n```\r\n\r\nNodes can have either a constant value as a default state, or provide a function that lazily computes the default state.\r\n\r\n```tsx\r\nconst randomState = createGraphNode({\r\n  get: () => Math.random(),\r\n});\r\n```\r\n\r\n### Dependency graph states\r\n\r\n`graph-state` leverages the cumbersome process of connecting stores to communicate one another by seamlessly connecting them. A node's `get` propery receives an interface which can be used to read other node's state. Once a node reads another node's value, the read node becomes a \"dependency\": whenever the dependency node updates value, the dependent node recomputes it's state.\r\n\r\n```tsx\r\nconst greeting = createGraphNode({\r\n  get: 'Hello',\r\n});\r\n\r\nconst person = createGraphNode({\r\n  get: 'John Doe',\r\n});\r\n\r\nconst message = createGraphNode({\r\n  get: ({ get }) => {\r\n    // Read the greeting and person nodes\r\n    const greetingValue = get(greeting);\r\n    const personValue = get(person);\r\n\r\n    // When greeting or person updates their state\r\n    // message re-runs its get function to create a new state.\r\n\r\n    // Return the derived state\r\n    return `${greetingValue}, ${personValue}.`;\r\n  },\r\n});\r\n```\r\n\r\nIt doesn't matter when `get` is called or how it is used:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  get: ({ get } => {\r\n    const cond = get(A);\r\n\r\n    if (cond) {\r\n      return get(B); // If A is truthy, B becomes a dependency.\r\n    }\r\n    return get(C); // Otherwise, C becomes the dependency instead of B.\r\n  }),\r\n});\r\n```\r\n\r\nWhenever `get` is called, the dependency list is rebuilt, so the timing doesn't matter for a node to become a dependency.\r\n\r\n### Lazy Evaluation\r\n\r\nNodes, even though can be created on any level of context, does not evaluate until needed/used.\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  // This function does not run until\r\n  // example is read.\r\n  get: () => runExpensiveComputation(),\r\n});\r\n```\r\n\r\n### Keys\r\n\r\nNodes may accept a `key` field:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  key: 'example',\r\n  get: 'Hello',\r\n});\r\n```\r\n\r\nIf another node of the same key is attempted to be created, the first instance is always reused.\r\n\r\nKeys you define are dev-only. Production environment will produce a unique id in place of the keys you provided.\r\n\r\n### Subscriptions\r\n\r\n`graph-state` allows managing subscriptions for side-effects. This is useful for subscribing to events (e.g. `addEventListener`), timers (`setTimeout`), etc.\r\n\r\n```tsx\r\nconst timer = createGraphNode({\r\n  get: ({ subscription }) => {\r\n    subscription(() => {\r\n      const timeout = setTimeout(() => {\r\n        intervalLogic();\r\n      }, 1000);\r\n      return () => {\r\n        clearTimeout(timeout);\r\n      };\r\n    });\r\n  },\r\n});\r\n```\r\n\r\nSimilar to `get`, it doesn't matter when `subscription` is called. Every recomputation runs the cleanup function returned by `subscription`, and re-runs the callback.\r\n\r\n### Mutations\r\n\r\nThere are two kinds of state update in `graph-state`: `mutate` and `set`. `mutate` directly changes a node's state. `set`'s default behavior is similar to `mutate`, but if the node has a custom `set` function, the custom function is called instead of `mutate`. This is useful for building actions.\r\n\r\nBoth `get` and `set` received interfaces has functions that allow mutation.\r\n\r\n```tsx\r\n// A node that mutates itself.\r\nconst secondClock = createGraphNode({\r\n  get: ({ mutateSelf, subscription }) => {\r\n    subscription(() => {\r\n      // an internal variable that tracks a state.\r\n      let count = 0;\r\n\r\n      // Subscribe to an interval timer\r\n      const timeout = setInterval(() => {\r\n        // Update our counter\r\n        count += 1;\r\n\r\n        // Perform self-mutation\r\n        mutateSelf(count);\r\n      }, 1000);\r\n\r\n      return () => {\r\n        clearInterval(timeout);\r\n      };\r\n    });\r\n\r\n    return 0;\r\n  },\r\n});\r\n```\r\n\r\n### Actions\r\n\r\nInspired by Redux and Flux architecture, nodes can have an action-receiving function called `set`, which overrides the state mutation of the node. The `set` function accepts the same interface as `get` (excluding `subscription`) and the action being received. In contrast with `get`, `set` does not react nor connect to read nodes.\r\n\r\nAn example of a graph node emulating a Redux store.\r\n\r\n```tsx\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n\r\nconst reduce = (state, action) => {\r\n  switch (action.type) {\r\n    case 'INCREMENT':\r\n      return state + 1;\r\n    case 'DECREMENT':\r\n      return state - 1;\r\n    default:\r\n      return state;\r\n  }\r\n};\r\n\r\nconst reducer = createGraphNode({\r\n  get: ({ get }) => get(counter),\r\n\r\n  set: ({ get, set }, action) => {\r\n    set(counter, reduce(get(counter), action));\r\n  },\r\n});\r\n```\r\n\r\n### Memoization\r\n\r\nNodes have their values memoized. Once a node attempts to update its state with an equivalent value, dependencies don't get notified with the new state, thus bailing out of recomputation. `createGraphNode` accepts another optional field named `shouldUpdate` which is a function that receives the current state and the next state. By default, the states are compared with `Object.is`.\r\n\r\n### Concurrency\r\n\r\nNodes with asynchronous `get` or `set` may produce unwanted side-effects whenever both methods run immediately after one another. To fix this, nodes, internally, have built-in race conditions which allows further side-effects from occuring by preventing `set`, `mutate`, `setSelf`, `mutateSelf` and `subscription` from further evaluation.\r\n\r\n```tsx\r\nconst itemsList = createGraphNode({\r\n  get: async () => {\r\n    const data = await db.query();\r\n    return data;\r\n  },\r\n});\r\n\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    return applyFilter(currentList);\r\n  },\r\n}); \r\n```\r\n\r\nNodes also accept a `resolve` method from interface which wraps a given Promise such that it will only resolve if the node has not yet recomputed.\r\n\r\n```tsx\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get, resolve }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    // Prevent from resolving if recomputed\r\n    return resolve(applyFilter(currentList));\r\n  },\r\n}); \r\n```\r\n\r\nNodes that return a Promise may also be converted into an ADT node which emits the stateful representation of the Promise result by using `createGraphNodeResource`. The resource node emits an object with the following fields:\r\n\r\n- `status`: The status of the Promise result. Begins with `\"pending\"`, and changes to either `\"success\"` or `\"failure\"`.\r\n- `data`: Value being represented by `status`.\r\n  - if `status === \"success\"`, `data` is the resolved value.\r\n  - if `status === \"failure\"`, `data` is the rejected value.\r\n  - if `status === \"pending\"`, `data` is the resolving Promise instance.\r\n\r\n```tsx\r\nconst listResource = createGraphNodeResource(itemsList);\r\n\r\nconst example = createGraphNode({\r\n  get: ({ get }) => {\r\n    const { status, data } = get(listResource);\r\n\r\n    // ...\r\n  },\r\n});\r\n```\r\n\r\nA valid resource node can be reverted back to a promise using `fromPromise`.\r\n\r\nMultiple resources can be concurrently handled using `waitForAll` or `waitForAny`, which correspondingly behaves similarly to `Promise.all` and `Promise.race`.\r\n\r\n```tsx\r\nconst [name, age, email] = get(waitForAll([\r\n  nameResource,\r\n  ageResource,\r\n  emailResource,\r\n]));\r\n```\r\n\r\n### Factory\r\n\r\nFor producing multiple nodes with the same core logic but varying values, we can use `createGraphNodeFactory`:\r\n\r\n```tsx\r\nconst nameFactory = createGraphNodeFactory({\r\n  // Similar to individual nodes except dynamic\r\n  key: (id) => `/profile/name/${id}`,\r\n  \r\n  get: (id) => () => readProfileName(id),\r\n});\r\n\r\n// ...\r\nconst name = get(nameFactory(id));\r\n```\r\n\r\n`createGraphNodeFactory` produces a function that passes the arguments provided to `key`, `get` and `set`.\r\n\r\n```tsx\r\nconst updateName = createGraphNodeFactory({\r\n  key: (id) => `/profile/name/${id}/update`,\r\n\r\n  set: (id, defaultName) => ({ set }, name) => {\r\n    set(nameFactory(id), name ?? defaultName);\r\n  },\r\n});\r\n\r\n//...\r\nset(updateName(id, 'John Doe'), newName);\r\n```\r\n\r\nIf a factory returns a Promise, this factory can be wrapped with `createGraphNodeResourceFactory` to produce resource nodes.\r\n\r\n## License\r\n\r\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)\r\n","readmeFilename":"README.md","_id":"graph-state@1.6.2-alpha.6","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-8VtXXtm7w3v1ExaQ3o9hhgvWnSf4JM7fJYt48tIRzCM2YiGG2pyQi1cXOzdkkvvsUswfcWzwsV7aoDz7p8JqcQ==","shasum":"61efe461e64e1b512e36131fc0885926df5b7329","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.6.2-alpha.6.tgz","fileCount":18,"unpackedSize":194110,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaTazCRA9TVsSAnZWagAA2toP/38LoTjh1++kfytGB7Pt\nKQVSIEA2SgaATO07kappk+aRTMm3PV+JLzmIFYdFYr8cvJ2JW2crQfJzgTiD\nGPzmzGyTuv8kf4HIOr4AmSB+5ieVRcHaA9636v1OI7NaC34YVwDLiLpJjl+T\nMSe7GpxxCYp0o4vsj8ApdhaPYw0q4Gb/WGmK9q2mLmIk9G/6whLd3wnt8SaY\nXWlC0B1FWsUEcZqzKTM9U2Q+YLemwnCE9qlNJlldPTOxIHSJdKmtONy/g9qt\ngZ2hcrunCajpFYOMvFrnnqkmVD/7wXtfifZE4cNAwEv2ma9XkhuZytXru0oT\n1Lwojxzkkzi7TdAhcVBV1Y2AMfDqNCXa0UvDkll1qJRv+AVgXbQZQfNI2F5M\nBh6/FMmpXlM+zxI8TiBGmvrZHKbbCw6AuIgZB0AudIaVfeMj2EsGb8OB3Am0\ndNhddzAPilz2TKe3cFhjIFFJMK2y6K7dGh2IstTaPpYEZdWAlaQ1qFZCGQ0x\nX3WIrZOFMOHlT0rd3Y8u38b1XJla+WaGWdwlW6A+DCNXrwFAFrGGxu+1bZrS\nTdxruxdhx2ewt7qrwj2iUugT7JMsS6MYeVsPd0zl6ndwqlZ1Q3MgyZAYrVNN\n5BDclOrkXRHvtfi2qG0u08kxvk8AldzG+6kAOFKMSjKnrDdVBnTvsOg+0QDy\nI53F\r\n=HeMC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF3mur6zC7dGmXhbHIwZ25Oi0sIr+YNDuJkS//Lu0GOpAiEA6wA/u6VXDHPuixMcdtd5pmL85Vbe2w+gXlJjfmJ/o1Y="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.6.2-alpha.6_1617508019198_0.7611263752527473"},"_hasShrinkwrap":false},"1.6.2-alpha.7":{"version":"1.6.2-alpha.7","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"597b9043b1774e76e57c07c596a84d87b7ecc437","readme":"# graph-state\r\n\r\n> Digraph-based state management\r\n\r\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\r\n\r\n## Install\r\n\r\n```bash\r\nyarn add graph-state\r\n```\r\n\r\n```bash\r\nnpm install graph-state\r\n```\r\n\r\n## Usage\r\n\r\n## Features\r\n\r\n### Think atomically\r\n\r\n`graph-state` motivates the use of granular stores, or we call them \"nodes\", that is, nodes that only store a single state.\r\n\r\n```tsx\r\nimport { createGraphNode } from 'graph-state';\r\n\r\n// A simple graph node usage\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n```\r\n\r\nNodes can have either a constant value as a default state, or provide a function that lazily computes the default state.\r\n\r\n```tsx\r\nconst randomState = createGraphNode({\r\n  get: () => Math.random(),\r\n});\r\n```\r\n\r\n### Dependency graph states\r\n\r\n`graph-state` leverages the cumbersome process of connecting stores to communicate one another by seamlessly connecting them. A node's `get` propery receives an interface which can be used to read other node's state. Once a node reads another node's value, the read node becomes a \"dependency\": whenever the dependency node updates value, the dependent node recomputes it's state.\r\n\r\n```tsx\r\nconst greeting = createGraphNode({\r\n  get: 'Hello',\r\n});\r\n\r\nconst person = createGraphNode({\r\n  get: 'John Doe',\r\n});\r\n\r\nconst message = createGraphNode({\r\n  get: ({ get }) => {\r\n    // Read the greeting and person nodes\r\n    const greetingValue = get(greeting);\r\n    const personValue = get(person);\r\n\r\n    // When greeting or person updates their state\r\n    // message re-runs its get function to create a new state.\r\n\r\n    // Return the derived state\r\n    return `${greetingValue}, ${personValue}.`;\r\n  },\r\n});\r\n```\r\n\r\nIt doesn't matter when `get` is called or how it is used:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  get: ({ get } => {\r\n    const cond = get(A);\r\n\r\n    if (cond) {\r\n      return get(B); // If A is truthy, B becomes a dependency.\r\n    }\r\n    return get(C); // Otherwise, C becomes the dependency instead of B.\r\n  }),\r\n});\r\n```\r\n\r\nWhenever `get` is called, the dependency list is rebuilt, so the timing doesn't matter for a node to become a dependency.\r\n\r\n### Lazy Evaluation\r\n\r\nNodes, even though can be created on any level of context, does not evaluate until needed/used.\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  // This function does not run until\r\n  // example is read.\r\n  get: () => runExpensiveComputation(),\r\n});\r\n```\r\n\r\n### Keys\r\n\r\nNodes may accept a `key` field:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  key: 'example',\r\n  get: 'Hello',\r\n});\r\n```\r\n\r\nIf another node of the same key is attempted to be created, the first instance is always reused.\r\n\r\nKeys you define are dev-only. Production environment will produce a unique id in place of the keys you provided.\r\n\r\n### Subscriptions\r\n\r\n`graph-state` allows managing subscriptions for side-effects. This is useful for subscribing to events (e.g. `addEventListener`), timers (`setTimeout`), etc.\r\n\r\n```tsx\r\nconst timer = createGraphNode({\r\n  get: ({ subscription }) => {\r\n    subscription(() => {\r\n      const timeout = setTimeout(() => {\r\n        intervalLogic();\r\n      }, 1000);\r\n      return () => {\r\n        clearTimeout(timeout);\r\n      };\r\n    });\r\n  },\r\n});\r\n```\r\n\r\nSimilar to `get`, it doesn't matter when `subscription` is called. Every recomputation runs the cleanup function returned by `subscription`, and re-runs the callback.\r\n\r\n### Mutations\r\n\r\nThere are two kinds of state update in `graph-state`: `mutate` and `set`. `mutate` directly changes a node's state. `set`'s default behavior is similar to `mutate`, but if the node has a custom `set` function, the custom function is called instead of `mutate`. This is useful for building actions.\r\n\r\nBoth `get` and `set` received interfaces has functions that allow mutation.\r\n\r\n```tsx\r\n// A node that mutates itself.\r\nconst secondClock = createGraphNode({\r\n  get: ({ mutateSelf, subscription }) => {\r\n    subscription(() => {\r\n      // an internal variable that tracks a state.\r\n      let count = 0;\r\n\r\n      // Subscribe to an interval timer\r\n      const timeout = setInterval(() => {\r\n        // Update our counter\r\n        count += 1;\r\n\r\n        // Perform self-mutation\r\n        mutateSelf(count);\r\n      }, 1000);\r\n\r\n      return () => {\r\n        clearInterval(timeout);\r\n      };\r\n    });\r\n\r\n    return 0;\r\n  },\r\n});\r\n```\r\n\r\n### Actions\r\n\r\nInspired by Redux and Flux architecture, nodes can have an action-receiving function called `set`, which overrides the state mutation of the node. The `set` function accepts the same interface as `get` (excluding `subscription`) and the action being received. In contrast with `get`, `set` does not react nor connect to read nodes.\r\n\r\nAn example of a graph node emulating a Redux store.\r\n\r\n```tsx\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n\r\nconst reduce = (state, action) => {\r\n  switch (action.type) {\r\n    case 'INCREMENT':\r\n      return state + 1;\r\n    case 'DECREMENT':\r\n      return state - 1;\r\n    default:\r\n      return state;\r\n  }\r\n};\r\n\r\nconst reducer = createGraphNode({\r\n  get: ({ get }) => get(counter),\r\n\r\n  set: ({ get, set }, action) => {\r\n    set(counter, reduce(get(counter), action));\r\n  },\r\n});\r\n```\r\n\r\n### Memoization\r\n\r\nNodes have their values memoized. Once a node attempts to update its state with an equivalent value, dependencies don't get notified with the new state, thus bailing out of recomputation. `createGraphNode` accepts another optional field named `shouldUpdate` which is a function that receives the current state and the next state. By default, the states are compared with `Object.is`.\r\n\r\n### Concurrency\r\n\r\nNodes with asynchronous `get` or `set` may produce unwanted side-effects whenever both methods run immediately after one another. To fix this, nodes, internally, have built-in race conditions which allows further side-effects from occuring by preventing `set`, `mutate`, `setSelf`, `mutateSelf` and `subscription` from further evaluation.\r\n\r\n```tsx\r\nconst itemsList = createGraphNode({\r\n  get: async () => {\r\n    const data = await db.query();\r\n    return data;\r\n  },\r\n});\r\n\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    return applyFilter(currentList);\r\n  },\r\n}); \r\n```\r\n\r\nNodes also accept a `resolve` method from interface which wraps a given Promise such that it will only resolve if the node has not yet recomputed.\r\n\r\n```tsx\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get, resolve }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    // Prevent from resolving if recomputed\r\n    return resolve(applyFilter(currentList));\r\n  },\r\n}); \r\n```\r\n\r\nNodes that return a Promise may also be converted into an ADT node which emits the stateful representation of the Promise result by using `createGraphNodeResource`. The resource node emits an object with the following fields:\r\n\r\n- `status`: The status of the Promise result. Begins with `\"pending\"`, and changes to either `\"success\"` or `\"failure\"`.\r\n- `data`: Value being represented by `status`.\r\n  - if `status === \"success\"`, `data` is the resolved value.\r\n  - if `status === \"failure\"`, `data` is the rejected value.\r\n  - if `status === \"pending\"`, `data` is the resolving Promise instance.\r\n\r\n```tsx\r\nconst listResource = createGraphNodeResource(itemsList);\r\n\r\nconst example = createGraphNode({\r\n  get: ({ get }) => {\r\n    const { status, data } = get(listResource);\r\n\r\n    // ...\r\n  },\r\n});\r\n```\r\n\r\nA valid resource node can be reverted back to a promise using `fromPromise`.\r\n\r\nMultiple resources can be concurrently handled using `waitForAll` or `waitForAny`, which correspondingly behaves similarly to `Promise.all` and `Promise.race`.\r\n\r\n```tsx\r\nconst [name, age, email] = get(waitForAll([\r\n  nameResource,\r\n  ageResource,\r\n  emailResource,\r\n]));\r\n```\r\n\r\n### Factory\r\n\r\nFor producing multiple nodes with the same core logic but varying values, we can use `createGraphNodeFactory`:\r\n\r\n```tsx\r\nconst nameFactory = createGraphNodeFactory({\r\n  // Similar to individual nodes except dynamic\r\n  key: (id) => `/profile/name/${id}`,\r\n  \r\n  get: (id) => () => readProfileName(id),\r\n});\r\n\r\n// ...\r\nconst name = get(nameFactory(id));\r\n```\r\n\r\n`createGraphNodeFactory` produces a function that passes the arguments provided to `key`, `get` and `set`.\r\n\r\n```tsx\r\nconst updateName = createGraphNodeFactory({\r\n  key: (id) => `/profile/name/${id}/update`,\r\n\r\n  set: (id, defaultName) => ({ set }, name) => {\r\n    set(nameFactory(id), name ?? defaultName);\r\n  },\r\n});\r\n\r\n//...\r\nset(updateName(id, 'John Doe'), newName);\r\n```\r\n\r\nIf a factory returns a Promise, this factory can be wrapped with `createGraphNodeResourceFactory` to produce resource nodes.\r\n\r\n## License\r\n\r\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)\r\n","readmeFilename":"README.md","_id":"graph-state@1.6.2-alpha.7","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-TrCspEGCttI39IrSI/i8nbJAWSNdMhTY5Q2Xu9+kRbk19ovlONaq7EYgtWaZ+RVp2lTUfzs8dhPH7g4A9FH/Zw==","shasum":"5621a36de4545b69ed1b431ed0e9d95d026e242d","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.6.2-alpha.7.tgz","fileCount":18,"unpackedSize":194084,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaTeyCRA9TVsSAnZWagAAHscP/0d+g0eggC1n/yB59HBl\nZ6zii+oYcxrYRUoSljWsQAJIwbJLmc8O7FZJX+iMvEXk3NK8C551RecF5sU5\njigsZslU7YCrxUJPjXkeZLdXIABeucjjGVyQMWFKe2IEBYU8wtUdLvvp/5JM\njvQz92+1axMK/4fREh/WCmg3fEf3ibZFjNl53rczTKfeGyYJOOzoocP8xExx\n9jK7CJJf8hz4ie/Kpqna/z72Pa0XhNG+m8gRzfZsjjA1q9sXO1JrKSpA6VAn\nQWqxiowvLgj7IBzTvwXIqVDysADBv7Id3vCLDzejcrFZl9wPT+MxIdxjOdy/\n49lrMr/g+adzvvqNNHQS5e4SKyWk0gpD7W8wogEwFHFYJMeYWin/eG6qAQ24\n/dkNQhfKycnjKtODMasV2GFOTKE+Oz442Vn+j0ds+z95wsOrGmEZZYvnT9HC\nwLCtOHphuTu4T+1SwN/XUAqwQrkGfj3kUjeWtWNTZezwb2i4sDx3b44GyxRZ\nThl5qr4CO2D6oSuDmwCvFHZjCMdTeFqH92Q0D54X5MeFkR5AowrMPq2J3Mxw\nEKW4Oi8QTVuw/fsCh8/C0Qc9nTUNg73FNhoeIqrcDxuZeMgpnDH6RPvjZJvF\nGH18FJ/JV2OpsX2isRBkZ3p2eyjMgtVHmDtGiz2yCbZ198hdWzAJDsYXfMyE\nSonv\r\n=s3Np\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDCvZ7Y422I+UfEQmKv7gNoPp1Ipn46JPUkeNguarR/QQIgbR/tq5fyfrzz0vWO4JoJ2PEK9e/8qfkyW0Zqr8Zx6aM="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.6.2-alpha.7_1617508274159_0.08730241222027169"},"_hasShrinkwrap":false},"1.6.2-alpha.8":{"version":"1.6.2-alpha.8","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"7ea318bb7556de56993acd25b7f6efa16d1a9295","readme":"# graph-state\r\n\r\n> Digraph-based state management\r\n\r\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\r\n\r\n## Install\r\n\r\n```bash\r\nyarn add graph-state\r\n```\r\n\r\n```bash\r\nnpm install graph-state\r\n```\r\n\r\n## Usage\r\n\r\n## Features\r\n\r\n### Think atomically\r\n\r\n`graph-state` motivates the use of granular stores, or we call them \"nodes\", that is, nodes that only store a single state.\r\n\r\n```tsx\r\nimport { createGraphNode } from 'graph-state';\r\n\r\n// A simple graph node usage\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n```\r\n\r\nNodes can have either a constant value as a default state, or provide a function that lazily computes the default state.\r\n\r\n```tsx\r\nconst randomState = createGraphNode({\r\n  get: () => Math.random(),\r\n});\r\n```\r\n\r\n### Dependency graph states\r\n\r\n`graph-state` leverages the cumbersome process of connecting stores to communicate one another by seamlessly connecting them. A node's `get` propery receives an interface which can be used to read other node's state. Once a node reads another node's value, the read node becomes a \"dependency\": whenever the dependency node updates value, the dependent node recomputes it's state.\r\n\r\n```tsx\r\nconst greeting = createGraphNode({\r\n  get: 'Hello',\r\n});\r\n\r\nconst person = createGraphNode({\r\n  get: 'John Doe',\r\n});\r\n\r\nconst message = createGraphNode({\r\n  get: ({ get }) => {\r\n    // Read the greeting and person nodes\r\n    const greetingValue = get(greeting);\r\n    const personValue = get(person);\r\n\r\n    // When greeting or person updates their state\r\n    // message re-runs its get function to create a new state.\r\n\r\n    // Return the derived state\r\n    return `${greetingValue}, ${personValue}.`;\r\n  },\r\n});\r\n```\r\n\r\nIt doesn't matter when `get` is called or how it is used:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  get: ({ get } => {\r\n    const cond = get(A);\r\n\r\n    if (cond) {\r\n      return get(B); // If A is truthy, B becomes a dependency.\r\n    }\r\n    return get(C); // Otherwise, C becomes the dependency instead of B.\r\n  }),\r\n});\r\n```\r\n\r\nWhenever `get` is called, the dependency list is rebuilt, so the timing doesn't matter for a node to become a dependency.\r\n\r\n### Lazy Evaluation\r\n\r\nNodes, even though can be created on any level of context, does not evaluate until needed/used.\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  // This function does not run until\r\n  // example is read.\r\n  get: () => runExpensiveComputation(),\r\n});\r\n```\r\n\r\n### Keys\r\n\r\nNodes may accept a `key` field:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  key: 'example',\r\n  get: 'Hello',\r\n});\r\n```\r\n\r\nIf another node of the same key is attempted to be created, the first instance is always reused.\r\n\r\nKeys you define are dev-only. Production environment will produce a unique id in place of the keys you provided.\r\n\r\n### Subscriptions\r\n\r\n`graph-state` allows managing subscriptions for side-effects. This is useful for subscribing to events (e.g. `addEventListener`), timers (`setTimeout`), etc.\r\n\r\n```tsx\r\nconst timer = createGraphNode({\r\n  get: ({ subscription }) => {\r\n    subscription(() => {\r\n      const timeout = setTimeout(() => {\r\n        intervalLogic();\r\n      }, 1000);\r\n      return () => {\r\n        clearTimeout(timeout);\r\n      };\r\n    });\r\n  },\r\n});\r\n```\r\n\r\nSimilar to `get`, it doesn't matter when `subscription` is called. Every recomputation runs the cleanup function returned by `subscription`, and re-runs the callback.\r\n\r\n### Mutations\r\n\r\nThere are two kinds of state update in `graph-state`: `mutate` and `set`. `mutate` directly changes a node's state. `set`'s default behavior is similar to `mutate`, but if the node has a custom `set` function, the custom function is called instead of `mutate`. This is useful for building actions.\r\n\r\nBoth `get` and `set` received interfaces has functions that allow mutation.\r\n\r\n```tsx\r\n// A node that mutates itself.\r\nconst secondClock = createGraphNode({\r\n  get: ({ mutateSelf, subscription }) => {\r\n    subscription(() => {\r\n      // an internal variable that tracks a state.\r\n      let count = 0;\r\n\r\n      // Subscribe to an interval timer\r\n      const timeout = setInterval(() => {\r\n        // Update our counter\r\n        count += 1;\r\n\r\n        // Perform self-mutation\r\n        mutateSelf(count);\r\n      }, 1000);\r\n\r\n      return () => {\r\n        clearInterval(timeout);\r\n      };\r\n    });\r\n\r\n    return 0;\r\n  },\r\n});\r\n```\r\n\r\n### Actions\r\n\r\nInspired by Redux and Flux architecture, nodes can have an action-receiving function called `set`, which overrides the state mutation of the node. The `set` function accepts the same interface as `get` (excluding `subscription`) and the action being received. In contrast with `get`, `set` does not react nor connect to read nodes.\r\n\r\nAn example of a graph node emulating a Redux store.\r\n\r\n```tsx\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n\r\nconst reduce = (state, action) => {\r\n  switch (action.type) {\r\n    case 'INCREMENT':\r\n      return state + 1;\r\n    case 'DECREMENT':\r\n      return state - 1;\r\n    default:\r\n      return state;\r\n  }\r\n};\r\n\r\nconst reducer = createGraphNode({\r\n  get: ({ get }) => get(counter),\r\n\r\n  set: ({ get, set }, action) => {\r\n    set(counter, reduce(get(counter), action));\r\n  },\r\n});\r\n```\r\n\r\n### Memoization\r\n\r\nNodes have their values memoized. Once a node attempts to update its state with an equivalent value, dependencies don't get notified with the new state, thus bailing out of recomputation. `createGraphNode` accepts another optional field named `shouldUpdate` which is a function that receives the current state and the next state. By default, the states are compared with `Object.is`.\r\n\r\n### Concurrency\r\n\r\nNodes with asynchronous `get` or `set` may produce unwanted side-effects whenever both methods run immediately after one another. To fix this, nodes, internally, have built-in race conditions which allows further side-effects from occuring by preventing `set`, `mutate`, `setSelf`, `mutateSelf` and `subscription` from further evaluation.\r\n\r\n```tsx\r\nconst itemsList = createGraphNode({\r\n  get: async () => {\r\n    const data = await db.query();\r\n    return data;\r\n  },\r\n});\r\n\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    return applyFilter(currentList);\r\n  },\r\n}); \r\n```\r\n\r\nNodes also accept a `resolve` method from interface which wraps a given Promise such that it will only resolve if the node has not yet recomputed.\r\n\r\n```tsx\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get, resolve }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    // Prevent from resolving if recomputed\r\n    return resolve(applyFilter(currentList));\r\n  },\r\n}); \r\n```\r\n\r\nNodes that return a Promise may also be converted into an ADT node which emits the stateful representation of the Promise result by using `createGraphNodeResource`. The resource node emits an object with the following fields:\r\n\r\n- `status`: The status of the Promise result. Begins with `\"pending\"`, and changes to either `\"success\"` or `\"failure\"`.\r\n- `data`: Value being represented by `status`.\r\n  - if `status === \"success\"`, `data` is the resolved value.\r\n  - if `status === \"failure\"`, `data` is the rejected value.\r\n  - if `status === \"pending\"`, `data` is the resolving Promise instance.\r\n\r\n```tsx\r\nconst listResource = createGraphNodeResource(itemsList);\r\n\r\nconst example = createGraphNode({\r\n  get: ({ get }) => {\r\n    const { status, data } = get(listResource);\r\n\r\n    // ...\r\n  },\r\n});\r\n```\r\n\r\nA valid resource node can be reverted back to a promise using `fromPromise`.\r\n\r\nMultiple resources can be concurrently handled using `waitForAll` or `waitForAny`, which correspondingly behaves similarly to `Promise.all` and `Promise.race`.\r\n\r\n```tsx\r\nconst [name, age, email] = get(waitForAll([\r\n  nameResource,\r\n  ageResource,\r\n  emailResource,\r\n]));\r\n```\r\n\r\n### Factory\r\n\r\nFor producing multiple nodes with the same core logic but varying values, we can use `createGraphNodeFactory`:\r\n\r\n```tsx\r\nconst nameFactory = createGraphNodeFactory({\r\n  // Similar to individual nodes except dynamic\r\n  key: (id) => `/profile/name/${id}`,\r\n  \r\n  get: (id) => () => readProfileName(id),\r\n});\r\n\r\n// ...\r\nconst name = get(nameFactory(id));\r\n```\r\n\r\n`createGraphNodeFactory` produces a function that passes the arguments provided to `key`, `get` and `set`.\r\n\r\n```tsx\r\nconst updateName = createGraphNodeFactory({\r\n  key: (id) => `/profile/name/${id}/update`,\r\n\r\n  set: (id, defaultName) => ({ set }, name) => {\r\n    set(nameFactory(id), name ?? defaultName);\r\n  },\r\n});\r\n\r\n//...\r\nset(updateName(id, 'John Doe'), newName);\r\n```\r\n\r\nIf a factory returns a Promise, this factory can be wrapped with `createGraphNodeResourceFactory` to produce resource nodes.\r\n\r\n## License\r\n\r\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)\r\n","readmeFilename":"README.md","_id":"graph-state@1.6.2-alpha.8","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-P0AM2px68CRseYHCVWPAss7Mu6/e11mRGAmgGRsu4X/KEhCDNBv42nzKgGSjeX60KoDTCdjliU2iJxy6Q2a6Ag==","shasum":"0a1f033e44f2899747715af8e81733b3fa62d729","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.6.2-alpha.8.tgz","fileCount":18,"unpackedSize":195681,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaTqvCRA9TVsSAnZWagAAKAcP/3wWPtoT9OHARYnnSvMS\ng3EpqO1+7bwrzGy+HYjg5dMT9p2LPhQl5RI3kcITgW2Q6pOGvrwet+DXqbDg\n2ki/ezMpX03nBl7y9xRxc9y6NgyXtwWaTlZdVPZWbl7B41HRRYyJF4CTjXfA\n4NV5cm6K4qVl+Hxun/p2sDBWP5EzJxtUD2UbVcMBrmEhmmL05fO+x0bI9mL5\nvJ3N2VJ+RY8QF2lredMJ3kUlTm/r8V96vD3i9F/yzsOv595gffQOS94KmILi\n9Zyb4xJX4ClWp8l6cLzS3Qyy6iiYjHvkKZhuzIsiCF01U1ikqC7eaNy5uUqO\nrBL69GheWPfKz3xFIkEsKVtIHlBVMhA66E8JEKw0eP5yfXmSVskGrd/YtQv5\nhAucKoiBwAslt5KJP5aZqobub1UaSKgbD+6U8ql7oz42VAb8Gl3qmsWmyFo3\n8AcUGsIxC0xa0V8d9JUmiPpLfhr8/CX5T2yCfSAviCHdIQt1uPRCxF6hA2Kc\nY3gTTi8p4wDMxl4GdagrwhDaz+W3ZqioGFY9RgNnkMbNruGKlWY8Qcfb2VFR\nh0VbBodH6TY0jc3AnOH0hBwdwsYLPS2H+wEiU8YBAT8Xp4NOWqAQnpwOWfWu\nllgT/JAR8RoKOuubpHtnAMD2RYrGwJ3luSBbRhKu0ktpPVcfLyUlG32kciYq\no7Pj\r\n=YfGU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD+lhfdU0zHzxb43fsnLGImIM6fDZ2dpSpE9BAGAbvTmgIhAO4L+QNg2jSoOhobu0JiFP2igR7VlIi6DEByyjOna7Eq"}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.6.2-alpha.8_1617509038823_0.7651053397864096"},"_hasShrinkwrap":false},"1.6.2-alpha.9":{"version":"1.6.2-alpha.9","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"3a62d13fa30c84ed88539a17b9b1facd789b82b4","readme":"# graph-state\r\n\r\n> Digraph-based state management\r\n\r\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\r\n\r\n## Install\r\n\r\n```bash\r\nyarn add graph-state\r\n```\r\n\r\n```bash\r\nnpm install graph-state\r\n```\r\n\r\n## Usage\r\n\r\n## Features\r\n\r\n### Think atomically\r\n\r\n`graph-state` motivates the use of granular stores, or we call them \"nodes\", that is, nodes that only store a single state.\r\n\r\n```tsx\r\nimport { createGraphNode } from 'graph-state';\r\n\r\n// A simple graph node usage\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n```\r\n\r\nNodes can have either a constant value as a default state, or provide a function that lazily computes the default state.\r\n\r\n```tsx\r\nconst randomState = createGraphNode({\r\n  get: () => Math.random(),\r\n});\r\n```\r\n\r\n### Dependency graph states\r\n\r\n`graph-state` leverages the cumbersome process of connecting stores to communicate one another by seamlessly connecting them. A node's `get` propery receives an interface which can be used to read other node's state. Once a node reads another node's value, the read node becomes a \"dependency\": whenever the dependency node updates value, the dependent node recomputes it's state.\r\n\r\n```tsx\r\nconst greeting = createGraphNode({\r\n  get: 'Hello',\r\n});\r\n\r\nconst person = createGraphNode({\r\n  get: 'John Doe',\r\n});\r\n\r\nconst message = createGraphNode({\r\n  get: ({ get }) => {\r\n    // Read the greeting and person nodes\r\n    const greetingValue = get(greeting);\r\n    const personValue = get(person);\r\n\r\n    // When greeting or person updates their state\r\n    // message re-runs its get function to create a new state.\r\n\r\n    // Return the derived state\r\n    return `${greetingValue}, ${personValue}.`;\r\n  },\r\n});\r\n```\r\n\r\nIt doesn't matter when `get` is called or how it is used:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  get: ({ get } => {\r\n    const cond = get(A);\r\n\r\n    if (cond) {\r\n      return get(B); // If A is truthy, B becomes a dependency.\r\n    }\r\n    return get(C); // Otherwise, C becomes the dependency instead of B.\r\n  }),\r\n});\r\n```\r\n\r\nWhenever `get` is called, the dependency list is rebuilt, so the timing doesn't matter for a node to become a dependency.\r\n\r\n### Lazy Evaluation\r\n\r\nNodes, even though can be created on any level of context, does not evaluate until needed/used.\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  // This function does not run until\r\n  // example is read.\r\n  get: () => runExpensiveComputation(),\r\n});\r\n```\r\n\r\n### Keys\r\n\r\nNodes may accept a `key` field:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  key: 'example',\r\n  get: 'Hello',\r\n});\r\n```\r\n\r\nIf another node of the same key is attempted to be created, the first instance is always reused.\r\n\r\nKeys you define are dev-only. Production environment will produce a unique id in place of the keys you provided.\r\n\r\n### Subscriptions\r\n\r\n`graph-state` allows managing subscriptions for side-effects. This is useful for subscribing to events (e.g. `addEventListener`), timers (`setTimeout`), etc.\r\n\r\n```tsx\r\nconst timer = createGraphNode({\r\n  get: ({ subscription }) => {\r\n    subscription(() => {\r\n      const timeout = setTimeout(() => {\r\n        intervalLogic();\r\n      }, 1000);\r\n      return () => {\r\n        clearTimeout(timeout);\r\n      };\r\n    });\r\n  },\r\n});\r\n```\r\n\r\nSimilar to `get`, it doesn't matter when `subscription` is called. Every recomputation runs the cleanup function returned by `subscription`, and re-runs the callback.\r\n\r\n### Mutations\r\n\r\nThere are two kinds of state update in `graph-state`: `mutate` and `set`. `mutate` directly changes a node's state. `set`'s default behavior is similar to `mutate`, but if the node has a custom `set` function, the custom function is called instead of `mutate`. This is useful for building actions.\r\n\r\nBoth `get` and `set` received interfaces has functions that allow mutation.\r\n\r\n```tsx\r\n// A node that mutates itself.\r\nconst secondClock = createGraphNode({\r\n  get: ({ mutateSelf, subscription }) => {\r\n    subscription(() => {\r\n      // an internal variable that tracks a state.\r\n      let count = 0;\r\n\r\n      // Subscribe to an interval timer\r\n      const timeout = setInterval(() => {\r\n        // Update our counter\r\n        count += 1;\r\n\r\n        // Perform self-mutation\r\n        mutateSelf(count);\r\n      }, 1000);\r\n\r\n      return () => {\r\n        clearInterval(timeout);\r\n      };\r\n    });\r\n\r\n    return 0;\r\n  },\r\n});\r\n```\r\n\r\n### Actions\r\n\r\nInspired by Redux and Flux architecture, nodes can have an action-receiving function called `set`, which overrides the state mutation of the node. The `set` function accepts the same interface as `get` (excluding `subscription`) and the action being received. In contrast with `get`, `set` does not react nor connect to read nodes.\r\n\r\nAn example of a graph node emulating a Redux store.\r\n\r\n```tsx\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n\r\nconst reduce = (state, action) => {\r\n  switch (action.type) {\r\n    case 'INCREMENT':\r\n      return state + 1;\r\n    case 'DECREMENT':\r\n      return state - 1;\r\n    default:\r\n      return state;\r\n  }\r\n};\r\n\r\nconst reducer = createGraphNode({\r\n  get: ({ get }) => get(counter),\r\n\r\n  set: ({ get, set }, action) => {\r\n    set(counter, reduce(get(counter), action));\r\n  },\r\n});\r\n```\r\n\r\n### Memoization\r\n\r\nNodes have their values memoized. Once a node attempts to update its state with an equivalent value, dependencies don't get notified with the new state, thus bailing out of recomputation. `createGraphNode` accepts another optional field named `shouldUpdate` which is a function that receives the current state and the next state. By default, the states are compared with `Object.is`.\r\n\r\n### Concurrency\r\n\r\nNodes with asynchronous `get` or `set` may produce unwanted side-effects whenever both methods run immediately after one another. To fix this, nodes, internally, have built-in race conditions which allows further side-effects from occuring by preventing `set`, `mutate`, `setSelf`, `mutateSelf` and `subscription` from further evaluation.\r\n\r\n```tsx\r\nconst itemsList = createGraphNode({\r\n  get: async () => {\r\n    const data = await db.query();\r\n    return data;\r\n  },\r\n});\r\n\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    return applyFilter(currentList);\r\n  },\r\n}); \r\n```\r\n\r\nNodes also accept a `resolve` method from interface which wraps a given Promise such that it will only resolve if the node has not yet recomputed.\r\n\r\n```tsx\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get, resolve }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    // Prevent from resolving if recomputed\r\n    return resolve(applyFilter(currentList));\r\n  },\r\n}); \r\n```\r\n\r\nNodes that return a Promise may also be converted into an ADT node which emits the stateful representation of the Promise result by using `createGraphNodeResource`. The resource node emits an object with the following fields:\r\n\r\n- `status`: The status of the Promise result. Begins with `\"pending\"`, and changes to either `\"success\"` or `\"failure\"`.\r\n- `data`: Value being represented by `status`.\r\n  - if `status === \"success\"`, `data` is the resolved value.\r\n  - if `status === \"failure\"`, `data` is the rejected value.\r\n  - if `status === \"pending\"`, `data` is the resolving Promise instance.\r\n\r\n```tsx\r\nconst listResource = createGraphNodeResource(itemsList);\r\n\r\nconst example = createGraphNode({\r\n  get: ({ get }) => {\r\n    const { status, data } = get(listResource);\r\n\r\n    // ...\r\n  },\r\n});\r\n```\r\n\r\nA valid resource node can be reverted back to a promise using `fromPromise`.\r\n\r\nMultiple resources can be concurrently handled using `waitForAll` or `waitForAny`, which correspondingly behaves similarly to `Promise.all` and `Promise.race`.\r\n\r\n```tsx\r\nconst [name, age, email] = get(waitForAll([\r\n  nameResource,\r\n  ageResource,\r\n  emailResource,\r\n]));\r\n```\r\n\r\n### Factory\r\n\r\nFor producing multiple nodes with the same core logic but varying values, we can use `createGraphNodeFactory`:\r\n\r\n```tsx\r\nconst nameFactory = createGraphNodeFactory({\r\n  // Similar to individual nodes except dynamic\r\n  key: (id) => `/profile/name/${id}`,\r\n  \r\n  get: (id) => () => readProfileName(id),\r\n});\r\n\r\n// ...\r\nconst name = get(nameFactory(id));\r\n```\r\n\r\n`createGraphNodeFactory` produces a function that passes the arguments provided to `key`, `get` and `set`.\r\n\r\n```tsx\r\nconst updateName = createGraphNodeFactory({\r\n  key: (id) => `/profile/name/${id}/update`,\r\n\r\n  set: (id, defaultName) => ({ set }, name) => {\r\n    set(nameFactory(id), name ?? defaultName);\r\n  },\r\n});\r\n\r\n//...\r\nset(updateName(id, 'John Doe'), newName);\r\n```\r\n\r\nIf a factory returns a Promise, this factory can be wrapped with `createGraphNodeResourceFactory` to produce resource nodes.\r\n\r\n## License\r\n\r\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)\r\n","readmeFilename":"README.md","_id":"graph-state@1.6.2-alpha.9","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-pEus2509pDTOVZsTQ6257MJ/mXO+D7pACVfUKd/vCv84gn5BVD+HcjfvJW4wPm4txP0oMBYcJmpdvBAhCfyOPQ==","shasum":"92c19ea82368a991cce5828d2853f7b95532d338","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.6.2-alpha.9.tgz","fileCount":18,"unpackedSize":195687,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaTr3CRA9TVsSAnZWagAAWngP/06E+ruirwN26m5KTxsG\nL8Fc/fgQ/wPSoQpjEgbO0nADyRq3WoMexOxM7b1BKXIp99YwsR4Y32VascKt\nYV24JCN02VJDgFdyYSTNIafX4AsGejSPxVRqFzthC+HFfC1lzGl39SLJ3s7w\nHzAGwrYR0LuOMbIVXTFlodkZs+ExbsEjy5ez15ykLmDm+sN2U/KKnlthlSpU\nkOG1+FIZWY0Liu2tmbWOkjd2snoYmqsjOmuwU39j1xpQZnJZhNOegRyrAKOb\nqqRUvnWpewO1b+yL0luYxQ7w6ObNXZF1FMEObTLcIblHooClpwejiZlGk+g+\n6Qo4YPd5APUrktld6byn+uQxrMbvi3N4Jh1+RmmYxv3EfZmKDYCysCFQUY1W\nSjlBnmf29AxG+/eYiw8VzSgLEsQ5Kmsy/WTuXtJJ9m70m7Fn04qs9SNEyXXD\n+bfk2f7NFu5Du5nXvcxf9VRStWFdEOoj3Zy4BOJXwYZrTctGK5KQxi942IpZ\n6zH53iH7g7e+RDzLqS26wd5x0EPDlmpaU3IpuwZ4gfAzJPqoMGFVzhY9Y7T1\ngVqnXUJ6NOa3K4In8YjAQ3RW+e2z6N8QZU/Nwyhte3FcYZiYTKtmcUQgBAaH\npZZd1f6GcCMMVrjGj6oBv3F5es5/0u3xzbEnREFQO465w2+dZiImYtoNuZzR\nG0Gq\r\n=H/Lh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCne2m1GV1cy/PfMI2/7fV20EJdahK/ZAhbezTRot0uWgIgGz/NdPH1NkDH6ZcBFrkyTeVpCl1B/qOl2T1hK2xGN+o="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.6.2-alpha.9_1617509111020_0.19348176891345048"},"_hasShrinkwrap":false},"1.6.2-alpha.12":{"version":"1.6.2-alpha.12","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"4681b45a310d32090edd342f1887be3fe3a0ec4c","readme":"# graph-state\r\n\r\n> Digraph-based state management\r\n\r\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\r\n\r\n## Install\r\n\r\n```bash\r\nyarn add graph-state\r\n```\r\n\r\n```bash\r\nnpm install graph-state\r\n```\r\n\r\n## Usage\r\n\r\n## Features\r\n\r\n### Think atomically\r\n\r\n`graph-state` motivates the use of granular stores, or we call them \"nodes\", that is, nodes that only store a single state.\r\n\r\n```tsx\r\nimport { createGraphNode } from 'graph-state';\r\n\r\n// A simple graph node usage\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n```\r\n\r\nNodes can have either a constant value as a default state, or provide a function that lazily computes the default state.\r\n\r\n```tsx\r\nconst randomState = createGraphNode({\r\n  get: () => Math.random(),\r\n});\r\n```\r\n\r\n### Dependency graph states\r\n\r\n`graph-state` leverages the cumbersome process of connecting stores to communicate one another by seamlessly connecting them. A node's `get` propery receives an interface which can be used to read other node's state. Once a node reads another node's value, the read node becomes a \"dependency\": whenever the dependency node updates value, the dependent node recomputes it's state.\r\n\r\n```tsx\r\nconst greeting = createGraphNode({\r\n  get: 'Hello',\r\n});\r\n\r\nconst person = createGraphNode({\r\n  get: 'John Doe',\r\n});\r\n\r\nconst message = createGraphNode({\r\n  get: ({ get }) => {\r\n    // Read the greeting and person nodes\r\n    const greetingValue = get(greeting);\r\n    const personValue = get(person);\r\n\r\n    // When greeting or person updates their state\r\n    // message re-runs its get function to create a new state.\r\n\r\n    // Return the derived state\r\n    return `${greetingValue}, ${personValue}.`;\r\n  },\r\n});\r\n```\r\n\r\nIt doesn't matter when `get` is called or how it is used:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  get: ({ get } => {\r\n    const cond = get(A);\r\n\r\n    if (cond) {\r\n      return get(B); // If A is truthy, B becomes a dependency.\r\n    }\r\n    return get(C); // Otherwise, C becomes the dependency instead of B.\r\n  }),\r\n});\r\n```\r\n\r\nWhenever `get` is called, the dependency list is rebuilt, so the timing doesn't matter for a node to become a dependency.\r\n\r\n### Lazy Evaluation\r\n\r\nNodes, even though can be created on any level of context, does not evaluate until needed/used.\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  // This function does not run until\r\n  // example is read.\r\n  get: () => runExpensiveComputation(),\r\n});\r\n```\r\n\r\n### Keys\r\n\r\nNodes may accept a `key` field:\r\n\r\n```tsx\r\nconst example = createGraphNode({\r\n  key: 'example',\r\n  get: 'Hello',\r\n});\r\n```\r\n\r\nIf another node of the same key is attempted to be created, the first instance is always reused.\r\n\r\nKeys you define are dev-only. Production environment will produce a unique id in place of the keys you provided.\r\n\r\n### Subscriptions\r\n\r\n`graph-state` allows managing subscriptions for side-effects. This is useful for subscribing to events (e.g. `addEventListener`), timers (`setTimeout`), etc.\r\n\r\n```tsx\r\nconst timer = createGraphNode({\r\n  get: ({ subscription }) => {\r\n    subscription(() => {\r\n      const timeout = setTimeout(() => {\r\n        intervalLogic();\r\n      }, 1000);\r\n      return () => {\r\n        clearTimeout(timeout);\r\n      };\r\n    });\r\n  },\r\n});\r\n```\r\n\r\nSimilar to `get`, it doesn't matter when `subscription` is called. Every recomputation runs the cleanup function returned by `subscription`, and re-runs the callback.\r\n\r\n### Mutations\r\n\r\nThere are two kinds of state update in `graph-state`: `mutate` and `set`. `mutate` directly changes a node's state. `set`'s default behavior is similar to `mutate`, but if the node has a custom `set` function, the custom function is called instead of `mutate`. This is useful for building actions.\r\n\r\nBoth `get` and `set` received interfaces has functions that allow mutation.\r\n\r\n```tsx\r\n// A node that mutates itself.\r\nconst secondClock = createGraphNode({\r\n  get: ({ mutateSelf, subscription }) => {\r\n    subscription(() => {\r\n      // an internal variable that tracks a state.\r\n      let count = 0;\r\n\r\n      // Subscribe to an interval timer\r\n      const timeout = setInterval(() => {\r\n        // Update our counter\r\n        count += 1;\r\n\r\n        // Perform self-mutation\r\n        mutateSelf(count);\r\n      }, 1000);\r\n\r\n      return () => {\r\n        clearInterval(timeout);\r\n      };\r\n    });\r\n\r\n    return 0;\r\n  },\r\n});\r\n```\r\n\r\n### Actions\r\n\r\nInspired by Redux and Flux architecture, nodes can have an action-receiving function called `set`, which overrides the state mutation of the node. The `set` function accepts the same interface as `get` (excluding `subscription`) and the action being received. In contrast with `get`, `set` does not react nor connect to read nodes.\r\n\r\nAn example of a graph node emulating a Redux store.\r\n\r\n```tsx\r\nconst counter = createGraphNode({\r\n  get: 0,\r\n});\r\n\r\nconst reduce = (state, action) => {\r\n  switch (action.type) {\r\n    case 'INCREMENT':\r\n      return state + 1;\r\n    case 'DECREMENT':\r\n      return state - 1;\r\n    default:\r\n      return state;\r\n  }\r\n};\r\n\r\nconst reducer = createGraphNode({\r\n  get: ({ get }) => get(counter),\r\n\r\n  set: ({ get, set }, action) => {\r\n    set(counter, reduce(get(counter), action));\r\n  },\r\n});\r\n```\r\n\r\n### Memoization\r\n\r\nNodes have their values memoized. Once a node attempts to update its state with an equivalent value, dependencies don't get notified with the new state, thus bailing out of recomputation. `createGraphNode` accepts another optional field named `shouldUpdate` which is a function that receives the current state and the next state. By default, the states are compared with `Object.is`.\r\n\r\n### Concurrency\r\n\r\nNodes with asynchronous `get` or `set` may produce unwanted side-effects whenever both methods run immediately after one another. To fix this, nodes, internally, have built-in race conditions which allows further side-effects from occuring by preventing `set`, `mutate`, `setSelf`, `mutateSelf` and `subscription` from further evaluation.\r\n\r\n```tsx\r\nconst itemsList = createGraphNode({\r\n  get: async () => {\r\n    const data = await db.query();\r\n    return data;\r\n  },\r\n});\r\n\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    return applyFilter(currentList);\r\n  },\r\n}); \r\n```\r\n\r\nNodes also accept a `resolve` method from interface which wraps a given Promise such that it will only resolve if the node has not yet recomputed.\r\n\r\n```tsx\r\nconst filteredItemsList = createGraphNode({\r\n  get: async ({ get, resolve }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    // Prevent from resolving if recomputed\r\n    return resolve(applyFilter(currentList));\r\n  },\r\n}); \r\n```\r\n\r\nNodes that return a Promise may also be converted into an ADT node which emits the stateful representation of the Promise result by using `createGraphNodeResource`. The resource node emits an object with the following fields:\r\n\r\n- `status`: The status of the Promise result. Begins with `\"pending\"`, and changes to either `\"success\"` or `\"failure\"`.\r\n- `data`: Value being represented by `status`.\r\n  - if `status === \"success\"`, `data` is the resolved value.\r\n  - if `status === \"failure\"`, `data` is the rejected value.\r\n  - if `status === \"pending\"`, `data` is the resolving Promise instance.\r\n\r\n```tsx\r\nconst listResource = createGraphNodeResource(itemsList);\r\n\r\nconst example = createGraphNode({\r\n  get: ({ get }) => {\r\n    const { status, data } = get(listResource);\r\n\r\n    // ...\r\n  },\r\n});\r\n```\r\n\r\nA valid resource node can be reverted back to a promise using `fromPromise`.\r\n\r\nMultiple resources can be concurrently handled using `waitForAll` or `waitForAny`, which correspondingly behaves similarly to `Promise.all` and `Promise.race`.\r\n\r\n```tsx\r\nconst [name, age, email] = get(waitForAll([\r\n  nameResource,\r\n  ageResource,\r\n  emailResource,\r\n]));\r\n```\r\n\r\n### Factory\r\n\r\nFor producing multiple nodes with the same core logic but varying values, we can use `createGraphNodeFactory`:\r\n\r\n```tsx\r\nconst nameFactory = createGraphNodeFactory({\r\n  // Similar to individual nodes except dynamic\r\n  key: (id) => `/profile/name/${id}`,\r\n  \r\n  get: (id) => () => readProfileName(id),\r\n});\r\n\r\n// ...\r\nconst name = get(nameFactory(id));\r\n```\r\n\r\n`createGraphNodeFactory` produces a function that passes the arguments provided to `key`, `get` and `set`.\r\n\r\n```tsx\r\nconst updateName = createGraphNodeFactory({\r\n  key: (id) => `/profile/name/${id}/update`,\r\n\r\n  set: (id, defaultName) => ({ set }, name) => {\r\n    set(nameFactory(id), name ?? defaultName);\r\n  },\r\n});\r\n\r\n//...\r\nset(updateName(id, 'John Doe'), newName);\r\n```\r\n\r\nIf a factory returns a Promise, this factory can be wrapped with `createGraphNodeResourceFactory` to produce resource nodes.\r\n\r\n## License\r\n\r\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)\r\n","readmeFilename":"README.md","_id":"graph-state@1.6.2-alpha.12","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-4XXSIdV5luWrmp5AwHqsAfQNnsdUs/6utoPqTAp2PhY4ysCBa1iEr2kzVQ11sj4yL2NjSI0CsPIVFeYFUCT8hA==","shasum":"cfb6e8a39539ae11d8d94736620642d273ed8ac8","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-1.6.2-alpha.12.tgz","fileCount":18,"unpackedSize":196170,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaWAaCRA9TVsSAnZWagAA5ngP/im3ePw9vAHifFsfP1va\nhwUV8JF9kd2b9tAX4cOvxYIxOjoBaK9bJUJkxpgVkNEloUKxb44u7kbkrNPI\n/2yB530qdXFZf/X8GTTrMJ1ACo78Afg5YifpPkGW3NzOeLCmlfaqyHUfr/Xf\nxfupjO5MvW+m5v88GkFeUYDsiA2DHXmZZNUZoLcpDAhFlb72wTpcFJh7lyMU\naKFxBhdyC9NF93NxLaY3a5bVCN62O5knlLXJQ4a9ny9IY/oBu/gSNceHmIn9\n7nqL3f8VtXoUt+koeju0igQYur16laTAuWNQFqKf+PP3sdfeh6rYtdiVL/HB\nKxF2q3j9S9uVqkc+BKF53aoseemS1NHnVxFRf2dTyYBUw0mK9rpfNVK4/9Sg\nLSpw1gTMGmyVR9b5msew1ESdTvmaoxNAbm8ey7dm588ifAlKrO88N5PotAU1\ntGaesBcWH10BUwmoDZqV0jEkygHcQZj3CnVtYmm9yMHsziwps7EXKAm0uyBC\niceZxjzOIBCx9ipJMd2H47R7iITzctb4uh5rDmku5EkwxGBeTZayf7AgrGLl\nq1Zw08pt9wor4L2372CE67Vt2fOh/a5S/FuqNAIGt9dz7L6oiDcVyhWGl8uq\nLXC02wCzDs7tlSXnF9yac5xuZwCgRuIYGOgDlziXaJWGc9yGBnIfsf1jDW/I\n8snA\r\n=PmPu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCPKbfd+MG28Lg0ceDGMsmwicpUGNINqnr/J9PUopWqvQIgLpIJMTvnQ8Yg3g61qwVYhKdnINtvo+miAwj2bDApMhU="}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_1.6.2-alpha.12_1617518618358_0.7979619116889178"},"_hasShrinkwrap":false},"2.0.0":{"version":"2.0.0","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.34","eslint":"^7.22.0","eslint-config-lxsmnsyc":"^0.1.20","pridepack":"^0.8.0","ts-jest":"^26.5.3","tslib":"^2.1.0","typescript":"^4.2.3"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"gitHead":"0518b879f40799a56c59dec1739b3560b7650ccb","_id":"graph-state@2.0.0","_nodeVersion":"15.4.0","_npmVersion":"lerna/3.22.1/node@v15.4.0+x64 (win32)","_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"dist":{"integrity":"sha512-uqr9rO4A52B6xKRlal6Pv3gIJ+TvfjU2hFohetluqrSLSCRG7/do6I4/pcxJjQA7O0V7wHyipvIneRuisAYX2g==","shasum":"42abd214f27e0b1f7cf04b555af602b877105680","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-2.0.0.tgz","fileCount":20,"unpackedSize":210629,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgevKxCRA9TVsSAnZWagAAiSAQAJ2DMlEIdobAwuqAXxMo\n2kFuNn+dskzJPtGqpnuDm5zxjCYEcQPuQDD3HdBsMV1ahRbOhw9Mmop+Z6PT\nauy2FR+4yVcaXEzQNbMLQKQU69U0pOvWXMaP2vTsP0pbpCiH2zFZOEvWuMHN\nwiL+03CJLl8Vpd6+yG9Za9n4ehRyi9wDHMBHjM+OKvoLQ+Virj71XRntPHO2\nfMg9g9E3qwMGn3ZfudW9bNPK1gBScd3RusoGpFWGWU8IudAJJJ0Rae0lyXsk\nyRQBNh5sZ/5YSgnJBLozzpsBxfGAQgzeVl4t27SuQIU/vhMYvG8w5i5XQLtA\nCji5Un5XuvagudZQ/b//QZvu8d3GnpOJKrNGmfAir7f+YBbwvx/knGf3Rtm4\nHvSJWbh4Wc2yTVHpMLubMpTWL9ZSiebIV0hL7R8c2h7xbEEif2TqwNvk71aV\nFhC4byhtpAsMja1dE+EiewQi/ESLGQzMUCZlm//qjIrvXi/TuXsIiXuayLON\ndMqkDG2fHo3HJ37yw4dan73NVDfZzd1V5amIzv3+nsrlB2SugUxzIwZ9vqKO\nAGvRkHjKCxxleqKQWWUPd0SYb9TDS1opMbzIat3frMrk3QfrKLFAFbxePPMS\n+4iBE9TKnXgTzbi+msE2WuYcD5Ypm8QT+LiIG0EtzxlvnTcEinBkfJbFHn3E\njqbG\r\n=DGfY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDbglrdSfQ32LcQuGzXQ0EZUyy2RE+1qXgp2akYdAHuQwIhAPTf9b+pv92Wd03P+txeGyztLLtEVNuhb28FP5lX6eJ1"}]},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_2.0.0_1618670256847_0.6845112747573543"},"_hasShrinkwrap":false},"2.1.0":{"version":"2.1.0","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.41","eslint":"^7.24.0","eslint-config-lxsmnsyc":"^0.2.1","pridepack":"^0.9.2","ts-jest":"^26.5.5","tslib":"^2.2.0","typescript":"^4.2.4"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"dependencies":{"superjson":"^1.7.4"},"gitHead":"dcb1fd0346452f797b66fea07a77179bfff22e2d","_id":"graph-state@2.1.0","_nodeVersion":"15.4.0","_npmVersion":"lerna/4.0.0/node@v15.4.0+x64 (win32)","dist":{"integrity":"sha512-6BojN+t0FD+X3TSaHz459sbYULO5lpuyhZFtS1PL6XZ4SfdnVimmntrHAm/5q45+6CaAsoY26cgmhAy6iO08Wg==","shasum":"ed40e9feca59de9ff1aa6a34fc4dc99eca0385ac","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-2.1.0.tgz","fileCount":22,"unpackedSize":233403,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJggqUhCRA9TVsSAnZWagAA6fIP/R62HtUyPSGx56Hor7wa\nLcYQBCgctF/eZ9jb9NqU016HbKnwbA2Xp8vYnw+o+5LEI9wrXM+9SnfPQWyu\nsfQUZMXJDjjo+VdpWSK0eQg0jkktfojao+YRoPtixJYPHSKoBzJHFZCD2pHx\nZWEcT3MTAokoNrbJePCZEsgEaezIz0OCv78VKlv7kYhpXCdLrdWhLKXg7Uuw\nzthDzLvrj/kHlEeO/j6tOxqxbc5YEYHBrt5CpLOR/9HnaqfnItiXNyzgKULx\nwXRtud26lr5yXi0n3nC7DDYO5mLYDoHiaW9imasAYvS09AneFJ6ZU2944i9e\nzSy0tI7fww7ztLOjVA0J0KRZFD66KEyplTORMW+1G1iVokkch5HOP7YojERZ\nzhwF7lvgKuyLAwidZh9/iMxCq/O/sCFW6c2jzjJ3K+G75HOd/VgZIJriVoux\nh6YhnNQxaB6GF6Fw6+8WMtnlbJFUi2IWE++Ste01t0ovVtk8no6sc93+axqM\nE6LS0DMSgxDh54aHh8U3JQeh/IzVvCdY9wPeuVESDCL0X/W24hU7OvGKI8D5\nILTTXVE2RDOwruYnzsqIxshk13M/lCLhEJF6Si3dmsxoNJQyBFxA6xoqETd+\nj3ScFIGsRtZx7REygFK+pTNQI3obUweSGipyrZMWNhNgLVyE0s9b/DRSXjmS\nWJgX\r\n=BPxm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICGPT4xlLrFukrCMYtEyaN+JGSALoQ2BbNT/X5Z4K0ZLAiBkC99ro68GxTbarrmECXJ0fP54kumAF2f9GG5BQ0JYBQ=="}]},"_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_2.1.0_1619174688579_0.5836369274031423"},"_hasShrinkwrap":false},"2.1.1":{"version":"2.1.1","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.41","eslint":"^7.24.0","eslint-config-lxsmnsyc":"^0.2.1","pridepack":"^0.9.2","ts-jest":"^26.5.5","tslib":"^2.2.0","typescript":"^4.2.4"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"dependencies":{"ecmason":"^0.1.3"},"gitHead":"59c6ca84e60309b287b590f06d46f523badb44ed","_id":"graph-state@2.1.1","_nodeVersion":"15.4.0","_npmVersion":"lerna/4.0.0/node@v15.4.0+x64 (win32)","dist":{"integrity":"sha512-mHWNGL5onUMMtkSXKxX0qsYJSAdzRte/u7Zktt72KLJyNSwtkUbNDjh3sN6JoVyby/pCi+rigqzH0XcAlhkQMw==","shasum":"67154fcbdde02144f492cfb3d76c12e010d9775f","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-2.1.1.tgz","fileCount":22,"unpackedSize":236423,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJghsSACRA9TVsSAnZWagAAZC0QAJnO0j6X8dCTlVg6nipS\nCcHOxJYXiG7w0il4iQo4O99/WLyfqp2JG3atTxmV+j/Lgq7fHKF0J5Tn58aU\nLqputxa1iQBxRPNhlbwivix5LUs2ZYBPm9poCteRw+3p2VKWSH9aXWh26k2z\nsq+/zuau6wlaG6EGQdG9yQkttG7/8jkIlO0Ivni4KY2GUBB7n/llCAA5juzo\nNVs/G4qveoHLYWpT0EIqTGJ2b9rcLsMSYW1zYN0iKL7NyLcPnRhgkW8xpK09\nhgMrggM1ocapWIfVyfcT7n/jOA+O6hsFxuzUFv3javnf3ZhI/lPD+QgYrRJM\nSnMfvHarx4cMB/MuGduXFNDqeLQPzcIn7NmSUw4TkhCYCOv/g20qXexyS+h7\nkX7QHsaGK5rqenpyYu8XL+JuBsyNC3YwYjPVq5TPXIO7cV0IghOU5JT4bgWd\niLZuHX1Uyrptbfa5UD0LOKGaSeyCCi7dX9XmS2dJ5zGCpXEq2FcauVhrWo4h\nkNu+biidhR+ezqHBCrxaCGCZo2oI7cBjhNC8w/CjHiPMr88pRYYF68VCD5Qt\n4I7Xx4upCLsNB9f2GvI4dl1SePnBwFWuvMtkfqoYkvWmHhHucpexaegoh/xq\ng9x+JCAerOT6I7xJXz/JkHsVx/ECj/1NK6UF2phxi4SbaK8RdmOOT/FUobh1\naKif\r\n=wPoJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICC4cJdkQORuWAwz3oEHTbuwOBOejBew/GZCb1jn8IECAiEAklH5OzIkm3CzIuc9b6Dxw3N4xEc7jEDfV7v6ulklUCo="}]},"_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_2.1.1_1619444863598_0.8008005493769152"},"_hasShrinkwrap":false},"2.1.2":{"version":"2.1.2","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.23","@types/node":"^15.0.2","eslint":"^7.25.0","eslint-config-lxsmnsyc":"^0.2.1","pridepack":"^0.9.3","ts-jest":"^26.5.6","tslib":"^2.2.0","typescript":"^4.2.4"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"dependencies":{"ecmason":"^0.1.3"},"gitHead":"0b6fa93a86e839b7cfd39b18218e5dcedbf416c7","_id":"graph-state@2.1.2","_nodeVersion":"15.4.0","_npmVersion":"lerna/4.0.0/node@v15.4.0+x64 (win32)","dist":{"integrity":"sha512-XGVG2SzAIwip5/78+gaTP4FvKYgQ4KSe7Pfm6HGtXYGzqUmB+dGqHaSIs9i731pG2BYKO600CW0MZ4XgF0MgPQ==","shasum":"2cad7de2b12bdc088201a76af84129f65b517abc","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-2.1.2.tgz","fileCount":22,"unpackedSize":236421,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgk/WnCRA9TVsSAnZWagAAHtUP/2G1XwJ25lbg+GC2d03Q\nfwoB5ZKJfb31qEg+/lS7tR1fWmDrJxSNgxoe//JDeNZCgsGza9DwlTCpY0fG\ncTrYjcN1ikL6frLwZYBkq5v0JNVfAdMZDmqO+OFbdQfohmGj+IbUDXI1HzWv\nZapJpW/1+EhGNP9NKUhmLB9jprYVlbqTHi7VE4ypsEKOJbGoE0HHSFd3g3Q5\nNsneNzxHlOm9Ug5hQiCwcCVacKEcPdAfeIoZvmB2hulk0cO9Sp9ysaTy5THy\n8NMZndflc8IHz3BKe3APZ5Jiv6uOOjrGYtErfxZ/PUxu4JR5nUy075rRoqri\n4zWAhnUA5dxkBmW7vG8WYnV7Ci392MIFGHZV32oCh8dthXblJa70sTMKcwzY\na/YyJA8iVfh0waKtSf/CDjDvWuDw0dZVK3+QA/br5UU+xCaGFyTPMyszX6oM\nkMQxRMpG3AjJub/5x2I7IJt1/z5tkkhOpAZyQAwMbXburRXHtkKlR390cz5u\nvkiOX+4beOq0jQIXsYin+dmTGZVpv7j/WXDL8XAh6rcgusb4qEMoyaxsB9o5\nQRfdPySyrQi6AGhALjQ80I8tE4f9K+AGUCRMBnJXH5sdDqc9Xrh26WjZTVkm\n/2SCSApEgLka3ZMRCoUitHhrIOhJDZRda5c/YE2kasfwidp9tU6folWHuAkR\ni/sB\r\n=Nq4r\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEaN2uGSqNYMhiRYIB71PIrr43ReBIj/zIj5V974BEYkAiEAhajcKrhRWzV/ncfg20GksmAJrkXYBmVcZj8yUc5ne2M="}]},"_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_2.1.2_1620309415091_0.36219081160455424"},"_hasShrinkwrap":false},"2.1.3":{"version":"2.1.3","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.23","@types/node":"^15.12.2","eslint":"^7.28.0","eslint-config-lxsmnsyc":"^0.2.1","pridepack":"^0.9.3","tslib":"^2.3.0","typescript":"^4.3.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"dependencies":{"ecmason":"^0.2.0"},"gitHead":"cb68222c7f85e73b02af165350f0c5b6f887470e","_id":"graph-state@2.1.3","_nodeVersion":"15.4.0","_npmVersion":"lerna/4.0.0/node@v15.4.0+x64 (win32)","dist":{"integrity":"sha512-lygj9ucA6p/j8QFtJr6F5bgG5vLYrQ1F/Tkx0ZKXyaaNmyEM3ib6V09JKyGqIHb4tczkW692sizRNoEcKOM2VA==","shasum":"0a8f9a37b2018c30d0dcea8192aabe417921add0","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-2.1.3.tgz","fileCount":22,"unpackedSize":237437,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgxxHOCRA9TVsSAnZWagAA+GAQAKI2xUoc6QP6p/CR4QuS\nrSVi1Uvjcl78wjJrM1CowPtis9Zc1mB5nQZoAKMCp9sdC2YjdilWfMyQ/D5J\nOisOkvw+kbD2/EHCUjxfz87meDbOQZNrm8RAKJaYAY4P3H14a36NNTaKr3Dj\nIVIYC1S51jmkgDa18+6I7oBEbSp2VHIZOFGYhieuE7xGaQS5+wjdHCpyp1ca\ng0eEkaKjWbT6OoXhXzQBQbgSZrSZT+4x8knK1XnVpoC4WuIhtenaXLxGNT3s\nv/sX9sxE5XE/cIYTWfZekLjoJXhG4hzz77ca5XV8etSS8jRElOhG9hixK7QL\ndIJ2NGJHM+8sq46cV/QP4Q5k/jG0y/ruRqSTqHgmgFhUwQiM/3SRIvehWG7q\nLCcvyehqKzGs6VfIJAumIgK0H1UBBr0YUjf6BdA+Mk+hLKAXiI8rWbdjzm/X\nBjxIBZmfTrOqVqkzf1GWfdNPgtNk4UaJdmeakEwAMdLdyiBAjKkZrQ13b2sN\nPSBGlqZt1iLGvOa9tpWrf39l6Uab/iAFA4Wy1ngjK250taYtgMBD8qU9Oo1D\nYSzDcx71gPPV9bUTkMGe+UM+FqPGYnHZ5IKqnTb8TBGVpufakFelJBvMNTAc\nXcosHd0BEb+gmtWAbmRK8A/eX1E/suSSpHvjGzwtLXMarnfwv12Tkrj76Jrg\nba7u\r\n=8GfP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDZDoKoZs/fNKkjUNcN8GFAowx8D8jArHH9h7RYWtGIGQIhAIbb/kT3lCLtqG/KQ/4jFGsv/TBD7PWUCunE3/OScwi7"}]},"_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_2.1.3_1623658958053_0.6502938698602301"},"_hasShrinkwrap":false},"2.1.4":{"version":"2.1.4","main":"dist/cjs/index.js","module":"dist/esm/index.js","exports":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"types":"dist/types/index.d.ts","engines":{"node":">=10"},"scripts":{"prepublish":"pridepack clean && pridepack build","build":"pridepack build","type-check":"pridepack check","lint":"pridepack lint","test":"pridepack test --passWithNoTests","clean":"pridepack clean","watch":"pridepack watch"},"license":"MIT","name":"graph-state","devDependencies":{"@types/jest":"^26.0.23","@types/node":"^15.12.2","eslint":"^7.28.0","eslint-config-lxsmnsyc":"^0.2.1","pridepack":"^0.10.0","tslib":"^2.3.0","typescript":"^4.3.2"},"description":"Digraph-based state management","author":{"name":"Alexis Munsayac"},"repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"homepage":"https://github.com/lxsmnsyc/graph-state","bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"],"dependencies":{"ecmason":"^0.2.1"},"gitHead":"9007b80a1c47f90fcd88b7c55a0a62c6a27eaceb","_id":"graph-state@2.1.4","_nodeVersion":"15.4.0","_npmVersion":"lerna/4.0.0/node@v15.4.0+x64 (win32)","dist":{"integrity":"sha512-/Qsg9QF3d77MMQIMsP8pYOHkYwa12VaTkG9FUsNvfup4PdbsF/kCfrEMc7xHdzWSSGr8PKoVYU0akRvYaGnkyg==","shasum":"122b5371445a4ac4c19f438b850b49c1bcea082d","tarball":"https://registry.npmjs.org/graph-state/-/graph-state-2.1.4.tgz","fileCount":22,"unpackedSize":228663,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgyG+qCRA9TVsSAnZWagAAodAP/RsCr6i4cShzLiZyB0xP\nX7D0S4U5cLdcbDGc1A4KnZZcOxjG+oB99nU8ncFgK3bHyWc2ZpCFJUk8dH6D\nrT5Rs9QmkScOP2yw2si4tYBKSRcU4QNC1lgySXhUi0lGDm4EmpQLfnzT5xeL\nsNv7yLHrtJgXvt52X0fRmSJNqhC0H9PxIRc5FGUsUD8z/RKwV6khjA7qagw5\n9oU475IkR6tWFgcGLpiKW3RLsbaZN8AmwuBaT2Qw+sMDAlEIRBQs+DcZZCBE\nEcaK3rBkHuGQlbrk1bAa5D0TkoF7qfpwE9dd/fD+P5DeD3iULU0SmyZ3mQcv\nJrNVcMiKtKXLlYoJeCE4N25CBF3bXTsB4Dv69hHxDNTFHNzAT1Tk1AtqdI4K\nIyc6Prms8OeNZXzPV4F3fuJoCWy6MeGnRxi/+jx5DqWMlQGaWWtH/q4w2D8t\nQ7TF+ZgopjknZw2inOTeVRQQS86ifbsCSIdfPG7q5rKVYpKDQ+8GTWncbufE\nCV2O8KiXmz5XGxE7MnAM3NA5ArcVWiHj+Uj295SGlocMenJ9WhqdLkzxInXm\nxTxtd2sIqBpfmJWpxfdUn8/t4Y4HX9adrjfPJMpXqhO0N1hvdF6fJrFR/Hxp\ncMsNLl+7R+Rekp6LSbfhE/4dwz5Xm2HblP+fzp+v5GNEO/2oEYutxF5MHej8\nM4cz\r\n=HO6X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCXJCvDKMKfSEhM7LdbF13ESy16JphERwvxUx9GsuJoJwIgNkO9M675nkCSjVeHVLQ9Sudu05h2/6hm4I/0uKPXrsA="}]},"_npmUser":{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"},"directories":{},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-state_2.1.4_1623748522120_0.6124782802423017"},"_hasShrinkwrap":false}},"time":{"created":"2020-10-09T13:46:53.867Z","0.1.0":"2020-10-09T13:46:54.023Z","modified":"2022-05-04T02:23:52.604Z","0.1.1":"2020-10-10T14:30:36.718Z","0.1.2":"2020-10-11T03:25:44.826Z","0.1.3":"2020-10-12T13:30:01.844Z","0.1.4":"2020-10-12T14:32:45.390Z","0.1.5":"2020-10-13T03:15:08.720Z","0.2.0":"2020-10-13T10:09:34.850Z","0.2.1":"2020-10-13T10:27:59.858Z","0.3.0":"2020-10-15T11:57:26.661Z","0.3.1":"2020-10-16T01:54:55.474Z","0.4.0":"2020-10-16T13:42:35.826Z","0.4.1":"2020-10-18T03:48:27.423Z","0.4.2":"2020-10-23T11:27:01.550Z","0.4.3":"2020-10-24T12:29:04.112Z","0.4.4":"2020-11-02T16:34:37.531Z","0.5.0":"2020-11-03T10:51:41.006Z","0.6.1":"2020-11-12T08:53:44.911Z","1.0.0":"2020-11-13T13:17:09.649Z","1.1.0":"2020-11-14T16:51:14.458Z","1.1.1":"2020-11-15T03:18:24.958Z","1.2.0":"2020-11-27T16:21:01.873Z","1.3.0":"2020-12-09T05:41:51.095Z","1.3.5-alpha.0":"2020-12-10T15:52:32.268Z","1.3.5-alpha.1":"2020-12-11T05:50:01.118Z","1.3.5-alpha.3":"2020-12-11T06:04:35.926Z","1.3.5-alpha.10":"2020-12-12T04:43:19.078Z","1.3.5-alpha.11":"2020-12-12T12:45:33.232Z","1.3.5-alpha.12":"2020-12-12T13:21:42.435Z","1.3.5-alpha.13":"2020-12-12T16:39:12.986Z","1.3.5-alpha.18":"2020-12-12T17:13:29.132Z","1.3.5-alpha.27":"2020-12-13T14:20:39.191Z","1.3.5-alpha.35":"2020-12-13T16:45:34.877Z","1.3.5-alpha.37":"2020-12-13T17:10:26.424Z","1.3.5-alpha.41":"2020-12-13T17:55:40.206Z","1.3.5-alpha.42":"2020-12-13T18:09:20.723Z","1.3.5-alpha.43":"2020-12-14T10:46:12.506Z","1.3.5-alpha.44":"2020-12-14T10:56:09.036Z","1.3.5-alpha.46":"2020-12-14T11:03:04.754Z","1.3.5-alpha.47":"2020-12-14T11:05:58.364Z","1.3.5-alpha.48":"2020-12-14T11:13:50.911Z","1.3.5-alpha.49":"2020-12-14T11:22:00.722Z","1.3.5-alpha.52":"2020-12-14T11:38:32.648Z","1.3.5-alpha.55":"2020-12-14T11:57:06.308Z","1.3.5-alpha.56":"2020-12-14T11:58:57.943Z","1.4.1":"2020-12-14T16:34:14.044Z","1.4.2-alpha.7":"2020-12-20T12:03:10.374Z","1.5.0":"2021-03-20T11:39:35.606Z","1.5.3-alpha.3":"2021-03-23T08:43:43.161Z","1.5.3-alpha.4":"2021-03-23T09:04:24.551Z","1.6.0":"2021-04-03T15:20:45.288Z","1.6.1":"2021-04-03T15:35:59.097Z","1.6.2-alpha.5":"2021-04-04T03:42:38.685Z","1.6.2-alpha.6":"2021-04-04T03:46:59.352Z","1.6.2-alpha.7":"2021-04-04T03:51:14.316Z","1.6.2-alpha.8":"2021-04-04T04:03:58.986Z","1.6.2-alpha.9":"2021-04-04T04:05:11.290Z","1.6.2-alpha.12":"2021-04-04T06:43:38.521Z","2.0.0":"2021-04-17T14:37:37.016Z","2.1.0":"2021-04-23T10:44:48.775Z","2.1.1":"2021-04-26T13:47:43.768Z","2.1.2":"2021-05-06T13:56:55.236Z","2.1.3":"2021-06-14T08:22:38.287Z","2.1.4":"2021-06-15T09:15:22.297Z"},"maintainers":[{"name":"lxsmnsyc","email":"alexis.munsayac@gmail.com"}],"description":"Digraph-based state management","license":"MIT","readme":"# graph-state\r\n\r\n> Digraph-based state management\r\n\r\n[![NPM](https://img.shields.io/npm/v/graph-state.svg)](https://www.npmjs.com/package/graph-state) [![JavaScript Style Guide](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript)\r\n\r\n## Install\r\n\r\n```bash\r\nyarn add graph-state\r\n```\r\n\r\n```bash\r\nnpm install graph-state\r\n```\r\n\r\n## Usage\r\n\r\n## Features\r\n\r\n### Think atomically\r\n\r\n`graph-state` motivates the use of granular stores, or we call them \"nodes\", that is, nodes that only store a single state.\r\n\r\n```tsx\r\nimport { node } from 'graph-state';\r\n\r\n// A simple graph node usage\r\nconst counter = node({\r\n  get: 0,\r\n});\r\n```\r\n\r\nNodes can have either a constant value as a default state, or provide a function that lazily computes the default state.\r\n\r\n```tsx\r\nconst randomState = node({\r\n  get: () => Math.random(),\r\n});\r\n```\r\n\r\n### Dependency graph states\r\n\r\n`graph-state` leverages the cumbersome process of connecting stores to communicate one another by seamlessly connecting them. A node's `get` propery receives an interface which can be used to read other node's state. Once a node reads another node's value, the read node becomes a \"dependency\": whenever the dependency node updates value, the dependent node recomputes it's state.\r\n\r\n```tsx\r\nconst greeting = node({\r\n  get: 'Hello',\r\n});\r\n\r\nconst person = node({\r\n  get: 'John Doe',\r\n});\r\n\r\nconst message = node({\r\n  get: ({ get }) => {\r\n    // Read the greeting and person nodes\r\n    const greetingValue = get(greeting);\r\n    const personValue = get(person);\r\n\r\n    // When greeting or person updates their state\r\n    // message re-runs its get function to create a new state.\r\n\r\n    // Return the derived state\r\n    return `${greetingValue}, ${personValue}.`;\r\n  },\r\n});\r\n```\r\n\r\nIt doesn't matter when `get` is called or how it is used:\r\n\r\n```tsx\r\nconst example = node({\r\n  get: ({ get } => {\r\n    const cond = get(A);\r\n\r\n    if (cond) {\r\n      return get(B); // If A is truthy, B becomes a dependency.\r\n    }\r\n    return get(C); // Otherwise, C becomes the dependency instead of B.\r\n  }),\r\n});\r\n```\r\n\r\nWhenever `get` is called, the dependency list is rebuilt, so the timing doesn't matter for a node to become a dependency.\r\n\r\n### Lazy Evaluation\r\n\r\nNodes, even though can be created on any level of context, does not evaluate until needed/used.\r\n\r\n```tsx\r\nconst example = node({\r\n  // This function does not run until\r\n  // example is read.\r\n  get: () => runExpensiveComputation(),\r\n});\r\n```\r\n\r\n### Keys\r\n\r\nNodes may accept a `key` field:\r\n\r\n```tsx\r\nconst example = node({\r\n  key: 'example',\r\n  get: 'Hello',\r\n});\r\n```\r\n\r\nIf another node of the same key is attempted to be created, the first instance is always reused.\r\n\r\nKeys you define are dev-only. Production environment will produce a unique id in place of the keys you provided.\r\n\r\n### Subscriptions\r\n\r\n`graph-state` allows managing subscriptions for side-effects. This is useful for subscribing to events (e.g. `addEventListener`), timers (`setTimeout`), etc.\r\n\r\n```tsx\r\nconst timer = node({\r\n  get: ({ subscription }) => {\r\n    subscription(() => {\r\n      const timeout = setTimeout(() => {\r\n        intervalLogic();\r\n      }, 1000);\r\n      return () => {\r\n        clearTimeout(timeout);\r\n      };\r\n    });\r\n  },\r\n});\r\n```\r\n\r\nSimilar to `get`, it doesn't matter when `subscription` is called. Every recomputation runs the cleanup function returned by `subscription`, and re-runs the callback.\r\n\r\n### Mutations\r\n\r\nThere are two kinds of state update in `graph-state`: `mutate` and `set`. `mutate` directly changes a node's state. `set`'s default behavior is similar to `mutate`, but if the node has a custom `set` function, the custom function is called instead of `mutate`. This is useful for building actions.\r\n\r\nBoth `get` and `set` received interfaces has functions that allow mutation.\r\n\r\n```tsx\r\n// A node that mutates itself.\r\nconst secondClock = node({\r\n  get: ({ mutateSelf, subscription }) => {\r\n    subscription(() => {\r\n      // an internal variable that tracks a state.\r\n      let count = 0;\r\n\r\n      // Subscribe to an interval timer\r\n      const timeout = setInterval(() => {\r\n        // Update our counter\r\n        count += 1;\r\n\r\n        // Perform self-mutation\r\n        mutateSelf(count);\r\n      }, 1000);\r\n\r\n      return () => {\r\n        clearInterval(timeout);\r\n      };\r\n    });\r\n\r\n    return 0;\r\n  },\r\n});\r\n```\r\n\r\n### Actions\r\n\r\nInspired by Redux and Flux architecture, nodes can have an action-receiving function called `set`, which overrides the state mutation of the node. The `set` function accepts the same interface as `get` (excluding `subscription`) and the action being received. In contrast with `get`, `set` does not react nor connect to read nodes.\r\n\r\nAn example of a graph node emulating a Redux store.\r\n\r\n```tsx\r\nconst counter = node({\r\n  get: 0,\r\n});\r\n\r\nconst reduce = (state, action) => {\r\n  switch (action.type) {\r\n    case 'INCREMENT':\r\n      return state + 1;\r\n    case 'DECREMENT':\r\n      return state - 1;\r\n    default:\r\n      return state;\r\n  }\r\n};\r\n\r\nconst reducer = node({\r\n  get: ({ get }) => get(counter),\r\n\r\n  set: ({ get, set }, action) => {\r\n    set(counter, reduce(get(counter), action));\r\n  },\r\n});\r\n```\r\n\r\n### Memoization\r\n\r\nNodes have their values memoized. Once a node attempts to update its state with an equivalent value, dependencies don't get notified with the new state, thus bailing out of recomputation. `node` accepts another optional field named `shouldUpdate` which is a function that receives the current state and the next state. By default, the states are compared with `Object.is`.\r\n\r\n### Concurrency\r\n\r\nNodes with asynchronous `get` or `set` may produce unwanted side-effects whenever both methods run immediately after one another. To fix this, nodes, internally, have built-in race conditions which allows further side-effects from occuring by preventing `set`, `mutate`, `setSelf`, `mutateSelf` and `subscription` from further evaluation.\r\n\r\n```tsx\r\nconst itemsList = node({\r\n  get: async () => {\r\n    const data = await db.query();\r\n    return data;\r\n  },\r\n});\r\n\r\nconst filteredItemsList = node({\r\n  get: async ({ get }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    return applyFilter(currentList);\r\n  },\r\n}); \r\n```\r\n\r\nNodes also accept a `resolve` method from interface which wraps a given Promise such that it will only resolve if the node has not yet recomputed.\r\n\r\n```tsx\r\nconst filteredItemsList = node({\r\n  get: async ({ get, resolve }) => {\r\n    // Read itemsList\r\n    const currentList = await get(itemsList);\r\n  \r\n    subscription(() => {\r\n      // This will not run if itemsList emits a new result immediately\r\n      // before the previous result resolves.\r\n      runListSideEffect(currentList);\r\n    });\r\n\r\n    // Prevent from resolving if recomputed\r\n    return resolve(applyFilter(currentList));\r\n  },\r\n}); \r\n```\r\n\r\nNodes that return a Promise may also be converted into an ADT node which emits the stateful representation of the Promise result by using `resource`. The resource node emits an object with the following fields:\r\n\r\n- `status`: The status of the Promise result. Begins with `\"pending\"`, and changes to either `\"success\"` or `\"failure\"`.\r\n- `data`: Value being represented by `status`.\r\n  - if `status === \"success\"`, `data` is the resolved value.\r\n  - if `status === \"failure\"`, `data` is the rejected value.\r\n  - if `status === \"pending\"`, `data` is the resolving Promise instance.\r\n\r\n```tsx\r\nconst listResource = resource(itemsList);\r\n\r\nconst example = node({\r\n  get: ({ get }) => {\r\n    const { status, data } = get(listResource);\r\n\r\n    // ...\r\n  },\r\n});\r\n```\r\n\r\nA valid resource node can be reverted back to a promise using `fromPromise`.\r\n\r\nMultiple resources can be concurrently handled using `waitForAll` or `waitForAny`, which correspondingly behaves similarly to `Promise.all` and `Promise.race`.\r\n\r\n```tsx\r\nconst [name, age, email] = get(waitForAll([\r\n  nameResource,\r\n  ageResource,\r\n  emailResource,\r\n]));\r\n```\r\n\r\n### Factory\r\n\r\nFor producing multiple nodes with the same core logic but varying values, we can use `factory`:\r\n\r\n```tsx\r\nconst nameFactory = factory({\r\n  // Similar to individual nodes except dynamic\r\n  key: (id) => `/profile/name/${id}`,\r\n  \r\n  get: (id) => () => readProfileName(id),\r\n});\r\n\r\n// ...\r\nconst name = get(nameFactory(id));\r\n```\r\n\r\n`factory` produces a function that passes the arguments provided to `key`, `get` and `set`.\r\n\r\n```tsx\r\nconst updateName = factory({\r\n  key: (id) => `/profile/name/${id}/update`,\r\n\r\n  set: (id, defaultName) => ({ set }, name) => {\r\n    set(nameFactory(id), name ?? defaultName);\r\n  },\r\n});\r\n\r\n//...\r\nset(updateName(id, 'John Doe'), newName);\r\n```\r\n\r\nIf a factory returns a Promise, this factory can be wrapped with `resourceFactory` to produce resource nodes.\r\n\r\n## License\r\n\r\nMIT © [lxsmnsyc](https://github.com/lxsmnsyc)\r\n","readmeFilename":"README.md","homepage":"https://github.com/lxsmnsyc/graph-state","repository":{"url":"git+https://github.com/lxsmnsyc/graph-state.git","type":"git"},"author":{"name":"Alexis Munsayac"},"bugs":{"url":"https://github.com/lxsmnsyc/graph-state/issues"},"keywords":["graph-state","graph","state","digraph","state management","reactive","recoil","atomic"]}