{"_id":"@synvox/core-client","_rev":"82-3f209a803b2dcd6bf307bc68fc42c411","name":"@synvox/core-client","dist-tags":{"latest":"2.4.0","next":"2.5.0-alpha.83"},"versions":{"1.0.0":{"name":"@synvox/core-client","version":"1.0.0","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"_id":"@synvox/core-client@1.0.0","_nodeVersion":"15.8.0","_npmVersion":"7.5.2","dist":{"integrity":"sha512-KaZiSmavSyXKxdmuIJKPG9BhW5pghdJv8JVIZDwhbk/aQr2bRwNVWVmpEE3AzaZRfDyZRfLY2W6iyu0amu+QWA==","shasum":"27edfa860381de792449ea7ec7e60c4e42ceadba","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-1.0.0.tgz","fileCount":39,"unpackedSize":388361,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaVAPCRA9TVsSAnZWagAAinAP/iVc8sXMBKtdVX3aww18\n1wLBIE1isRm48v7zbIYxTPuFOs2nzp15svMESwmjfuOaVSA8lcjece+0mwnR\nbLbwyDm2bml7/1Qf6xdLaGU7OqhpLxGRIO+2+4l0EzQ9ZDpHFEehZpLYx2oa\nyqsAgNt9e62YATQr82+8E++V5CAVVDgedYnlHKxg/zLJP1qzqpHfm9hh/OZT\nwosrEjMdmVoOf4unB7HUA4w4nyPlo1k3k4OOHs27JHO/17xDDl/jIKfNSY7D\n3kda93lD2VXywc4Oc6of9Zq+2EHldTniAy3ZTdkyQKARvdFr1utQou2AtlnC\nkn/2sX5iPyT3m11qskbS5sBIxNDeUo3cSqK4XGus7bqde4YNBy8zO+9VhWfS\nRKCY1r7dWi0detQH/gmgUPg6kv6qJts8xK4dv/b1nfM7vmSU8J2mLB+ILAls\nd5v7RKGTojZnrjJ5TM79IK+kXguUptzzL7YTEK5xMcYz7t1xh5OwcEEPneBZ\nA4UAxdctK8GEMBqZ2RJ1XJDkXzPxTvDJ4xwi0KhpDXSCULmv3sw5kBtGsP2/\nqpK6nnHDb1ecgSjqg955YBUei58rbC01U7OIOeWmk4gz8FJaGZEZQnDaaDgr\nBNZttiQULNp1nPlYNCmoL8LjqXbinWUwUqK2Dd3wB5dPSqZfUu6U8jWRrYq5\n7HBJ\r\n=ocET\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBrcIJ+nbMFf9vsjaTRiL9HQROzR61B6shdWDxYM83jOAiBsOSvJrx1qP8EhUkR8HMYQR9KzGMo/Ki90Ep/4PjY6Tw=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_1.0.0_1617514511055_0.17252298698485036"},"_hasShrinkwrap":false},"2.0.0-0":{"name":"@synvox/core-client","version":"2.0.0-0","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-0","_nodeVersion":"15.8.0","_npmVersion":"7.5.2","dist":{"integrity":"sha512-ZBK4qVvCh2OZ82rNMCo2+2HBVzSHXWUaX8uxjhZhpvwq3PbACgkLZye7M0s+QU4VHLqqC5v8Tum59wUA0gFpgw==","shasum":"73323eea1aa195e9d02b8173fcca8f6926e96349","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-0.tgz","fileCount":39,"unpackedSize":448053,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgapfPCRA9TVsSAnZWagAAlK0QAIQZmsRmgPXfTmHfXzl8\nEqgP87qe76uY7vRDckaIZx1v3Q8Diz4E0ib4gwAfPiYQ3okjVYIcMvC3z9Xh\n6cM6HeUteV9CFP6MkoArSCI9QTH/kzsP508MwaSGDkboZBQ7v21XJQzQLbKk\nJ03PmlNtc9QcjooW4Fk+ZXGR7FWz4IjeUsza45NcI4k1sYAz0xMNbGcD5m+k\n55qmPORX9UMA3jopcjltiAaDLI5w500AXORHpSDMymQsDGNJbn69MAEfW9ol\nJ7xul7cyl6q7k1ImgLNyJAsV+XP0F2Dd7xmyVcS76Y3HQQRYZvDqX0VgSgmG\npSLmjRnNx//zULP4dehQp2kHfo+GxGSHhYQ3QJ3qejnLbpIdDZAboJ7PG0eq\nEX0tK4KvTw3eLyfhV3pz8PPsgX8BbLcEt1yGgR8YVyJ061SvADCEnh3lQiRM\nqnIACnBRvU/eoYlGaGB+9U+twzC2r84sOUyyEELCkjY+sXYSe/AdGTdO2GJl\nVuedfTh/ok4eCQ+HR5ewh/H8TFbVu3lEEOWfjl+Crz5a4YCti8rgMBXLMltz\nJoQj174/aiyu1bAoiBJfneue+E1s2kEZXXNBolCFXeNzrxXw84eB0K5IVW22\ng6Rcu5ITtSonBGGilIhQZ/SpAmgXso4BBWb/n3ZjcRrIfIyYqdkMTnGP1RF6\n5oAZ\r\n=R7U7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCXM1XGDkQbUQDIAho1C0gyT5TR7V7A2eruKvad3tJk6wIhAMqJqSck+BlDRrnIZDntBhj6JOxTMm186Axjx7W4T7Bi"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-0_1617598414850_0.35218813093118295"},"_hasShrinkwrap":false},"2.0.0-1":{"name":"@synvox/core-client","version":"2.0.0-1","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-1","_nodeVersion":"15.8.0","_npmVersion":"7.5.2","dist":{"integrity":"sha512-gyaNaugQCFLJQkXPdKOYK97LeuSvL9aBvv4im04JCxoePAsbrkE39unc78TAIciSvr5A/Wp2BcQn1FSnvNQAOQ==","shasum":"422dc26a83989fcbcd00fd7f5f6e0b4c67378044","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-1.tgz","fileCount":39,"unpackedSize":459243,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJga7juCRA9TVsSAnZWagAASRkQAI0zWcEDPmTHTcUR+8Rx\nIdpnsnm6lzlUeP20YCS7Ax3+0sorACiGUGZ6ACWYvlD/sd/iDiiK/kSaNaB9\nXFdOI7v3x3zHJIpMP3cXg/F/02dcpFGHpfAHbZkVINTniZtOrwMo4eauT7Oz\nngT0MItOCpWPM/wB2ZFW1eQI6p9cil3R8AIVdrhYRVGCVZRr1kjPUFvd4rO6\nWBTIUdkWinAm05BD7xK0m8t1Y97qdwfD/G0r9iDmZuxEcSTi0AUkCyfwncJt\n45QUO0eBQMOHwMD39p+OMUnjPl64aLRClOR1MR2QKZWCrgPSz9tVaoyvKSrt\nODujACQ5EfHaHxqRo9jFmxLwUzAtu0Z2tRqFIW5m90XQwXVWX1qE37Lu9XPp\nr345WBp3XO0LFQZdS1JqrabTfWyeNQQez+rAhrhifWljd5597oVD1IxEUjoZ\n8WQVSY3NLp5UUXtGbStSisJ9OCilAVX9wa/FEwr28rNBzazPZ37bciuZcrcF\nu0j8dzHXk0f6u+dziaxysPC9vICazQeCnhSd8Vasq19nbYFxNWcesH0yCAhK\nyMPPX/c5/CNQwxLrytRJQFb4gEKApeqrxNhG40RVeWzzflAsZRJvW1iSB1g4\nFW5qemJBZC1sVZTs1I78rvUtZ8dIqHdOKVB1CLwsY64kfXF1pQVltZP9e1Xa\nuVs5\r\n=3ORt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCTNKyMmhTC7SSatCoUsZsZ1xHM/8scHIsWLYaGNnqKXQIgV+mtcNLDHAsRc00h8szJSz2jjFja7chCM13pZXByq0Q="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-1_1617672430095_0.6966308039045108"},"_hasShrinkwrap":false},"2.0.0-2":{"name":"@synvox/core-client","version":"2.0.0-2","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-2","_nodeVersion":"15.8.0","_npmVersion":"7.5.2","dist":{"integrity":"sha512-ZQT1CbH1RDof6qgssv+al7PNP64/mtlCJ2J80dVGbfn6lE7demzw+tZsQ+i/eRjcmPZRu2Ig066m20EdCjKiXw==","shasum":"535afa15a2a2cc5cbb53c5ffd915db81c98c9488","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-2.tgz","fileCount":39,"unpackedSize":459939,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJga7trCRA9TVsSAnZWagAATwMP/2T04+40tfxaHPdCvv9R\njuLMSq+tTfUq0whjJBz8BJgxlCi+6cUazBN5W932+sMBVFHnNYnHY6SK9O2L\nSoQP/FEdItB3Gc2rPZeVo535YDbRyyG5vI+iWgU+EvC/ifdH5j9vVXndrjJ7\n0BEg9/4Ie6yis0B3tI+v1ERMoz4zJsJ2O2ZbSLnwrMAieJ8xky7YVBge+HTI\nvUP8be+N4W+iHHtQ2ZCIQx7j1/+pmOhztThLwkgqzf2YXCueoM+JBiiTs6S+\n3X8XtTWq4X1JmyIPxztH+D0WPImW4BZC+nXXNc0jLBECXr8T/FCtJz0o4Gam\nHx9aXaIz4IhFGazAnz8RVjvDUy4Yfu1l/JxuW2hI6PlzeZhi4V6yI8MpjSA3\nVcBAK1ICUFvaCLCCV3L8gIkAqzggFbERH57ctTGOxjTVcCsv9MvsOuCL2N8/\nJEOJvkOMTsi6cjKxc8bHOcuLgKst6ECjmNf8qMWh24uyYKwpjB5BwgWO+v+q\nP0nmUVi0dNL1Z8Z8/uoxdJdNr8kgBeDzjAF/dqgJz02+yiwOaGURKVuyWsYY\n7Qjr39gbhUMIhBQNmbnN7ri8y8PmN9ujv+wtT+USKBsXCk8z2Ms/pmoCOvHQ\n84KQaJW4vfGesOCsuHZOgSZoXuWlM3z5tu3qnWJP6Stsl+4yqqjnjsx86T7r\nTC5m\r\n=ea8m\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIB+aGYgrLghKVbMP+rH5zwLhAK05ilQn5UfM/94hY9LzAiEA6SC26E7OGtfKnT2MFwy6FORhHngYnRGMdSimlq0xGWg="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-2_1617673066840_0.13060412074029348"},"_hasShrinkwrap":false},"2.0.0-3":{"name":"@synvox/core-client","version":"2.0.0-3","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-3","_nodeVersion":"15.8.0","_npmVersion":"7.5.2","dist":{"integrity":"sha512-Ky+Ly8Qq193BiCBYkE/VMnkwkp9lLDklNaISUWFhq3ZxTpCYXS2nOgK5Eecitda+VPtrlZtIRE+0ZqcdU0/bHA==","shasum":"8b49282d656bd7c8cb33b2183683152377bfd411","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-3.tgz","fileCount":39,"unpackedSize":463152,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJga+Q+CRA9TVsSAnZWagAA9DsP/3v+ogCVhW5l3/26Oy39\nUOyXSvm99Auqv3wlSgLF1Rg1tcl/+DZ8olaoje3FV/ybzDn25YqE63hMHGhg\nbXvBHHOVbJ6oJm633BlaD1lmXsmVnOWuELjD7/+3ricygn1GoL1vuizPjBPn\n7nVoS6E1xJnSEbqYcYLkPHwfKl/ocMp4GpQ7VCntsUTO3ZE95h1akztjlrrx\nLrxMSne6kKkFPKSXvdYd2JXubaaSmX6m36ew4NfNf6N2z8s/Lh+v4z6B0eWR\nu5PPEhosMqbbgQsZVRy28BFbNk1d6tRFnv1FVZrZCiIe/1mQwdNrrtPHRlLm\nXc1l1svO/SKW3umej6W56uBqDuwwigVRkvlknpNgC+1vdMtJrbmaPVqPdzGb\nqg1OTR+MtM9vBY6z2D5VTX17wWyhkHJryDrc2Z7vCHsNOXoxaemuvUs8p9uh\ntda8poPDjnBUqC9zQF7Qw0kiR3HKcxwrihtswGf5kQYcBywe0pz5IwZUxSTs\n3nnhozLWYfXpxAGly77bQnvUr3kn0b2x5P3XK+uVJEQOPLhTo1mfoSqG51R3\n9/2TvUMcn8/lZ+D2F8UBex//dIFNLwEPjwvpHVS/nHh/9UAbIA5Rh89ICd3X\nQoaz1GTcW7K1fMHJeO1oTgATQXsgY/NJ5ciirUva3kwCswQTp0oyfR1+IuW1\nodt4\r\n=mYg3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIE4yeIiWvw92uZhiC+J2D1mREMLZV0LmAyQ+i6xiKRl0AiAC1mVMDA/sXohQw3sHm1nFnH0Rq707cxXxlC7m/0MVdA=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-3_1617683518189_0.49341589411878983"},"_hasShrinkwrap":false},"2.0.0-4":{"name":"@synvox/core-client","version":"2.0.0-4","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-4","_nodeVersion":"15.8.0","_npmVersion":"7.5.2","dist":{"integrity":"sha512-qkTI5OE7hSDWWEQnqqLoLezNfsQtVNmUmRWo0xj3VQRryYiVNPbercKMKtEQlipAv3h6iDx/xWkbG/MJxXd1pg==","shasum":"ad17d065fbe41329a31a743690f0ce8f07c674ed","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-4.tgz","fileCount":39,"unpackedSize":462204,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJga+YYCRA9TVsSAnZWagAAOycQAIw33+nY/entoXaZsmTh\n7mIqUaxTTlvMKCCty0XNsjhHML2nEoCgLTFPIiNUpEePYGYkxeTIsJK/jUCG\nYhssLouz0ef8p/9P1sdRVjUibvcKuMkMmqZ7PzP9vIW5rQb9g7uEW2QH2Y5X\nH0BhttPFpXUML94i7Pb1ZphZrVPSCl8cM5JtUbD3pFpdcCNhpdpkoS48zhEn\nKjCGd0JcYr1f6WtfVS0arTrbsQncEZBo5qEUUzopirb8PDqI+srj4MzzXQhg\n6g5qfrFmBxOWYRjHqQ2ixmRRIWFYgLvHhZmLce85jinV2igCwP7wiSW9NJWX\n5OBDcHDk0sheMJ13m0VDoBZGFquN2duhUUGI2geyXjqgAXiTreC4LgQ8sMYn\nVv54LsAZC4exqu8MSfPu3Xi7JtIUdYKQR/e6g3au2TdLg15FBdQAejYE89lV\n9om5QPZctix2XjDs3k4ImoVN2Zgv2WUc52kkjnBXs0wd1VLReGkDrCtwBjPy\nzXPWHdo+sEQ1TtnT7p10zrEONjxsEoaSHhamAOLOI0PPeKAaA83ShPgObW0i\nqmNnHmpc1MKYGFimGP6mNpcW7WgwvrEFMjcJkgZDPxLefEwzI0IwN+vmt4h0\n/WJ+5cjSa1HoQscTMwQ2eI9G49bLpMuVqP5K8b+QEWqi8Hkv9y42YLjWzEdI\nduJs\r\n=+9Lt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA1iy8ptXsF+2pRyvvuwOuOJxhYziHFajD2I0SP0hRuFAiBcCtyrtu1+lS+ATIQFaadqgf+T/q+PHCMZOBXaTdjY7g=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-4_1617683991543_0.26526924433794896"},"_hasShrinkwrap":false},"2.0.0-5":{"name":"@synvox/core-client","version":"2.0.0-5","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-5","_nodeVersion":"15.8.0","_npmVersion":"7.5.2","dist":{"integrity":"sha512-pF+rgs8A3y2/APnckAcirXaBJACQQyJtMtCuQmgpTSuHmZ/JdnPJ3+1rgwnWOrYBAt80deNYLSCfmmQed9wZqw==","shasum":"4b9f86f6e61afddb1f3928ae899d5867470207ee","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-5.tgz","fileCount":39,"unpackedSize":462800,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJga+dXCRA9TVsSAnZWagAAY0IP/36wb7Z9S10NPcVgoCZy\nBOoByYj87tQeB1ZpwhlyQNXpQRAdpfG2TXRmx5YiIQU+wIlK26NoUDD+ysrW\nvN3/SsLdVVgByowm4HTUnHTHcX2JGl7ELbGLAbvcvsVfd1TB5W5dsS2xBELt\nA24yj4gcBQU+byYzsxWKdDVPlwMVT3owFL405PwC/A1xswlhWEfP4B7tecVq\nJaoPLS16Lk+E0ieAq92b7++kuT7ElzMY9YtdmgwYwP8xgj7pu7oX2snzJTad\na9fxFGQvIDyA3xeKhemEDIrg+zyO/kuIGJAGWHmMA9CkSFaaUXhNPTdTgJTt\nxPXHu6OhyMq/R6n4yAJaxN4tYpiBrVXXU5F/KF12/L8MeCgyZLq8j7ddhaSs\nk+DY/6CvYwAtluS71339oVlwDqrhhQmpjsn0FK2xSd2Gn/ezM0sSm1JGNPJ4\nKEflOEVi89E7HTdNyRk6i/L26jkPEEJ/SyIJVn64AXdSdFIM1ONNz5BHd/7S\nPEBcedg6E0LezeCSEQUoDd5qBEpZu+D0QV4rBNhxpVlPuJcM846BC7j0QWUK\nKyAudL/D7bgyEJarppuTx1Wsd4nXHZl1p2yyXYyjwUX3W0pW5yKUvxUp9axr\nbO7BL+rqul7UEalORaUEx28h9GUKl0SPSbfJIK5irdfWWdw44wLAgZ0YHnSY\nA3Bj\r\n=O7rh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICpw10qGsDXl2Zol6KEVbwYA/Ha7wQ15K+XOTq5ghBGEAiBRgqHTE8fhUppJlthfxN5raJa7+6/pRk5n/XDNYQ1tkg=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-5_1617684311538_0.3400191433019346"},"_hasShrinkwrap":false},"2.0.0-6":{"name":"@synvox/core-client","version":"2.0.0-6","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-6","_nodeVersion":"15.8.0","_npmVersion":"7.5.2","dist":{"integrity":"sha512-0gvedxX63tcHScG+XYBB6crYVLptbj7bHiOHQ44Yy7yIE+BlaFQneIrRpAQVbWVEwwSZsfXoR3K6TPtf0qjC4g==","shasum":"33d577f7c0885c183394d4066c5cec771eb54b38","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-6.tgz","fileCount":39,"unpackedSize":460204,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJga+uICRA9TVsSAnZWagAAARkP/Rkaui4jcwGaLR8f5SO3\n63FvZVlfoAzOS0gdeUaB4+sWtvdOUVY7PmivxjSUkbHX4GxAHcdHvErYOam4\nuw6O9nGeeUe+Wm+NuUe9qpJ6ZQSY1TJbQWwaRgzH8INZwAzi/zpQmUefwpYf\nFh3fogSL0nktFfrkJ3EZmYTtFGYZSYnZdZAHwN0m4EijCsb0SYoZJLC+yOs0\noV8IUnrzcEDe+l3boNilH3WFZgS4wUH/MZyN2LWk3BcqXm7JA7RdfGWT5Ue1\nDKPTfZchVoP6ohvWy/ynENGHnH49zDnWlbEJH0dx6frUWzmxFRZ/kUe2RO8p\nd4UwantYw1Cxf3sBsfHIXc0lzUtitNYLOsG7eq2V88Ay4MKDKuiVdtzxAqsI\njRfi49gP+7YHQMw8HErfzbygaLTLQK3yB37JqiNaSpUM+Fn2Crqu29zeFUOK\nvdZJlwwN0Kdhvw7tpspzAHA6zsVLOVElOJOxco+7+H8RapGsR5PLRvC4hd0i\nv3pgNoKB5wkuGyzWN9l7Owx+reSxXUhKIc8UX0p4NtgT7Qk/DTI5yND0YAoa\nBvoIw1jSUC1/bjZxcP+NJN80s7FLYkG/eopb714XHcyh90PZ+RS9kzUENj3W\nMK/E32Ht66ro5oNnFVEJ3J4c5/yhN6/YZ8rg4Csyyrkw5uNm464RyFSF/crZ\nqoiH\r\n=1Oh1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDIPZkMarw9VcoeNtxm4UFit7v8xsITDmwg6jpWQzGkgwIgNxHtF3PkP7GU14SkP/jvu+BXB1g0F21SnWzBJTNYNzA="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-6_1617685383781_0.8382787141153816"},"_hasShrinkwrap":false},"2.0.0-7":{"name":"@synvox/core-client","version":"2.0.0-7","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-7","_nodeVersion":"15.8.0","_npmVersion":"7.5.2","dist":{"integrity":"sha512-2Q1m5ODSeLY9RKPJbT1RbutRitm6Ckqfq1WpFzwFQ1Kgw9p1EZ/LgMr15wpqwYnQZ2NZOXWFccMWf2HEprgL2Q==","shasum":"2dfa765759a7b39f89b5bbafcef7d66530b3ca2e","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-7.tgz","fileCount":40,"unpackedSize":525569,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgbSphCRA9TVsSAnZWagAATmgP/0mVVBzzfeCJbu8rfC8z\ndgJLqywskzSbKJwaLnOCZOVT20vnf2/GW25dal4O7q8PtxgpOO5xAM7wiNib\n7HnTRsJq1abPmGzUXrLcMJYrVhORdiA0LoR1YHEjz5atLVKrzAFuYwIWl0dT\nqBx0mwCA9kayOIWLyGcaa0bt0AY/cw8p0fMICxK7cEipo1CEOFYXcnEHLJjN\ne3zzxuxxmAJ4IYJMqh2P/bNnIzQCRhSgEciLXvLW9t2zNwlrk/kkh2393eeq\n2CY5UqiH5tWmY03aPtku/H8znSr0oERmyoZKGNq7b0ryi2ovCeijeZMcRFBI\n6avwcA+zXLM7XUgBwyYYjnPImD/R4pQM3Mus106GNt6fVdftKOKGfeEy6uk0\npq8bYWmk0SKdYirftx6qcbwsQSaXfaB8xK1wQ+Tzful6lOQLjkbZR44Ly6eI\nu8vK2qByGB+5ZNUI47h622OofrgnzmV/b1GU847PlQoSbTaNwVEPXXAuEgFb\nGaO2zDs9L4EkmLjPsZju819sh4v8Ty1YPE+QkiECnFpTPU3Cfq96D3ANAtui\nD8tOfjOi/FTfYfOltdeBOhSUAxZXe6QdFvCbL3jHwM8fQGXo5dEN0ecuD2cd\nclX6JsYREekaP9ll1OEYI8ay1lv+iU+fJQXY9sFDT6toTOgde/+LJnHVlPoh\nGosW\r\n=+Q0L\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGSiSCV9KQd9SSb7e+8koqBj/1UaB+ZrvexzHU0qIyoqAiANG+2379+jY5VbQo/X7NmTVCXGEG/W3Po6XkqQXJhIKg=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-7_1617767009000_0.870659566710748"},"_hasShrinkwrap":false},"2.0.0-8":{"name":"@synvox/core-client","version":"2.0.0-8","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-8","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-z2rMcUW4y6Nbag/gqZOSEZl11WVJb3guL+2YSg5EzWNaLsmVYlgM/8XQjgI3i2OQzLh5T8KhsG8u3KxTHOJbjg==","shasum":"eda04995a045a1ee4e89f20f6ee0cb9084836a94","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-8.tgz","fileCount":40,"unpackedSize":528491,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgb9SCCRA9TVsSAnZWagAAnkEP/AkArRgYbSSQlZA1fXRG\nvGsg/eM9pgUS62oXgiSPGCSOc9KM698FRfMIL7H01coz4wruQLC+yuUXdqkc\nhYw6RwXZCPO3nqowtIjZrYMEZlzyoqRcon3S4YSdRRZOOrJ5Nz227o1ui1l/\nKAYkcZwOkw8ZWlwfroIEKVkCddvwQEQSHsKsB/75RXbd8Rf0KSAOgryeG4OI\nlbfJpACzcYgkyF4Kz5xu+OonkhMFL/JSbML61j4AZmOXsYecgLgweZsX/Eq9\neVU2nQzcbOF2ktlIWNa/cr+fLT7Nd5qSzPNsDV+4J4h/rK6scFGfNtwzT14y\nUZDDrY8dNW3afSc3mnnELeuF5yvin7F5Xyl8eMKbkNKm5ZDGEnwX5JFA/4cs\neO8aiXEmBhDQmfvgYMouMqfJoQ5iYA4qvOCNkS6hzk82QUaMas8pnUxlh1lQ\nYcMgkkcIcdjXyoFzLYSBzfCSq4lS9ZgasrDt/2gXIMY2r237ECrcQ9FmOMPh\nv183NWCV6r0aHiOpKsml7S10InkM/4F4nbEXk77Vebf0trFOSaOCtM/6HMVp\ncyiTqfxqYfzGIMDQBPWXJ3iI7CupNAz88JzBmXWwX48DI8mlLZOZbY4WSFJC\nmmaRNXG0U/57uoKIyV3uf9ZO6eiZOPEqLEKVMLyhKu+utmM+qlO01iBzsK/X\nFrsz\r\n=fGNi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCvnGMIrOtw50n6CLQ/+AVUBjUV2N3U9A4JiRgqk54F6gIgJPc+glT3hUzypIe6b+3nksRu2Nj+tCE24oL9xKOK65o="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-8_1617941633830_0.651517149688341"},"_hasShrinkwrap":false},"2.0.0-9":{"name":"@synvox/core-client","version":"2.0.0-9","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-9","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-KDmJH1njOMNXsdQSveeCB341XTGvqZHlXUZ6sstEMBjrhEI+I8HkpGhNCVO+HzKxuJgoBmVP2/n0eIJiaWEEww==","shasum":"926bdb46a59f32ca3c4d0b356839235d828be6b2","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-9.tgz","fileCount":40,"unpackedSize":530458,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgb9mQCRA9TVsSAnZWagAADP8P/jsxwoFPwttyRcrLqEb4\nK+aJwN5jgc0DJRe+6YGbP/m/dljK/srVm1NfUnnCLzSkt3ZvlhF3CWy+w/x6\nRIneCTO53wXO5OYwCNyC+g4Fjh+ISzl1ujNHFHpMKHJGFsQ0qpYFB/733a5o\nCDQUfo4zACZyLE/Pz4HEiev1lFOwKkue/QO/PVKxOJLwchAa1KfT8H6Yzu9b\nBrjI98cp8njv5d5WYofsyhsubRrjPqQciGapXTa0rDfaW1x5wwqhbq4vMdhK\ngKbTGyGKpP6IwkCrGTFYMy/9K9YH0zWzEdef1vrtsVviSpb4lotr4sDstsuV\njZRAkbZBgQiKsxeuz5E8TU26L1800NR8tvgE/C20np5VUWn6g3AlnQvsSt5d\nObAm5OMJFgVPoCY+GFlJpWFcxi3vis66C4MXPZHydkYpp35+3E+WPU3ckYzs\nAl1q4x8CEojqqzhCZyXUILiA+EOQ5KXm2+H3KuI1X1XRf/pTVV6/r14YOAhb\nY2BU9UTpZy2R1W/Ux4hxLy1YYtnNk/patPS5rl9y4bUFVeywoZuxx2wzGu2Y\nCClP6WiHxUhTk+iCF1I3iItUn6g7sc/5yIY7vpL3sUBdDhPBXAsb2vQSN86C\nqlI0fb84WcqCyS4WA25r4m/BjVN0ix09Ep2nsq2p1KzjkCyD6aRJ2AJjJ3+s\n49M3\r\n=9SsS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCEf+FOt7e0cOlQOmHNkKTmankAdwPCiIMYA8deCXiQ9gIgd26KOnqqO7mrKxQrB2EFjMfY0z67eOFKeSjD51Ra6CM="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-9_1617942927668_0.3177101225721888"},"_hasShrinkwrap":false},"2.0.0-10":{"name":"@synvox/core-client","version":"2.0.0-10","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-10","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-kjUp0dyVYNTbgKWLFp44Ca0gkeNE9bNWRHvUaTHtWfJOmVSwKaWtaKFvhJ4EpiH40gL3GUHB82eFgluGcpSTVQ==","shasum":"0caed6a41aa8f12b126ce2c1801200fd770c5f62","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-10.tgz","fileCount":40,"unpackedSize":528317,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgb+W9CRA9TVsSAnZWagAA4UoP/RFbXFbLFmIGxnFOFyvI\nxBnbTPSPMenDQQ58jrVsr4E8XN7c8o7o+Iv4INOs1Bp2hTSWE9bQufKVhxCC\n9Cd4F3iJ15xy9rHw/KNwhsyy+Wzusow2dyAfvNtrly2KSRCRAwruzNE7mNql\n72ikQWGHANwKbWuq9tSUjSoDEQwsxKI/cRB5dlmfK1pntHRGeIILEB0dJcuF\nAXDpBKMkzpTmGpBUfYwKg9bhsbHvQfkEnPsRWgCYc3gtrx+mEkirHSotnUFf\nIzniUQMifdz+zgZVqOcYkvryydB6d7K/S5zMUV3PZbQseMOyhiIkgcQTdhUe\nVXIlo4L1rXU8cKzopTArBEGj+Wkq6KV1O5Wj/psL6Me07N8LARUPeIHOAm45\nC96wqCGH7uSRjDQ1PUl/3ZziulgrI0aDgimjcZUMAxRuMe3ma7S9GDLKozEd\nrVruejOPGy6/5Oq8n40KyDf3dA/J1dDwClVUDyBFXguYZH5Zf6wIIoD2KON6\nfHLFLjfbyfRTcvhjxMEAesGlN1+q+7MoHv2zcUjJZhCK1Jj4MRM1IlFdBAZs\n3n+N5vcGZLIqICG5BhdfHrsXQEKf5cV2Xhb68mGZNxEookAcyYSZkVCppDtc\nFyQT2EKliAnYY4V16YEsD2IaneJT6Q1WmZMTkBzwmhKmogkaIGb2sKJhMewh\nnrzF\r\n=6XNM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGhAB7xs/iffIjtTOxXOmdydDh1F+x0FZElcgXljGWQoAiB0dsRtTXATnoF5+kQVytLqiN4sh4ko3btM+gDOEyKbTw=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-10_1617946045097_0.7525862351178088"},"_hasShrinkwrap":false},"2.0.0-11":{"name":"@synvox/core-client","version":"2.0.0-11","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-11","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-+N+YGIg3gVxu9YdQNU3N99WiDBTDwCwtUlKY5pAN/qd1lnHIHiWR90iZMVI+2C3T7VT6KbgXlTWvhtTsyaZMJw==","shasum":"c19062419abd5aa4aed71fd445735c7bc5d82ed1","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-11.tgz","fileCount":40,"unpackedSize":532074,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgcjuQCRA9TVsSAnZWagAAdMgP/3zLvUo9X/MnwHy1JsJS\nIaYSpuNUyBK3NUTJNAvolItzc/flAnFHko2mQSrFotCpcxKdLxRir3hfaH0y\na8ZF92sX52M6Yn61BbgontL9UhMaYUSsK2LfxoVElvhMWobEsDwxrhLLKRv5\nVFZDJLHcn2kZCcFKP+SpKwyZi5Nu/tJVZVoxMQCuFOdjbfsTfN35Tn78ym6q\npBmrfp0FaCBtFFe27oQCo/nqm0GNLSnHWoBD6o6Qi7XrlIl+6JMdnLYoHfme\ndQjI/lKJzgUoL8ZIspgprJbIRtXH8OILwgzXOIn3wpQ/2QD7kqqCudV2OqUB\nUquQVJ1WRcFuf9B0RQeqDLqTMSLyISnVDD9muhdqZMFVDGsUE/sQPLjBiHyY\nmIlr23bNyOAcLzw8clPQBedOQCy/hSgxpyXERPEQsUtBleP6eH6NZuY03Akd\nvBdZScuUyrpg65uk0bNCqchfMiSoZn6yFx9dXBG/FSc1LwkXmkb4AiQsyVOL\nKMBAHj0vHRN3un0u8H71e/9IyX8+AQQIscLOJaFUZyfflI5wBU6/ahUBOHXx\nbBDzv6HJWGCuE7fXAC8ep6oXifMPy2N5+wACHcd6T3nVYDCE/V5FaLVibJCS\n+UBRNmp5XwRlhk/KXhP3yJ2kF4Mo7Aa5T7WD0vM6YcxSE88AO6Irwdshg8ji\nSsjq\r\n=RJMk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDF7XYBSJurvOINRxCJjfbx9PjzceuWHqeCOyUDhXMTnQIhAJxPxR5YAvl5M/dHqc2VhcfOc+gk0ZrSQhsOkW/644XU"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-11_1618099088217_0.17896938052054034"},"_hasShrinkwrap":false},"2.0.0-12":{"name":"@synvox/core-client","version":"2.0.0-12","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-12","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-ZL+CcxVGNDhkfMvQx/8d978S91/wvtNXOnTG3znNR6PMOJIXH46GgLxYndkYPv+mLGUXURpoRtZXWAtIgByttA==","shasum":"38dd8eceeee9cfb911f385b40987553f590429b6","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-12.tgz","fileCount":40,"unpackedSize":538775,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgcky+CRA9TVsSAnZWagAAYoYP/3CPrhDkCBCODU6U0GAB\npiL8hH8pWomHgIataZBCnQa/dS+L+omnq41qoAoMRmlZO73MEj7hC0wwDUvc\nDczqvN0YMPUEByWF6xY++NWKK8K1RX0PVEDWQchXy7BNewy9+baxbXamZUXg\nlI0znLirVVpbWoeBL2oAx2uDO8uc0RXVX9NsS83y2OErw6IUfg39LwJUlhIA\nmGzZO7C+EO6afVkKccAyY6u/cUwUuVxZ6Vrvri1p0tQL3wpqr01MRoDtt1l3\nUpcOR6mFGFWR6sLtP6jHC8jsPi6Jeu5cnKzasAuvQDwpH4xuyR7XWXD5Urlb\n+hIzqSZTJQH2tJge2zDdj3gb6nj1thbs1ZHmDJDGvwAXopwJygmPy+YUC+We\noLXVvi/WmSVFFougK3VW5UYCjSg1A2PYdboMYNe4+potohDe0VjVSso8UBJU\nHrfC50PtmW0+XgBJaKh8fmq9Wv4+BmODfb0TGVBgv+uZkz4cWUqbA6jOsTAt\nFr87iRLINIxeRSoipFZhAc0BJuRcMkujvxdBPNrRcuY5PRGI55zUqKTefFOs\nxcZr/EDAaqY9yNolQCf+NJCkT4T1Z4aG4YjQhMgC0y4nYklFBnxUIyh5Aq14\n4Rp7XN32VkIGeVOr5QXfPvOZ1z2+b/fNVyqTa9RtNZpuPdjIg8+N6VOADWIJ\nfkxW\r\n=X6WK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCwUJZ745mMXKZLloVM6Z3DuxliKBORBI9srtwRDGPpBgIgT+zOfht7X9pyBJL8NnLauNqWy48tX+zyo1tUOyvgjT4="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-12_1618103485949_0.3954638642867123"},"_hasShrinkwrap":false},"2.0.0-13":{"name":"@synvox/core-client","version":"2.0.0-13","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-13","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-haatG1JacKooDyZsjFR4A5DrczZo8TCCrMoJZJuDmAsKhCsQ6Hcy9iD1DlzeukUdLE0O55JHbwm49uaKAtN9HA==","shasum":"ce2fff9e34da5ecbe38ab608d411de78abad36e5","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-13.tgz","fileCount":41,"unpackedSize":544241,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgcnSRCRA9TVsSAnZWagAAdswQAJ5p1fOHDfYT+Jsp4WsP\n/zSF/Lt5SBQjjbfRM6KFN4uIHW4yXidnQHtFwb8ITdZatlp59BqKMpDLwstv\nli/kWV64ncVo9RiFFsgpHbzdp05gNqEXJULQBnceJ4w0H4QmR7QJ0yGsNmby\nKbgzued7VG3Xrephk23TE+bRT7FvomsRRKPYHMEuSU0tIpbRQH97jbSrrPbJ\nc/f1FFz3YTKSb5xGShtu+UhSgq1UIQ3uazhHZ3t2qYgnr9uXGCvedQCLAaaf\nbA4QDlhyIbyF5uebRSb6zpJlwVAE44PLKls9uRzQNmK01WxOunVfSTSQ7/hy\nJPi0YhW3eIpkqpC5e+TLH0ZYbwwkZKNcDgwPRnJofUnA6uiMvelQKKsjODI7\nO0IGuNNUVSaTPkWOmHPyN4VTrc4ymaBSuIv1MzMeqMXAHC1nYKPhakCVVlj2\nZ39Rf9Jq1j3kdkAty5BQ+o39xWAt8H3Cq0qBWp9HZGxLmeNm/ql43e4QCU7g\nWP9KaRURJCeBvODDZHyJR372C2b9mGfLfC10kHbbNQ9xt8nfmi2wXOPqPoAC\nyPBO4i23Enw2F24MJn928T/r0L5M2uOMrslOIVj660xCxi8VszN/U0lJdsta\nqqGN4Wts+rjPfs+4ONW3gCVpJ6bxEOyyzR2tF31CjeDFMA9np5KzpOLyZgbu\nudzy\r\n=4T2l\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF5ryY63dJZmEVjQOCrAGXB9HYZp618K4BQNmAHAmmBpAiANYab8koYkgv+0A+hdZL7FmovhhQI6W6MvlbxbxkT6Lg=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-13_1618113681347_0.9215375562281223"},"_hasShrinkwrap":false},"2.0.0-14":{"name":"@synvox/core-client","version":"2.0.0-14","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-14","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-tlMUzeGEOSf9YxnI8ZZxrmekgxgVmip2fzales9yTbVyBCKrrV5AkPdOOUDXAvsi3ShOPByrP5HrPpDTpLhd4A==","shasum":"a3d440baea8321f2dbd07bf43e597e8e69140e87","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-14.tgz","fileCount":41,"unpackedSize":552094,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgc0Y5CRA9TVsSAnZWagAAIo4P/jV6kFqRnoHXAOmhkfkY\nX7uLo3DBcNDchDjB8kbTNFJB7srXMhdBilfMjhTj7QzVZYGjgEXBFbnTNvjj\nsBfxiQ0S5NinHR8/epErNlNR5gCNfGa6+eBRPRuRl4fHL6mgMaJzF+6FNcTc\no0CMSXnY0+D6zVaTzuG5oBWLiZ2Y3PgP/EP0KsXe/yRTtscsFlzcY0I/Cb25\nqC2lVf10ynnl5vkRqzpnktuLb95jN3Eb/Uladqq4J69253DiwBKgUM86KlrB\n3UbYOPgHILQxQ5BFWNhpwInyJVjt1H56AqzQuF9QgtmtesyD1/HHg4bBV3vr\naRhicby+rI9Ak4ieMp9ZR561nMiIFxqPmSvjC/vYRzCKlY1bbojUfXtZ6zLg\npnq+Ladr3OZI3zxLSYqSSAvh8hEE8xP+G7UbNH/mty0KUpTd5EUz5C0G66XU\nX9p5PlOL7TNfW2EMTWWa2oVwx0RUjS8lEEx0XfX1uewBDLvGAnlet1+DL4ca\n9HUbhJRIgO0mBLdQWwo7w+dMM/+cE7PbhtlpKTDGwzSf4V4i7HUqRZqwIrUG\nx/LA6cEuOaKIESHgRINmVQeYv/a+tQeG9Gy1OpyrUJQh++/oUUdNtv7DyXzj\nbhAuaxiXBqaXONxwvApablPPvf6Qh1TimS64JmB7bFtF5UQGLnx8MoNtnkgB\njwQ2\r\n=MRAW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBwmEDeEb4VOTDv/EA6s0jKyAbEc0ckeR9tjNHfPCNiCAiEA5TBsTQxqyWVLIgcmDSknjOTtvAZPfAuCpaDjj+Eaa6Q="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-14_1618167352755_0.17903686420276466"},"_hasShrinkwrap":false},"2.0.0-15":{"name":"@synvox/core-client","version":"2.0.0-15","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-15","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-TfkaETnSYmczDR1cDWNdNb1hQQQFsxrVrjgY1EF1Y4RKnP3kXufvt/Lt/fLAQw+kYZn+AZZFd19SOxsorP232w==","shasum":"8d34046c637c8847b52efbc00a812e03a29443e1","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-15.tgz","fileCount":47,"unpackedSize":563494,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdRfCCRA9TVsSAnZWagAADKMQAJGk8r8urpMn8C1TfCiW\nqPoN8AwNqzCNDLH15J/MvNPAgsSDa+F81HubCtQ5eJurWy0tV/jwbF1TUNo7\n3jkqFgl5Dd2c0Apvf/nmG5CdH3ew+aOdVYKcGRzcNcPg24dnHe/Z3IyOXQix\nCehVidtksCM57dre8NEaayJDx1udrU+a3IQPvq0bOVWcEPw2pJ3ojgj68J4e\nLuzRNI40rqDM3ENyUTv6gG5ULfHaCxGw+KwTv1pIVzwsDgzCYITY7ttff5hn\nPaMJmow+5wppO3jMvAvSE16Vnormw/a0XTDWqx3sa0oyScBg+WwxYsW5bsu5\nwYuafS3QSqGm0dMxK/QAAPiggjcgpCKVIbGRULJs0QVAbTWPsdsVNDSFaj0n\nCEzz0vi0imNQRKpE4kFlsJj6OdCpoe1zfc1EDnu8nUlMfoAoso4ymO2jQgAg\nG++L+yI5yTSdgrw//Q+ZQ3PycLlWoh6aXKDFkDn1SlwWitiB6GqkM+7HMsIR\nAdFkzSj4JpKLomdEbPYcPAkPXr3GtEF9pL2rnITZCll6/HaryONgBEojxvuh\ntF2z1qanmQ7qZYfN/Lg5eEqHdSTB7b9heZYxFH9tlmvDmROUTPtZkQ8hn8Nc\na2dnCrrzEH5T1JY7LffCEc9KVrjqentpNb9FdZCNW2N0EzJXsbAvdmi199zn\n5tKm\r\n=Tkb9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIACiyELWKWd7ZORk58eb50DiYIJcRqgwAnaMJwv6gLgaAiAhrifCBYHjSl3pe16TuWy+KgX44X9GB07CXFvQXwZrDQ=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-15_1618286529979_0.6064487432614516"},"_hasShrinkwrap":false},"2.0.0-16":{"name":"@synvox/core-client","version":"2.0.0-16","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-16","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-7eFz3/hhTdvSxcD+2tflXW3cvea2ppcGccgwm04BBrZjmtpEgudGsB4IyR0FbufMiNWjXnSFTfEggIl7BNKKsA==","shasum":"04d4011053a2e5157433851f19d28c4f8dd254d1","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-16.tgz","fileCount":47,"unpackedSize":568094,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdiPnCRA9TVsSAnZWagAA83oP/Rzt3D4M0EZudPGaOa2w\nglalV6DI1jlNxX8f9fQGrC8WyeAFwZTo3jJ5qMKIl3epJ4JT/CcbFh9MgGWn\neN8+SnZAn3vk9AgjzlXYF4+TFKHSoOdrQtVqNWbt4YF4VPOut/Xa6fmop7F9\nRD2+tKxijhft3Qs0JcMOv6lqQ1NfMh9wResfzPWnKGSvoZIXl6yarzRm8Pcl\n7N3+u/y9GhQV9gYdOtjGGX+LUfp0ffjF7CAQs87yzVjUXYzCXJeP70HGUtXe\nlaYZV6fZGZTae+wq+8X5UOWzqPA0PqCOlG3n8euiM+2hPyVIyDYE4fOI4ykM\nZg3Ka4e1E6NJakdawy+kZIt8/WSQHOOPtC/RAR86G3TWdrtlNdbAdOyjWGQr\nlO4QghHZYwAEWlfMMCyjnkghuE4tXfasrxgnoewy4ZigQFTD8oG17T1CSnAx\nTOy1+8SumGmYNqTeGM3hxiIjIbdHP3bHbQ+Fker+Dh10H+IDSmUoEGM239ih\nxjUsvJAEtrWKHmmk4Mwh2uBvjc4ktxlSCNnbvKK+jJ+qpmoDTpqq7cPtc8Jg\n03KyKue2gSCsjjE/5G37MC9PfJzE2OhYoeN5MTFWTsAZHoTu2N/AZtHOQhQL\nGeDfOPzvhoAeQn8U8HRbU+ZkiL/hPVRVXxfROcfqNyMfPTXY/kR3uEdjq5pp\nt02U\r\n=46tU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDYlmiz7MeLSFp7mwgHl1TXuUxnptdIaBShvG76wDIwIwIhAKab3VWIbSmzjPntolSZJsFbnp1mHEiOsh1Rewd8Gmh5"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-16_1618355175528_0.23416148504494605"},"_hasShrinkwrap":false},"2.0.0-17":{"name":"@synvox/core-client","version":"2.0.0-17","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-17","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-zwgF5GtRQ1sfqx3923aiF89FgyCjAq3RUZeGjpmp1x3xbMyLX0GpIIoADzQiM1hNhtAaHzIWRs2SYM53gpiqnA==","shasum":"d54357c5d0503a924292a5b6fd27b5c2b8a89885","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-17.tgz","fileCount":47,"unpackedSize":570213,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdlx6CRA9TVsSAnZWagAAIJcP/0G5aGyEKs/Azdy0gOq+\nmw25s9buFWvZTDfirV1XJnE8PzbYMrNvxlq7GtVhrrO4t29doPycPQuE7M62\nQnowuugMeRvvnexKHHnk4Jkf1ssfg4fVOwxyqumZQ3L6grdIFYMoJFm7M5n0\nPotWXE7XRCbuBNlrl1xxwU7USDLvOdCtD+vMk9mZkwWt8liQt6m08HKACDra\nJmrNBJ5wUayBJYASMLetQB8K8A+7ONOvt7DWXv74AaqkC8OYbHqycB6PM0p3\n4X/PTIOFXjilIO92LwhkWapdEvppA3fX73J3Wu3K8RLCtX0V+NBx8BQMez/G\nBI3l8UanGu0j6UKNkjMYqIa0kllW9xYZCAigNcB2hCyNNEYK9BFK3p4zbMSs\nDYe8DeQwNYASKbpV/Elgk+e8MOsS726qCRIwFOEDC/D23fh/WBOcoUiunxcf\nfsxWvOSPbXN/gnt+TrDx68C5wESm9z4VZVhiek/ldtcFUNTqnhQBEq4S4HsN\nOxcM7F7BOQqnHrYw9S0bR+z+9ZhqEPMJ99JFS8/m3glU71b89Wd5xGtz50ou\nkfxfQAbTNS2sazWGcNz2TXHs0gXoVkqce/dnEomcpnCBvPXIEpT6kJTplJmg\nzLVbDPMLvdxdHVhziUzQqvxfGZF89X+pe/OW5hf6D8vKrg73wiN46lX5oiT7\n0Ka4\r\n=TPUN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICZRwsVvtzul/KQeDSu3jvw9UGrnJlEjGOzCX7tdE46tAiBM9r86XfDnWghpJ+Pn+u9H7GZwXwRPVmpOlYqVKQLp6Q=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-17_1618369658131_0.00015286051240703813"},"_hasShrinkwrap":false},"2.0.0-18":{"name":"@synvox/core-client","version":"2.0.0-18","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-18","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-P0nrA9olBHLIVv66h077D6aToFinf7B7QhULnOE4mex2hipDbas8/wdl04H9RL6zpXZmk5GnOAGwvl9gw8sj3A==","shasum":"ec8fb76e63c25c2fbe6af90cc5845734f26d7137","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-18.tgz","fileCount":47,"unpackedSize":574606,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdmFdCRA9TVsSAnZWagAA53MP/1ALkYiyUjpF3KtHtBLK\nrG0i/xjSFstMlAKVXt9TwTELSsCUlQbkIrxZ6sFMun7z5ZMPlsRnQoA1QCh0\n6kGhLWczKg8rKO22Umk2O/fXdYFV4VtryQcCm63+xCIRXt8LPMSbUkw3Ujwi\n3f5rxmlQaPfhp6/20AfJKZVKXCL27zzhAJ4n81DEEOQxvMVAAdRJmCVajtBR\nNauLOSkdBhpyOtp8Aes2iBjvFTozxf1+XIVf42oZTFuepoCYY6KqfUIe2IR9\nOrm2dZlwwk0lyEFl/nGu/mAloWhsbImgoEJvRcYJVFvdOsHUbVKnWfHCq2qJ\necEMNSo4VXeTPmR7aPATjukExZF2+aNhDpYJy+KxbAlg6JMewB+0T3Cjz9dx\nL1GVgsaqrsxcLhJCrQIx3pqgdwtS4YzJ84Lm+weg1FlfMi4ZE1A3+KsRRXgy\nSIxtkIq25ULP90v2e7IQViu+OcJ+OuV4cjyporVdzjmX2MV3gvSYOKxCRGmf\neTrTg6JRNJ5or+bGe/SxKayMerwaqel3eGFeNa/ApZ9xvvhruRGotewuBAoA\nOSsx1Z0VaUKc9mHD5HJDZf733cBLmUSvIIPD0XJs9sV1uwGgL5T8am3D/iVV\neUNwa04bCqSBe+8Fhu3EsxVRUVt+bs5vHMY470jK030aD0n04RBF1XxYg1tN\n11d7\r\n=6ysr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFpFdg/opXVG1MffFVN+SPm81RJMwhaP9ebviUQpsrDkAiEAk9nwi7FjdrjjsIb8JNnmRTslBpI/el8g3PfMiprsJzA="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-18_1618370909015_0.4793790799248969"},"_hasShrinkwrap":false},"2.0.0-19":{"name":"@synvox/core-client","version":"2.0.0-19","description":"","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"ERROR: No README data found!","_id":"@synvox/core-client@2.0.0-19","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-m/JqSQ5dDAV7418nm1PUGy0B/O3VZH7BsSirRgdIMqd/b/1dVelMM2/NGZ8TwPjIVSxE/orOy8pHwdAYuCGTXA==","shasum":"a1ed1eba7c5ac5c348577a76baf5749ee8985f0f","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-19.tgz","fileCount":47,"unpackedSize":574918,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdnT0CRA9TVsSAnZWagAAxnQP/iaPtqAj9QRTwbuw/f5z\nmhZT2QYRnjGaNAzdhOA+E5C8Ge4o5/YbndV5CQDcLsGAkk+xF/2SzGMXgEKX\no4mVCbr1hFtm+P6o15k97dF5Xo3Tc9LX1FjmMpf/nGc317ZyuWaeJuhRdXkj\nlcKa7rq1S6WjIHBZKvLZJ6cZXiOW+vC0wmdRHAz71pnHmz6Y4ciBeD9sbgag\nxw6Dyw4ImUOQS0uSkV1VMgTlR2mrtF6mwyJTzsndfPalbdmz+ws3msffpi0/\n2aASh3dJw5X8kYuMHE771n5snhppnP8W4gTpKRUAAm5MOcY6l3sVz2ruMEli\nlYGgKTEydtQuXpr8Qn2j8em6WATDRSJqSi1RwXUa+G7Sh+KSTmBVvfmCkHbR\nszAHZtfnf30EedXA7t2Nc+k7ZAfM8iJXaRySxC/YGSXi53E5Sq08I8T+lW2o\nwT8gR9FzLC8HMM/Sy5/3qtxVONpMYBUYJ0zT9rE3lb06kD+cpmq5GP1zSxuV\ngTGnLVNrZuFsmkdARi3Hcmhpamf1DjjTq6K7raCqMPUhPlsDvlqfFrYId/mC\ndnb0LwkikojzYd+2RLdenkKp4LEZlXah6FMKuZJzj8t3T7x2eFUvwJ8S8xh/\n2mDW7IqQBaKAdwNmphBLFPXNt2Kl8rn3Z3500PF49FBCrO+v4qt6ZBhXmyDp\n2RBT\r\n=xZjS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDtrRfVS7CeV7aSTBrjPrrTsmtEWYqxQF5O6OhU9FJ94wIhAOFTSXNxcf+fQUwG2PSHxawxGNhs67vW2vuiJhQnoIGs"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-19_1618375923530_0.030618263210287155"},"_hasShrinkwrap":false},"2.0.0-20":{"name":"@synvox/core-client","version":"2.0.0-20","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","_id":"@synvox/core-client@2.0.0-20","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-krMKOVqm5ULYtV6iTtuDnkeiDlHdlkov79fOoCZ10veDqyeB+CTMDvb+MziiyfBD7gHo1sGQupOJoK0KZxH+dA==","shasum":"cd2325241d4c7354746d0eb1be89178b4fd9d6b3","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0-20.tgz","fileCount":51,"unpackedSize":586261,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgeNGvCRA9TVsSAnZWagAAeaEP/0K82FfIMXlLkTpCYR7k\nkyMu6bCxOKTFqOs4acljCIP49Bfo8RVAXC83pWeEkpjljQBgAoOqsIZMki4J\nPqhZklpoNYo+UjLqEEOwpK+yEfo/QywivpH4UqCwyj+YGiFFnFbgEbIUbF1z\ny3G/dSxMT6wFPkh7xIIYog5WuLmLaq+Asci99jScEWemSwvtquUePv+RXZQC\ntD5xBTc2V4jWw8cLiBFFHlme1yynCXqz5nYvNywvEYi2b7Wi1e6PJ1UvbOq9\nGWHEvPjpBkO24PWAxPxtsXSTMCe3ufvxby7hJ4T2MuIndMUmOdChYh9sNa/k\ndQPWHvoO4KUwT1KOnWIIixhAWvvycaA2dRT0DwKGuHFNpUzKAXsPJB+MLg5P\nuTsG/EJo3NptofdH/0d/nVGIbQw7HG8QIhI2iaIyq+gx1+ezJ4GbxRmlekq5\nBlORfOdg7H1sTP5biQbeWmJUa434APZey20M1aX8sep28AWago1BIGrgSH2J\n73yyYzGrR79dhw9OBtlARW+0vkllwFSFDWdUL2LDmCU713TFreRo11Jw2NUK\nMCoTtbsZ5WurCU4Kz0i4tVYcEawtpiwKkqZjauXJo6RAAWS7k6Ho53khhEid\n2B/USDaHbHJ0XTe49uwJcv9IM6bwMllK72oqzHKTkUmZDWv2wcotlFWn+Tbn\n0ddx\r\n=Ahrd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGLqrgPcZd8V0c96Q7scXuOkJVx/NX/j1XxDlY/JPYPqAiBymBM88aJgjNbkRjun+3xSfALMrwtps6I5pwQnUEbLUQ=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0-20_1618530734883_0.09411370551129794"},"_hasShrinkwrap":false},"2.0.0":{"name":"@synvox/core-client","version":"2.0.0","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"license":"ISC","devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"_id":"@synvox/core-client@2.0.0","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-qM88w4uodm8ghX8s/eYqk62mh0o99DPcHSdqR2aPD+l6vcW5NiEhA20K4FDnmIqEI8wMU6ClHqxwaokkSKS6ug==","shasum":"6e21757d3f469930ec9d783f21f555b44947aad7","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.0.0.tgz","fileCount":51,"unpackedSize":586258,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgeh4gCRA9TVsSAnZWagAAe44P/2Wg9RWTzI4c7JD+tA/1\n42NbYIp24dxvfR9bkPhrfDbJ6klFp4+YLLkjijFjC2Hx+0S7rKax34b+TWLE\npmwKTcRHGVMkX0GSfQVLUjFAG0uZahLy3GW2JHyZhGVIeLvg9ypp9x1wn8K0\nFfyoyClkTkvilEb2RCr7D7OA/5hAvPH2xb3y8dzXMXeafANJkV7HAkZmvMNb\nv3wUGdrJ9qJxr89tz1PuwvHXLWFEk59ivs6tJJIbAoi58M8f0TqL3KgbGN7W\nQdJYwgbXe+/Ju2HRj+2qq0MqEgaxKsFaF4bddsRWDGU24mHzX0qzn1kZfZD8\n/JNMJlyuyIqQR8BY/c4BLbwVQNK8iwzosYtcecPcS3aK/3BfRWDV3bWyM1qA\nzOkgqND1IQks+Mtwf3cugxGjkqpiweMnJpToLTK3LC1fjWpnvzC+W5q1x9KG\nM+yvDWDyvBBofGe5ZoV+dWD65cTdUwnKb6P+ggZXmR9VHOc89mYvZmSrW498\n0mM0QfCR+YzoRHz83KrMxzBSjloMgM49Bd1liZGXQYSum1EfJXvGDnjRSewc\nXWjsPVfU6L90ktN8hKfmR9yRWVw6pfrbGd8xNKdUQ9sb+zn/HTYvH7k/8V7X\nHRcLGB1gNBF6v+2XODg7lWSmwu7v0MD3PrGwhJhCPvMcdyPlMJKceuTmTl2s\nz0bO\r\n=gjgH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEYwwG9ddiwyjhDDJgIhqqe5iTandMs16eJe8/rmFcLJAiEA9DnwhqDN1EdtRGTi0La0g+u8qD2ywnVW9X+n4738pBA="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.0.0_1618615840063_0.2165930375532712"},"_hasShrinkwrap":false},"2.1.0":{"name":"@synvox/core-client","version":"2.1.0","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"devDependencies":{"@testing-library/react":"^11.2.6","@testing-library/react-hooks":"^5.1.1","@types/express":"^4.17.11","@types/jest":"^26.0.22","@types/node":"^14.14.37","@types/qs":"^6.9.6","@types/react":"^17.0.3","@types/test-listen":"^1.1.0","axios":"^0.21.1","events":"^3.3.0","express":"^4.17.1","jest":"^26.6.3","knex":"^0.95.4","microbundle":"^0.13.0","pg":"^8.5.1","prettier":"^2.2.1","react":"^17.0.2","react-dom":"^17.0.2","test-listen":"^1.1.0","ts-jest":"^26.5.4","tslib":"^2.1.0","typescript":"^4.2.3"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.1.0","_nodeVersion":"15.13.0","_npmVersion":"7.7.6","dist":{"integrity":"sha512-+jzCOnG5ZrPK+v0VHeb2XoL2pqdIyOxQ1FcnhwoMPbEGJT3WDCm8wUJKpFUYsCUpgjrIr+SJqwUi1a1e4YWs2A==","shasum":"67b2c972a3275e732cb23f83b469ccd035b8e2c8","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.1.0.tgz","fileCount":51,"unpackedSize":592547,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgf66cCRA9TVsSAnZWagAA4O8P/3tsjiV2DutqJ4ybDIPd\nYCEIumB3OVXFGzyLT81mkVU5c/TSZkMa0osV95ztVdPHzegyLVFofXGzkcf7\nWlxkUqIrsixhjDMtauuIgT0UbOsMycX11Du5eeI4jVyQfHHTYmnyPsGZlnR7\nFvG5PkgEOezZ9L9DWMq9EwIclqJWoERzFANO5FnVIa6dQS6LjT7vOR4MrJ9U\nJiLMJNiovuxuhUMeeg8rxkCiznXexXTQPkTih4yJ78jS86C5zqEfYEiDAWZE\nCNCoEXZ+9lgvqgjJtP48ieG8ouSn0J6SVx+TJ3Gxhuh4+VV7VH59Yw4dZC1b\nu0aL1+6CIIkYIy3+lqZYxjlmX5B/bBzx8beQtE4jHmPpcNgRPcc2IdFTe8Ph\nmZFt07ynQvF8yp96rthBRF+SMHHYCND7o4VWdtn41qZ5vev7LuujnPEEBhjH\n2zc/i3qz6RofWqoprd2KODfpvJ8z6L7cirqvJT7wL5DXlkquhO5BiCmc0NfJ\nl48QYuXxtVmLQWw9pmPtPDv0Est8nUqm6NTtbb6RP6VswatcRAZ6UiNjtt+1\nGiCFxDGg+QW4K/q35l2+fxqcvfrfcJqjVRfARyvhDPF2jOqK+NAYhWZd1ct3\naoYFs+5i50K6vE3BuerADWSD8bNdMjpKPIOu09CkhjADtREBsorcFzQZqDiT\nJoKN\r\n=X7gu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDmcR3v9/w7NaBAEfD9J/ywzL9q5nFkS6Dxgu1JHlVtDgIhANiBwd+piWUK+3MbwHbQBzb6Cug88Topayeh3giytBni"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.1.0_1618980508397_0.3589905884990119"},"_hasShrinkwrap":false},"2.3.1-alpha.0":{"name":"@synvox/core-client","version":"2.3.1-alpha.0","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"fb91879bac1fd2a6040d461ee07e1a9bc8d7521d","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.3.1-alpha.0","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-tpbkggPb54dC0/1VAMfccTbIeyzBmSgOFUnDrA6qDPCDjStS1YJazcQWjAt4MKzW+w5hp0N/boLOnXGIVpsMew==","shasum":"9e3d00f7d75f7d7c0f953fb8db7671e972e479c6","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.3.1-alpha.0.tgz","fileCount":52,"unpackedSize":596955,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgi4+KCRA9TVsSAnZWagAAO68P/jv3vqBC/tBi9VRn0MwL\nFQq08nLkqwt//aTtHZKidR5OrhM45TFWcHkHl8ojU/m3eBPh18GLtIkGYDis\nxt8sJOmoY9Ms8bpauGDpO4hXYFTFFmT89Idc8tWlE+9Ata53cLMuIfk4lRaF\nQjAoawiVEy9cH+SFU4oPnqHHbWNzExqH8/jRmSbZZLipq/Ihh45Kq0d0LvPh\nbNBPlV/gS9UdTiyzdfOMqIyBYUmi/Fpek6jUl12P3ZB73hixbdgQEFim32zD\nSNnLD40QK0vlY/LviIErpSpF9rTWXB8oz/YCPPD1F7I+4A3goC18IT3shch9\n+RIr2Q6D6H48hKw9LHpEEK/qaAtYMwGR8o0YNMNiGI7/5LjNXSqViX4p6cUn\nXw1ESrDi/IDdBlrvoQnlpzXzNNI2giHfBFebVehirC8Duew/8GTWi8Y2/Xvs\n9Lvsgs8LtF7KKTFNgyt5I/qbJTHTiMCKiGaFPYIyGqu3D5s4d58KFTsHqzW1\nr8xKxdFeQLcDAfoqG55DD7P2lzdCKvk/ZAT3u04moSviV2+nIwLizb9PO0eN\nKPHXmhM6De/oZi39+DsEPA/+lj5OXcPmF5Gk25a6rIFjh/VJxjg1g6cB9OGH\nWT3pNQ8p3k30Qm/AAUAdYqepUXc40AfO5J+utJQahDzdFzsQ87QdKV6W8bxc\nsuro\r\n=o0Dd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDkvO1H40LktfyCX0tpdIPMTSIZzwWQrr3fxYrlWnmw8wIhAPXLU0XQCeZYZHhZiUD5Il4KVO6aQg2ZQ3TsnL54D8Xd"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.3.1-alpha.0_1619758985935_0.9355575909715603"},"_hasShrinkwrap":false},"2.3.1-alpha.1":{"name":"@synvox/core-client","version":"2.3.1-alpha.1","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"4d85d41ce666e5b8aa557f67193580be4d2f9d6f","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.3.1-alpha.1","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-rro9nsjCvVHmwwm0aOpDKHOOJBfJa62kQvngiGxr+wt8xsUVQJkbTiDDJYabciiBbF/OQ6h32A3oujcy0r86Wg==","shasum":"c2fe792d72087c658fe182eafe155934bd35d322","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.3.1-alpha.1.tgz","fileCount":52,"unpackedSize":596955,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjMTtCRA9TVsSAnZWagAAWhgP/01q+0U5CKXVttMTVH1o\nD7G1in1SWfdPy1vGVrPZBadGVV3C4Kci23E0H/eRzpnAjjzHOLmHxRNU1WLk\ntZmetvFdfsJHYX0RW1ptc/zHbImwo8wCDnXMAy9gIvoaaRe5r/afaVK7+NZF\nZiFH/mJfJQKpXBDJY6PmOucHwXsvK4Trja7Z0Y3+wCwCXp8CiZ1uf9FGZdWF\nzxwSXHxzf7Ke7+bJq0/32vRyy9m+zUhy2cPpr/7c0ntHLGZI7VrVMHSTKJQS\n8eQRwfWEHP4A8Q6OUJHm8+1fPsUhkbNg11TIKUjfJDqxyfmllZtclVV/4W29\nWDU6HCoTBo2Lw0uQZp3kr2wW0+6an0jTQkNjulreKQLd0G8mGA7AXaSRKmk8\nnp+X+GThXHaHOs1hZrGtdbRLuj8I44cEilKcwzNSZdigH5HzJzQWtLpJmusp\nwDytmDCkGTbBHR12NMWFPW9ra4w9c0bVoYTri7VNdWJ8u8B1YxFd/FRt27CT\nto7rJWqv3A364X3wGaHpU23foZAuUsMDu+5BEEpAawi+q5Izh80O1xTe/Q6h\nI6BoeajH1NSl+rHwmhDKuEZaickz0zKo+YL5mCrZwTPiMRYs7MXhXCmUzCND\nw0DvqcbSGshLCXgum8KqyVJE6ECcQwzAH5hZdFkWUFivBOdul9vC7FTSDnU3\nOScU\r\n=uI+g\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFbZhvjDnK7qQwKjXBahD5zojEiK6kz0o3UKrSHkNQSxAiAwosYTC8W/Z21/3Rh8k5/n36JUHAcjcJC70magePnxaA=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.3.1-alpha.1_1619838188536_0.6065135104624411"},"_hasShrinkwrap":false},"2.3.1-alpha.2":{"name":"@synvox/core-client","version":"2.3.1-alpha.2","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"adc74bca51eecc341d2b3060ab252db2fb533465","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.3.1-alpha.2","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-VuFk3yKNRsUfSj+KdwoMFMTBq7DG+1HRrvaZy+WyQaL/4XE4jtjC0Mbr3RG40b3PjSnmm1SfVyTgcGz/n1dWoQ==","shasum":"d28f318fd638947b231f2b1ac69a8ce6502e8e14","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.3.1-alpha.2.tgz","fileCount":52,"unpackedSize":596955,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjMfMCRA9TVsSAnZWagAA8x8P/iXj1BSyS7xB4D7fvws/\nlA4K0xVG2wGWvxnXexdj+zIkUTb+HG7KzF8ho/Ht/rWXWHqvCjdhCkMfIflq\n04+L4BYgKcrAqzhAxQymf6PD2m+pJDPjpFJTPYcx4PjoSzAMTeRDWZ8jGMgI\nGEY+0BTIKFFYgATt97G0Ebl007Jo1xKQ6AXUGG8MGs79letT8PynGyZFrBat\nvCpoHEtilXxQl30F0bfPwsMtgREpVW0+T+Cy6jWso+Xtxtca7zEzuEw44fyy\n0xsk3+7D2QgR4XquwCAKu5fJk2n5+FOjVcT8K23CgbZN4QYyfiqf6hsReGo9\nkt34CfOALYku8ZvY8d0za2QNFo3nUyflbLWbwrJabXi+MTXeLUrb0DZVis7Z\nryH0l5EON7OS5+8l2PJQsFawU8Yl5M8gmx9tbzlD6BZqD76NMX2Z+28CtTau\nbomIOICwQcj+QObfwSP2I+oRO6rNmTHtAk3PjVe2CjUat6lkIYa6vqwpUG83\n/IFMSbQFjCwJZbeG0+8EUArZmg/EIPdnGn82Z0LlyQKkgFKPAUg5GcbCmFjA\nNEkDEmiVpVP5MdMtxoCZm5Srr5c3L9bbDCreqgFL6UWkG+8lqnwHH1y0xXR6\n8lM8bChegcfjYxiguEdvLgNw1i4PMbjYpooxjPMO9spYUkBX0KO0dkoHmCxO\nIrR3\r\n=rxT5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDGqlWQaxwmQPX0F1oToze8QpdXWKQxr6pYd5ujsUwWxQIgNHuS1fPPk9PJJk+jU1Ba+AZr+Oa4mE8WuMj4Qfyrrc8="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.3.1-alpha.2_1619838924131_0.10071755510203562"},"_hasShrinkwrap":false},"2.3.1-alpha.3":{"name":"@synvox/core-client","version":"2.3.1-alpha.3","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"84d05edd5f93c55caa2af59307397a0d30daa012","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.3.1-alpha.3","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-Ho4UG+YE0AP75KmrjvDXbpl7yan0Y4tMnMLCMIfNSnZhENTz2U8isrxlqZfwYstu2OJu3vd+2LQlbcmLTT+rKQ==","shasum":"c95ce479c55e7f6d3f2fcb8c53a6acee4ecd6ae5","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.3.1-alpha.3.tgz","fileCount":52,"unpackedSize":596955,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjY35CRA9TVsSAnZWagAAGjcP/0+UHuMQi/4ptuO0QmBG\naKAneauV+Dg5Ztx8nNI+6n8XoiSnhIfz+lg7eAiP6kcSMv25kZlvZNcwHRR1\n93m5bmeFBGEYSDn2/Ggu8w0Dz6/y8RIaqMR1+5tPmW3vSdoZLrTyQZwaBt4N\nT8GC8qEj2vUtt+mViQ7ss+XK2CZq5U5UCB4JVMJXeFWWaMmzoNFXbqgOcf1J\neF27bOHM0wlJcSvMoABJUlHkkQdzSK8xC6RXnORVPExLp0FISPytVgBpltvD\nD3mszny3cNlyUTjVIDkJXRAjG/LhBhGrt98NWZ9At0WSy+y67r9+BWr/nexU\nB0Ug8+S397gQf9ZbH9fTk+Av7NBRTOyUrqgJxa0Jg0vX9qr7LoNQFDlCvtTo\nucK2VAjmyWNvjbSFMkP6OfFTPzf7SAjT7e1QLFR93Knf7Ers2hmjjfO8YCJA\nk9opNV3lELBE2fVdlOTbnhJe2bTsD6SOfkCjnjkf3L1OONR5IvK36azBK5Zf\nF4VzVFJ3lGTwCET3S4vru7m5HltUmvdOLvC2+c+n7KCaHU3Plv9zvPlghwmE\nglhr4jU8BbQV3L6hXF/a2HO+OhmrFoe1WWCzgJcfa+seSiIP9+J+PCCg4So6\nbzu8TNScSluNPuOseYET/tvMNsJ1BtvE24tLKPLm5TaUGHF/LskKlJsvLUse\nLlFH\r\n=tOte\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHuD1J5bFmTRBkKjQkO6lTX9gNU4/OQjmvZLwYA7HM7wAiEAp5zey6gYnsQRFBk4H88CS7ioAm/N5MthBE/QZ34b8Bk="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.3.1-alpha.3_1619889656554_0.48964971381726197"},"_hasShrinkwrap":false},"2.3.1-alpha.4":{"name":"@synvox/core-client","version":"2.3.1-alpha.4","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"12bc2ec8ea003ca1c9ef1eea35a9121457f1a0d6","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.3.1-alpha.4","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-mSSkTw7lE1HdeA3yGybGzOZ9HF7rOUpM13SV93eDLQFr3Ij8wrusmPr3TQOy4bHex/R8pzEd2XTAwtcPDr1gAg==","shasum":"1504c57c84206d598e78f3edd4021a50e9f6fb99","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.3.1-alpha.4.tgz","fileCount":52,"unpackedSize":596955,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjbUOCRA9TVsSAnZWagAAIpoP/RYA5G5bgAw0ctSCmHun\nHYcFcVviBbdVnzO10Gd2qyaavaXCCSzcvL4EnMK8U1n65o5Z6fSIIWyd/hp6\nzkjdneKIqeK6VcAaxtgs0Ml5ldas72jOcS7BF1xBgLPyYvPtLysCvyO+fVN5\nDQ9lLSTHodjTSj1gyKTp7OTxOcS3RfOVgHPLle0wPtzaLZsxFqCF8HqSY2fS\nxPIqMcqw18/AvkcB5UtenX9eLe8nlmBzkINdxZt3rVO7fiLImZWyDrsSMm3B\nD3i8yR9fvY8vXU9m3D99uK7f1vTJ3AALcaxT32WunEEgrUsS88PstXEdd74a\nh0tb3mwQW64lr2klWrtwYkIiAd3pXmcD+hR5DQu423OpDyPs50p0OjckKZki\nhe2CVmSf/nTQrBxryEnvTNO4m0Kh0W+J2Kr9HUm3eqlJVUIBM8awjm8dGFo6\nH8uD86mMpV4klF1hUJ4a2H8mKSVCF53FiBKsVgSSMdoziiKkDPoN0AZOeXv+\n8e1iNsDfB1JZSBzVLDwNn8bkmhloC/FMB4szredMxZcXvgVoc/POhoCqab+Y\nZaLHlSrNvBA/UU0yiAErLibvN1taKQCgK3BR8AS4+bP0cw0k8moCpwW+Ng5u\nFuo7QQqtQ5LQ6RGdNF8v7fw0G+MtGycVKHb+4IyhHqc3ZUPVoWrpP/A73FAM\nOPDs\r\n=OQ+U\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICugX6GlAcoi4j2jjbWC1MvpFnGsiLVs16MW/r2UpZQnAiEAjLtdpxzZPWgmCtwxr26oetjeeGFs5ZUNR8dZDkFL+Vc="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.3.1-alpha.4_1619899661558_0.26463043743632286"},"_hasShrinkwrap":false},"2.3.1-alpha.5":{"name":"@synvox/core-client","version":"2.3.1-alpha.5","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"eaa2a5e4f353cfed8584faa7a04938b6e61e5e79","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.3.1-alpha.5","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-mlntSzX9yo8gcSi7zYzH4NgKkndrtyE5YOGrNb0er9JBVTXz19EV0hZNKin7HLSLrBp6EQJbwApyu53i8Z3MPw==","shasum":"2cb9a96226aa9a10b443a5175b2621f5d1249a9d","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.3.1-alpha.5.tgz","fileCount":52,"unpackedSize":597363,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjiwgCRA9TVsSAnZWagAALO4P/iPBfSZKDdAayWFFP3Tl\nIBqxNIOG2IqcbMDng0y7vnFQTu0/NQI6KyFOPlGmGPuNzCELFNw3qGjQNYtE\nw4qjsGZbn9/t9T1BuuLKTIB1rMyteQV9a8pwHmgY8Iw5damtvUzbNyhHRwUZ\nA6XqB+Pp+WXrZmTW3WPy7W20RJJSSQ7acArIjY/XMt2BNPytVgEy/QXlJk1f\nDeXe2aWtnfmjuywWfWCvdhTsh1ZenjuZmu7kQ+2wXYZGGoM0r3Jg+vfJRH08\n6Ko36GwLnU1+dzEjJR6fal7/0o4YhLUDjgUsTqRSXN0kkK/fWGT7qSGu+Djb\nGdEd1nXWLRY3Zd1VHsd05gzcW0adl58M+Qb9I8wCSKYueJ1j02aI7Ezof4Fa\nW8EVO7JI4IumN0tdvvxjKhoiQHAy9YnKiJ1x4XrnCgvE/kJo1ROXiUQV8STw\nErU26OJda3MGW8pazcg1Fvi9yZmEYzX3s2aKkcjnq9lIgPd6pJNIpqqHkxRf\nWP4HPPNulbWYWlgWfOU/YaRiCvCopdNCm4ibPoAh7LZk8Q+Y7/HYCpoEXEMG\nwA+DlOXDhWHb5ejSNcXFgticCXyOUaKqw6H5PSmUqs0hgp3PlFSXUYxZBXw3\n3yBQOOyp5VVVf3m1HrUv5Zys3mcZOPNpSWu12KfzKCCo5jM7WiQsbpIUkf9n\nus3j\r\n=K9so\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDNFWLtJt08dVzXpdw+G8q/m6Ie+gAFfquWcUf+TYy7wgIgTgVNgXsdODyX3DNruZOgaLd+kMf70oobLDax0dOFAgs="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.3.1-alpha.5_1619930143697_0.31907840479135197"},"_hasShrinkwrap":false},"2.3.1-alpha.6":{"name":"@synvox/core-client","version":"2.3.1-alpha.6","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"2ca148baf77d910eabb30c45b6e795023aa5b6bc","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.3.1-alpha.6","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-7/pf8g/EP1CSru0fhcaV2/6J0QD9Cda3nKK3O4yuA6XutM+DKn2kMX3jaE8BGpny/rd/lEzJFidQNndbKrCdjg==","shasum":"7dd4b04f814493b23ec230e5f7bafd79f62bd93e","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.3.1-alpha.6.tgz","fileCount":52,"unpackedSize":597363,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjuuqCRA9TVsSAnZWagAAgZEQAJJ5Xlejj0ObFJb+PzlF\nwLYvGqfPcxmLj/8AvxcRMiehtgr+w0tLuTm075Ft2I0QmGsb+QSb/GMcSlh6\novXQXJbwHHeA35H/uQ52Bz+Iu6+jUrkbit21PQ7zhX3Ks0acPNt4xzA1QB9S\nYlvbGLxmlTjuR8sWh7FFMkW12gQOSlMLQS+She/DjGbSgF2DK2sZACk4+DJm\n253018fAzonDxWI9JTT/dbZDJ3P/ugyF9GF+2AnIVMqkPlhvpmPm+7SB/6O1\nF/bgC0Zzg76AMn3OSsPAg01ULum3KdhmtoiJ6mXThZssNKaU55XaaIkzS+Vr\n4BU8YaeaKvY04a+rIDz/K3RQRZJvXE2vM5Nz+G2EcYnVWqFqhACfPFma8BRx\nJcY2nPwxbqa+OT6j7prb+plw3sp2/aQh4Tna72QTCrn6e851p4nULNhLMeIG\nkyv1IB0tBij5EdrWBUNwIECfmtSCzTceCIR/zg/npikusQJIFYCRwwWXsQ6q\nmuIh0onlBJQIqSaVXPYJuLi+Fqs443mKV+dXeOP3SiFb0BKmnJmke515mrqZ\nuK+kay+kdb5O3b7he4fV7Pb8TgiIPdbl60sqffrea7y1/FD0mExlIPvXRTtV\nEPSpgrtXhn9p2OCETSPeb6ygML7EHyBsfbAnheV0YO6QXKv37cNqHCf3YxHN\n8eGG\r\n=eamk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCR6871aZcc7j3kLWjr7dWS/ZeMKsNcwPIK6DEQQzUUoQIgJ31LwzS2g3WNf/fsqWtVizn4iwcM/lIfnxL89aQNrhI="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.3.1-alpha.6_1619979177640_0.06009839206476442"},"_hasShrinkwrap":false},"2.3.1-alpha.7":{"name":"@synvox/core-client","version":"2.3.1-alpha.7","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"1f8483707685313b0502434c918634d049341f17","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.3.1-alpha.7","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-NLHH9YI5Bbbs7kOxSoR6bZa6aYuFKVlVjoeS+F2MrH5yBq8IUZ3OEc1VI2H5lbpsKw3M+xSiVsFPsVJHhTAdSA==","shasum":"e24d60ff3d260ad1972bbde663ad5f306c749462","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.3.1-alpha.7.tgz","fileCount":52,"unpackedSize":586406,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgk1ppCRA9TVsSAnZWagAACmMP/1no6ZI6blZDwyDVf40F\n4xXfMyPjcr+EEC36LwQkR1TJi/orfeptzvvIEB3r0YEAqnZoH0CF0PXRrCBL\nBFrTbflr23btvtVQXNq8BU8aAPGdse3ReD8npfRElnCEg+FW0+Vsn5jSTU0d\nHzIqbBu23L5izUFOZcgvKJIvJ20VVUEsDxBpK5aGQvV+4Dy+lC0a6aKsZqsN\nVmEGMAe0Co+6DV282K9OQXs0b3VbOg9nsuLejwg+AMEbxp68orbmL0G+xsFU\n0aXQw44RIB3uErQxM+YoOYT35uBCqzaEbmLJxNrsp+MFCadFKZWIzRr+XDVV\npxiocrmVZ28EHAkUM/tMt3+It1fSmZMjv3QV07W9zC1C5gbrdsUzz5UgH7yc\n1OA42aANp59uNx9kF9HGWwtQLc1wssuq0yvBk2VjafSmQTFGW3KStf5VW56E\nW/9WZpNPzRXjfJ6eAyOeBBpBD8KZ9xkSvHy2XjvD+ZJDeHxiOzRuZA39uZT8\n5pDhignCvTxNxBJ6TOqoATYdX7zdUrfB9ebniORZCQtijxsCHP2Y0Wb1ZAmw\nt7qPM4lPOWaQPgAt89Rqv+Jsh+giukp1UmLeZ8zDJHzsbbGxnRSxr31/8m4A\nkT1mfszNIkxEC+7LjXxEL+0NBXac7EN9PeuTNwbU6xRvzstF3XZMHKmm+iTk\nNHO9\r\n=mc6J\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCwhtpJm+FXGNNoMsNuFbV23N5iowABziobI4QrEkA6ugIgUdVX2ZVfcpIyLRsJBkxu+cIXF+C0fUzYJ07JCF6IDpE="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.3.1-alpha.7_1620269673125_0.17859881625564866"},"_hasShrinkwrap":false},"2.3.1":{"name":"@synvox/core-client","version":"2.3.1","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"e5e3ec8f1a9d6b0145f73f364188f2f54c1e02de","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.3.1","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-czr/DyneWp1hHo85f1lxQfjdDaXvuF+8s+I5LX83xY1bFQjntr8KwO9GCqmfyfbH2iOc2d/mGEQcHabrt96yvQ==","shasum":"7dd1e263f6f63f1921d17b82c5ba74641600b8ae","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.3.1.tgz","fileCount":52,"unpackedSize":603311,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgoeWjCRA9TVsSAnZWagAAblIQAI3/HHHNatT+X7u9kDeG\ncxMGVQMBOo6QZZAYaHxUEZpbdtBtgeK3FoOXivOSIqd2HOMAPHGjdj8/H/F5\npecL2y9XFhlzCenHM68MpDyBTVeLVQo20DovvpfGEIrs9briF/nrayStXrrn\n23f+D1tF7wISoHZQi1xgV/UXBzKsf8BREp7Nrbefm6Blrwht0vJk9OHTmAn9\nd0E6wD1KZGUQVARrSN8p0pM7ZoTDRO17m4cTmjAsC1HFl2Rf1Da3RtmhJ7xp\nKzdITO5DV4oFJI9c9kwm4c+AaSolQSM59jLxPNEBQ3Vls9rsWxSAmvl4qSCs\n5yaM06VNlNRFRH+naeNIMwMGzNfgQyqyz17Gy/aA/pkWIrL+aupmJyXgRClB\nzF13g9S6vcfnh2tWrdLKtop8mUKxaPAzTCtNCVK6KK3HwkAoM8KoSsRe3Fp3\nu07vdOjx9FOCQLoLhJM880QDPCa1G/PtNhv0sIGqHe5yv+uUrYRykkXt6bZf\nkFWXqPNrrWc+vmN5p9AxYdGsNBnC2EkHYgvIs8iv/B7T4q9DINzCFcDx5a1V\nd3Tdph0HAbVekO3LZf+bckDdAVRJZJ9EHvfOFhXjh9dyrYs4dYXiuEGij7As\nkm7rLcbHmIZpzXgMM7PhJ8pTkj2yw/70wvC1x4GT2ECHfWnHfB65RqJs3J+g\nZf3I\r\n=pkks\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDBNPL+6lQ2rlkqrp2oWGVNTEiaELw9W3ljnZeuz7a3FAiBvMFXDow7i/+F68OAMdgW8FIsbTl1FLPSA52mYm4M3Rw=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.3.1_1621222818560_0.5562625417963478"},"_hasShrinkwrap":false},"2.3.2":{"name":"@synvox/core-client","version":"2.3.2","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"23519fad1ed6b28ece1cc197024fb206954fecdb","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.3.2","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-kODm2sOrFxn4DKsNSpVYrT3lXhHwD4QvPEfx16kVHApmn1g582/8pSlvUL6gakvQpr2L5bOra7bNSHIUNSs/yg==","shasum":"1c668437d0cc154840e259b2b54bcc56c155ea27","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.3.2.tgz","fileCount":52,"unpackedSize":591005,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgrcnGCRA9TVsSAnZWagAA7CsP/j0CA9fuHA6nQumYDgfy\nKI13pf9+QkgDHml9B0jvOHyxTF8imlssnqHVNYE1SHIBWPViq46pDfeLBCF6\nfoWnWdiI/Lxv7igRYjq2GmimMp8/CTYenN+/xcx++cOsmY9eevCoIiJvZ4Z4\n6txwSS5hF7kig7xQ/uAfxmGEghMvFKXSa1jHpRNUNcZ0B951yYlHmN++F7y6\nP9iMkSVuteJfwiZrmkSv++Y8kX56RSxxdVp9+x7RtVckF3lHwmltOnd+nFI1\n8Gw71CUUV9E9oIl7GTYjNfYTn7bVYvRv2R8Y/TK4UGV4x6JnAFPCNYRnzOfq\nccK1ME2PdyqjzSb5uwT1jA2kj6nEvCT2pZYoyh8gKdK0SDkA4PlcSFQ0F06N\noxzDWicDK147j4ldvkWnv3XOaxKyhuynNqPSOyWEgRoYQlqwqJXTxiUnsmJp\nI/DlDtenEKfe+ABuo/gPma2Iir09mMUDfqHRii2HuOovG+N4goQqHxh62MSl\nAqDX/kG5ve+Bv5Jg4D6IW0/9gy130L+VkRYRmFqLWSeHQZhfSQhEOnL/J3bQ\nCWIlSrKI9ARZEmsYq2J1c41Mq2UrV3XDPmyGVvHCQQr4W7vIjJgNtkALOQuv\n/uiQxniMwZdFV5/eUP+bKQ4/OXAKdYv7qEeVnJ2Tqda/YS8ipQcv+XMrolNr\nl3/H\r\n=Ahik\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDOeWO7ZpX735HDlBCOy4Ws0zxBZhovqAhKlLCFp/XpOgIgaEboA/sP1FOcHsy6aRqgbZFM2JLRokuKmePvy6O/l1Y="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.3.2_1622002118086_0.7237266710557615"},"_hasShrinkwrap":false},"2.4.0":{"name":"@synvox/core-client","version":"2.4.0","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"c0277ada4c1d84028e04efed1523a52475081b58","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.4.0","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-kMxFtH71ZvxMix4bYQf3qqU4/38ThWxLGp67dHVTDMmJp2lxvtcXKBcbtAgiIvYYHCL8FYhImDcB0UcbidITMg==","shasum":"480c963c0e9979e8658c192ecc757c58ad4f3aca","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.4.0.tgz","fileCount":52,"unpackedSize":513669,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgv8L1CRA9TVsSAnZWagAAQEIP/2cjGUIBjT1UGI9UueFy\nX3hZ4ielnR+BMREuTm1Kk97I+cyYS5kAa0OFa4+1S4nt2lcfko2zfTt0VltU\n7G1kdb5uZd/pG323+YL3bFxeMuh8WEFlM7PQHVIuj1viHfEj9qJDft8IPQG2\nat63TkaOqTNZ65vh8dYC6HAkm5gcvalVKVujR/abuwOq4iD7RtET5FR1wuV6\nibOrhoPqH+qJtAE0MGAtYlf3R6DY9rhlxLJA/6Xjk+3KbZf+wmKDJ5h/g0hh\nVZbEfaV9rVARNX1XJgOUFBfMkiPwchcO6sGyQ4hwvtWTbX3BOl+rTMOT/rYn\nZoGsurhp+C1UEwOT49aD38jrb3irCWQ8Gadg/cxZEi+BrAgdYYnaAE0Bfrea\nbv8/uevWxIEHHtF9TL2LSKqR/5FwNAOgEXRWUe+dBer1oEf0TZzVqPpSldTe\nyDj9JxR6DjYQRJzDesIIF1pJBHcw49NpFoqofcUFycEI94oBRVsSjDXvFThU\nOGFhHy4KH+RUH3fTewfh3Njk1dXez/bZDWw9vECNn4dlkOpcYnlxCET4y1zy\nXEik7D/1nt8QU7Q439Zqi329FMWvgirsuhGDlXXQ4JVP3QJQ0Vp78btXu550\nKoUs4KOns8/Bu4SuIi3h593xZo3RYZnsWkuY3ZblMkmicw5bIdIDWDEgDQdy\n7f2/\r\n=l9ku\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICC1Emr7vgcpULhjOks6D8WMaU7CwEBeU923OGAOVqROAiAhe6ubCp9dH4Ez+UcTPPMhHvvwQuXnuDLyZdWrb1WgNg=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.4.0_1623180021558_0.5428257706430146"},"_hasShrinkwrap":false},"2.5.0-alpha.0":{"name":"@synvox/core-client","version":"2.5.0-alpha.0","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"817d368ed937ea30832383e8c5e8424eb88ad6f5","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.0","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-xUm2p5MDtGqb4zphvSCe9RXgUY89YBXcxhxcmtUy2ZJcqMl8emG/x4RFMPfy2swB6hspqmVwHrs8aWAHXJ3+jA==","shasum":"e3c5a5dd1b5b5b8cc7692d3ee938cb8afc59520a","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.0.tgz","fileCount":44,"unpackedSize":432743,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgx/lMCRA9TVsSAnZWagAAR14QAIIQXcZMYsYNnklXXcE4\nMq+z/0z9PCj3rsj1p/Q+tIEyxtOq+A4XwiJJrN7s2hkaG3XZujFPLbQ5NmK1\n3kpbLtjy3tpCbZBJhXglZgelIL+UE+KlVqZm6KNbVYV0VFAzYN2onBrE9PUP\nA6mH+am0AlLFaHJzq/on4JFzg/YDwIKZw6zLvlnMis/wYIxdS/X80lp5vLKl\ngiiB5xKZPIM7jLF/sCTkNIw3P/TqhQaGBlJP94Sm93oZKz59V7ZC0YqNOug9\nFguV8JyS3dH7ZSf06k8DKyFo98/t6mYSXsEDWnigSWKI/lqRAG+IKs5aAg3+\nplKQYG0A2rcH4ueADZwhtB2B5QCgC+GPwtLHK7ZDXU+gMkGiBthh+FNTrsPo\nj9xktE46Ac5oE78+zEJhxCeJGzNxQGrBcA1fw7glqU1Qtvu5MWXe/x0aYPwF\np1rbtKcKts0ZBn7JpFd2SFZEEv0btRMwpGdexRnA1RRFTvYwsLwpfarSmM7s\nQRfA6w6KgmLr4iwcw2Qc3lMj1FxNtrbpdpQujxUqbj0IrZbDrTlurtRdZQ9/\nXxXuADlR7EJ3wGR8av67EdYkSyt4z4EbHfdzXvM9QCUm6Ij5sbpRSvT4QW8y\ngf1FsXE+r5XvJ6F0ZZGsDnRKfE09D+OYjW9sn8Zjwou6vBTQqXTZrb/vyzCn\nI+Fh\r\n=Bgys\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDfZdWWjZ6esYHQiBQZDB1qvFKQQricx0lG8zREk1pX2AiAlZV2AMgD2VZQLxCqFyaetD18zlxSMoiYGKCgwqKvgWw=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.0_1623718220272_0.2030564136039903"},"_hasShrinkwrap":false},"2.5.0-alpha.3":{"name":"@synvox/core-client","version":"2.5.0-alpha.3","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"7530c783d15c890d3167aed835b524a158402116","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.3","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-U76tA0fldVk4QIbFj2WWn20fCcVeepmHiYr6iYnyBOXTTXZ+iEP/DBzXf5YP4eRWJdSseAIHRqWChZHN83QxEw==","shasum":"b9b33a0f2c0f1cc9255fae9bbd03113f3140f6e7","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.3.tgz","fileCount":46,"unpackedSize":417361,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgysj8CRA9TVsSAnZWagAAbDkP/08sM7mF/rSsAHJKefMq\nqYoewp3TKFc6qFNxA3WBlm07+bJPIxxtX7PpkZYy2PfIS38mOiWP3An3r+Fz\n+DqUVH1bf9OByLuOXKQSOQX0zOIJt/48Yu9bsFH+WKZgq2qewd8oWKwzzIJK\nXYjAQ3J8YqvwDsjGJlwvb+6G8Eyoy5a42l5ZR7IlO1nBhD9BFWvejuMqMrh9\nLIs6PuFReZgHHe4zujeI2LiNNnDqVwLO6OJXSSJDdDQNRsk4Ou0tPV1n1n/+\ngPnmggzCUwuWZuHyYvBfX0CMFujmrzPR7WlzGCK8+w2UbQBKQIzAde6M65mu\nt3ueYbu0U/qdEWzaAfDqPSbF5aATvCSLIye21oYa/MKLrlDTM9RhTkC3Se+Y\nM28Ko3/vbZrKF6qYI25uULGu2eJg1a7A0wyr3N/VjdMF01tu97c963TU5Blb\nE9lM+S/CxEAjKLzj1bNU6rREDOrA/FwXgllaRIDQN1IaqpSSShuFdS57u1or\nve9emgB+2tNIjAwEq66h4+0ldKdlEQQEhrZqYBaleLK366hHMDja4FmRxryQ\nRnP/2n2JSOkpPVUu7rf4sTaLkhkqmmdjsqdzJgHqzOHuIpnnCxj8Fr6u64K1\nZX0gmtmmsUH7Z7HHpYfsrv5zNbaf3/CuH+JxgUIHyAKO80SfUoxoOxrSqerH\n2kB1\r\n=Rhs/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCk8uxkWTVX7Euc2/Rk2LLOX0NRTnuwTTh3eVwvx8oQVQIhAJsywws6goOak6VquVXdoxGkIZyoa9k1BCmuumODrYNi"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.3_1623902459560_0.8545633963543713"},"_hasShrinkwrap":false},"2.5.0-alpha.6":{"name":"@synvox/core-client","version":"2.5.0-alpha.6","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"2640027c370a356e31cab8b929770312250d68a8","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.6","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-9gveFG70XSdu+aoaVyK3cKkdRZ7BtFJhQJnXeyes6bOQOmcgYq2J/rf5H1XwBA5htvhEtAF/PSl1ZqYPzGMXpQ==","shasum":"963bd2111b33055b732dfdfaed49a5e0244209a1","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.6.tgz","fileCount":46,"unpackedSize":417382,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgzrdeCRA9TVsSAnZWagAAjCwP/RPcwzpdl7TSOgWy7ceU\neg4tRT2UYI7jVlP5vSusF7udZwUL8Z/nB6oV6xkU3SdxSRa3apSIn5WpSn4I\nxHc4gBjoJ2XClWFmccxDct4OGCOoLlDf2sHpomynP0sqb+tD/l1fYj4klPYr\ng/L6vTiUqw4u+uZYr3XSuoFXyVWG2Pi20/a2q05ULC4y9ndXWRBREjVEBlhP\nFYtI0AbQ/Cp0ahbO49C8Qj87a13pUZoqvHkA2fk/d3pRjXTuhd7alpbIHMgp\nrZF7kkFnKyYyBAeLTuwhljEUMV/BeDOZ/mzsF7lA16/LYWrmKof8e1NsyRY0\nGH9DMdylj4LWXjtCZC9pxipkFQO+Q1uBAIci1rsqtnJC5i9mMLhw5eDij8U9\n6XksXPM1HQ5MO8wr/ZQRMq4KiKryvZvhPsaRk5NSP/D1rS0kxIiugIFBQaNa\nLfhlcpH8iYI4Ymg0wIzsGZ0Uis4XiG7uFfJl8+fmPrHaX91M9ZIblCroD3Dc\nfHur1pi3EMJ8tFdNz8tIQViMg68UrBg86FP2EwtdM71sz1OIqHyWNh/MqunK\neJ8430TIXVrJ2gdgRb3sKVqd+kHl7zbtPEW+v8ZUHxZMf9ZWkC2eQee9MYFO\nuxaNPKMRqfSaROVblmf91nU6cPrmcoi5Bhv2DY8mf+UheYcjY7iIQsuFWlY/\nBWD+\r\n=sHpy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCiHXBPQaPPMMhVnWqgDhJhOdn2/vHr7bNRQEHjoKhzOgIhAJb9640zOpSO4EZwp4NME3/tyFY/f0Db6s8Kd/iVfjsW"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.6_1624160094133_0.6650260576005276"},"_hasShrinkwrap":false},"2.5.0-alpha.7":{"name":"@synvox/core-client","version":"2.5.0-alpha.7","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"99005cf4bf19a4a0c509e5d62c379be804ee7bc4","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.7","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-cHrOXqlM8AuncVEXtFBJWgdpGBEC/bLVxwEg0GfQMEFMRufbj6Qsyf743Kzw2uLXJeMv5zBrEO2a5GJg5FSAvw==","shasum":"f87c07b56a92cc7aed42c651ac632ec3bd080aed","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.7.tgz","fileCount":46,"unpackedSize":458038,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgz+iHCRA9TVsSAnZWagAApaAP/iT+qXKN7ThHi5l+uiod\nJUcK4fipKPsnhtcSJkU6YubSXZZ8Vfxqz3vyAvNZIax2HK5SOd/PcVEIdhSm\nAPSeqqO5X9Bats87hoSfH+GQl1aiMskPzR0P1MQOlKV6AlLQRC0miHqk3Rgz\nusMGGYg//aEVN8SB3JKa7L5GsuUlX4Q4W7PfanocgbzFBOxCTceAQ6Nccnhk\nfXHQAx4G38py8vcxSjrbnApxbDDwuCsbd5DaDzPmi1FQWh/77JPIO/6DkPZ+\nQNs04X8pnf5rRl1Q5Q97Zh/nP2l9hqfIR7WLltj1gBbkjUIhnROR43v6DG+R\nnO4S1mUcWs6sCuypb8ZzIC1tmqDd57iuzQ7iwbs2VqbYwiJepm4CRitXGDYs\nCI5ig0e60vTsod+NrF9bMEPs7zEsVCV9QSjEpztaXAtVhdEWjxLHmogpYCFh\nEkGc839M1bwUrK6iOB3WG6R6NVXw1+nkRegCB3mLk/cL+RPbsj8L6sgOnZmg\nfpZfUg8DH7PBFBYaTVUmZHEEI6M9K+cS7PGrXNa4SzzW9QE3UUh+37rwMFTr\ny2gCaUkVy+AQqdCfotinz2vhezFgM1xqzi/lEDXRebEBS5fjzzedKeUXgDFg\nnHm9guobvG1LAtoiuluc4VJc1dlB03OFLKoqfigSDQ6zb8fNScqE77eFQNF/\ndCU1\r\n=i5vt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBM2ljRkev2M3BRPRy8TiTjEZr/bWV6zK60hcyzNBlCkAiAb9ynn1edoEVCnNHZh5zYUjJGBCZTzmj2omlJiAR1t7g=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.7_1624238214946_0.8103407837620076"},"_hasShrinkwrap":false},"2.5.0-alpha.8":{"name":"@synvox/core-client","version":"2.5.0-alpha.8","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"5a3821810666f7d0b95384fe70a9ce26d902ceb0","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.8","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-4rSJMSeVfadY8mGzzvOb5BvGip1+yN/N2V7080BPvTtatI8O4HGPpKkNl6d2EEw/v6NPKzy1diYwEKzVzheIXA==","shasum":"9651e9d97d6f2299d45723bcca828dcb8dec8eba","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.8.tgz","fileCount":46,"unpackedSize":459524,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg01qECRA9TVsSAnZWagAAgCAP/2QJwa4/+VE9Zj7UR9rP\nf0/e2Z1JCY3ngjZI9DBe5QX1Y6zrN7GhiTpZkIjJxUbLO8YOIAaMky81E2aF\n409FJoNtdWGMauWGLXIXIswGZquGkJx5Ra34xVtFZOGtTWXEXrBoxxbT8FNk\n9HHu/OYbnz2irkyLUeeR2sXmtSzFa6Kq8SaA2c2WI38wOjc6Rg9zumgnc47d\nOPVznkmz0AtJj7NtgWb8cYhZGnGhB+IRfnrSFUaYaC2ysVvYeJJZhnxHcXhF\nmlks46apdAs1S+9Mrr0OOzwS6NURbK+WNvnc4XXTIameGIPbRPHskvi761kR\niP1/qxemCsIY5JHXRuLHaKVwrgvWpWmz3lV3o8weT8uIBg//cqgxlwsT3RsO\nZxH1FIE8xFdTZGUCbHOZvSq8AfQmR9OXCml6Ng/Z6QEB+ems8V+RoDzooB/H\npZS10ndHsOUn/s3EBDUPRJjVaQwFazU/axcyJ4Be4Hk04oVyxV+VZBnKAOAK\n2qp0In764HNrjX4yiOyR4m6lod3rNKO8tsncKB1ingA1zkhhHskJd44+Iyq3\nOEj5FSFXsdMDH4cU3emDOmdXGqqKlkejkHqhneLzs+A6fNtrP87g8PI1peJW\nfJV8Oy8QEiz7lgRt28WSvJJ42QlxmR+Ek2QQqnKUCVLkDqkvZROUSuUF+UxS\nG5iz\r\n=w6f+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAXWqzxuhA9hblp7GngINE2m2FE4hJ4ytOf2e+LJYtzqAiEArfYbQquVf1tyOFgGjWkBlcjfWZrS3SmEZWR9v52HvDE="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.8_1624464003642_0.9044998899854713"},"_hasShrinkwrap":false},"2.5.0-alpha.9":{"name":"@synvox/core-client","version":"2.5.0-alpha.9","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"9060d5ba5d2c4ae121c77bd8ef865f980a8a8e1e","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.9","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-zMxUaKDLTDkExn9zXSmLiz9h571rm66cCqC812O9zfpMB7kZ9kczlAxxd2kxcl0Ra8nJmaPnK1z2LM9I9tmUpA==","shasum":"d84a3045195c4601ffc53da82e170a4a82d3428d","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.9.tgz","fileCount":46,"unpackedSize":461971,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg02JmCRA9TVsSAnZWagAAwp0P/1NsDSTOyxC/n0yXOvaR\ndY+8sy3NNoQztxIaLrt5m0jdmeIpZ7eXbewQSnCQJLBW1DJ95erSwXXTQGq+\nK11U0KFGrNMmXAZbZ5urGEudR0gulezFHn6PwLHr2wJ6EntaOQsUp59xh66z\nm0YALdUFJRJp3qxvD1Zht+IqM6uc6EeVkvk1RdI/lNwa36MD1j0Fh9loIwO4\nG8rUJaJ52iZFb9HC5JJ06OvvMTomQl8UObxPSwm1uOYFWT07zlex141AMVuQ\ncNUCZsx9JjczZYCG1akyNVEW4Ob+33Oi2ioLEidtmPyxeJ0+MWjzj95z5xfe\nFqipWfrTXpmHI4mtL64KQI/8xjwKbdO6r3eoW9BxXn7PzTX7dU3yOVnJmZR9\nTFeZ7miaqF0Gbn6gFtmW/yYH/j1a+8YnK3AjhF3CrE24JOm+YJ6cHRk5EBTu\nD62x0HeIhd6kow5PkxQJ8Nmqq+VXBj9bIroTXbKN76ojl6VYNaVV1KXN9uNK\niWQFKXhLuM3gnhhGqan8oRJ9+CAisz5xz8EXRQOs8IDXPltRqh8Sxp1J3idz\naGHekFW3mOkE7PElJTmNKwEN1i2z1WNB+0DMCL69d6FHjSmiMP1gSYVhYanX\nW/AUp/jiKx6nRIu8uoT6CvS8qZYkL3f1lRDUt6gzf3i8/jGPqYUPfTPvWlcN\nWIlS\r\n=wRI3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGdz2udV0Ahwo68mMTud9WkLEUGHNStT4iT1lZHHMh4qAiBOFFkmahGSIiEpHuFCcRqU1rIZnDEaiAfNCbfQWUY4SQ=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.9_1624466021896_0.09206448973063552"},"_hasShrinkwrap":false},"2.5.0-alpha.14":{"name":"@synvox/core-client","version":"2.5.0-alpha.14","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"a3cd4e4f244cb187dbf680e16ecbb1b80c8bc92c","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.14","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-aBfPz75yGnYCydiO2aNNQ5Ci/hzuCsqX4JZtcZ2LbXXoXy4dPj/w+vzJHcV94o+qtuKK+flmXKaiQdBLaOdbjg==","shasum":"023b38226dfb3cce6d04b4ae4006ee4fbfd708ea","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.14.tgz","fileCount":46,"unpackedSize":473653,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg/ev5CRA9TVsSAnZWagAAYQAP/iojUmejHZXZgJA9kgVt\n3zZHGhapXxWgMy+LaoyAEPeO3J+wVsMsMBSC2pvmG/Cyw3pDZNha6HPmZH20\nLgZ4+VtrobaiOi6GHroJulTk1yBXao71aOQk5nwPbKNyYJu9pKCDEbH9Grgn\nWF3nwb8idG4e9fv4Npg0kKySaZSNAe6A4SIPUjJldkFzqKe/6ZZ6hyI6GQIs\n4eqfKPtshJmUA1RMzv4efzfbfdrE0cRPDwN2WjDIPfZ67ZvrEXq0P3YvFKjR\n4rbsjT9r6p5usfFoLWqbh/kPW5L5vW7xfg0R/owlUCh0A1rKiU7IeCFgvoD1\nUiH3UAuge1uDXh037x2VY08aGNk2R/cQx8QFBLWossFjRG4SdiMXybTWscCT\nR1h8qVfX58AZ8K1g0/v+MBihJDZVgFSVALy7IOi+f+GALWQv58USc/aE2xFq\nX5h2+fxpsVpPcjnaPltNK0bjxi/jAgN2cZ1Xqi98pBLOOqetR/p/Q3ZT61F0\nlFNODZsHQhUgEd55wowZMOosvfbPn5T0crCHxSYwyT94FbgPPWflQBEA7xJP\n2Rtydsybo50ilBN273l61kbLIcRxB1z8/jFDe9WErNyNrfNDrvHDz87bNB7k\nh7HFaM2rrs64G/Ce0xTye0qv3TtLj9HVrjL1IiZSVeE6errsBvKF5tNDH56F\n6DHw\r\n=RfK+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCli2UqTGUkXdptpiF1na6Qw5tfixYvo5z8ugq3oG8m+AIhAKngTbVIVPsNWDTjK0v9teftDVrOq0Elz5MmlcFrf1Cm"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.14_1627253753767_0.9870161798396313"},"_hasShrinkwrap":false},"2.5.0-alpha.15":{"name":"@synvox/core-client","version":"2.5.0-alpha.15","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"af7ad31fedf18f07bbbd30b0f6cfa3c8c5b41db8","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.15","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-5aajjUTFRZUjQQcUXgSMNdKtmHerT4cSGcJeYiOd/Ilv4EOapRm4cYWYzgeCUw4BhpcKnuoDI75OEeJ0fuz2iA==","shasum":"10f466ec415744cdad2cfe82d967d1a3033474f8","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.15.tgz","fileCount":46,"unpackedSize":477017,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg/fCUCRA9TVsSAnZWagAArsQP/Rw2As/wd87aSBFgzG8N\ntoQZoj39bke5iyDr1iqWhTez73gqk47hEFCCOHsCgMOr6V1+Ae449uu48c+1\nrWVXMQNB6M8PpRBwlbEjUrvBbl05qXxkaHM6kvYD+/sUzlivBhlmrImA8PrG\n8lg2MQWb6Zp7xTDd29ffHHVcAtOdCd/bb2qSrvP2wrRrjOaY04/pNQ0GB22n\nhkiJycvDAw9qPEIpVlg3sqIwqKg5D5L/vTu3FHimatgg2X+oth9ivGP19jBR\nEBKzGuoCY/FA/vgpAIVllNzfOcCi5TXCbaGMJZ1JYFCClkd/p6POlqqm5J0/\nwD3od9szn9ImHHMZfUR7QYeglPqor9UJJTF7zTuMRjtxys/ykXaUcZyb55Y0\n59fp8iUciGFet5CC2sWufrteu+qyObttIOM1TI7vbhlTDICJKkow3+P2LR23\n8dtKbWFC+0qhtlwnsBv0pUme0kY3WsEXQVqzHre0ehaSe7E5ncw5feOKEEIS\nKGp5FZ2U45gkO7bdXVofvNy3fRe3GZ5q1YsuJLVbhpNYNrPtYU398+vV6PD8\n6majKYzqJUenr1bUmmmgwkUMpOT1twaAX9elIDq51QD7uD+qy1uZoMaq5xmg\nIXxI8NQOgapiA6yGw0kPVIMI9JNT/ECx5i+jV028/gVEL8x2kTs5lZCtrAQm\n9S7D\r\n=kjTq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEmvWa/PZuyBhxnJKoGloPqBOkPtahEsUKigcOxI2sq0AiEAlip7zB9srUmMlbVNDiYaBM44bFr6xYMwFpRVl0UEULE="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.15_1627254932003_0.9850540531063365"},"_hasShrinkwrap":false},"2.5.0-alpha.25":{"name":"@synvox/core-client","version":"2.5.0-alpha.25","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"8fea78d4d74365f345a63131ed7afcb5dd40afe0","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.25","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-bmsyuoo5m1thvky3FI2h8gHTY+ZSmbzE9iMhLfrefpweQjBGW9uwIIlNFtVHCJX7q2L5B+tqSYKaHzhwHcbMRQ==","shasum":"4bc6b600692243e6371126306ffffd5264b9c653","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.25.tgz","fileCount":46,"unpackedSize":479698,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAo4PxVH91usmSDv4dHqFszSCwKW8EIXyn4udMyAGlutAiEAw02wG7NTpp7n2m5otL6MeKr+1VQPRQCkL/0rmGYjSt8="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.25_1632238404335_0.37206029676256347"},"_hasShrinkwrap":false},"2.5.0-alpha.26":{"name":"@synvox/core-client","version":"2.5.0-alpha.26","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"07cbba26772ee1d6e9d2c052ff77a657e4486943","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.26","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-ogxZJu1+xnHYVq6ZQ4Kc9uc3g4+v1dhMePYrfc4thgyKobb4sUQ4DPHM9Ub7EfFnxDi6MjQ5LsZ3a+s+7N73HA==","shasum":"595d35fe27bb84c5532502cb7ce881cce0d94a19","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.26.tgz","fileCount":46,"unpackedSize":483117,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCw9ylA1bJpbmRWmMQf0HdpXV8BkzWr7KdbXBHPTeAvngIhAPY4QqI+bLrZqZR7YmJlxMW3NtozD1aMR2mRSSZvIDG3"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.26_1632345868919_0.46480730451355967"},"_hasShrinkwrap":false},"2.5.0-alpha.27":{"name":"@synvox/core-client","version":"2.5.0-alpha.27","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","exports":"./dist/index.modern.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"957dffdcf8a1400eb482fb2eb6d82e2ffcc95290","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.27","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-ORxhWlKts4FHl6r2jWN3aV+eDwgnOdDqcG3FjmJ2Rx0SlTmK5A4U+Y6W1o91924rr7SP/3c7C7gF5qMdcfBojA==","shasum":"32508b170320867b795ec6745d3334413e416b86","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.27.tgz","fileCount":46,"unpackedSize":497189,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBzEE4pg14vF6eqmXAxBHr+ufGMnyWrwDT0Bry6/Mg9xAiBXVHsQrKmL9P2U4Ks7k1yaHwfzrbgLoYQ8Shr0LqPyEg=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.27_1632852678743_0.6563556886703439"},"_hasShrinkwrap":false},"2.5.0-alpha.28":{"name":"@synvox/core-client","version":"2.5.0-alpha.28","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"075acf7d79acc5a5b6b2d0e1d6214875173dee08","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.28","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-AMNQdJZgwQt9SC4W3oTUaIZvwba5MVGf1U0mS50d1VXJGRJep+RgLjZh68uD58URPgL8kl1m+bZfKqa0Zt3hXA==","shasum":"18659019e879f6ecd9892b3277f1877e6a7b40fc","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.28.tgz","fileCount":46,"unpackedSize":499294,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB7nN456vJWir1bd3NlOWTf0VjmjdMCqUEJURe6g5ZjkAiA0wI95jNAzgvHoUDYYN491dzLlTLtNZNv53pqMNc6bkw=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.28_1633037753967_0.7379665506001727"},"_hasShrinkwrap":false},"2.5.0-alpha.29":{"name":"@synvox/core-client","version":"2.5.0-alpha.29","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"6415bcdb374b178c08e3f6e389f2f472e3425ef8","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.29","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-ggzRUmJveGcFlK8pWHcZ4yJy9aJfyCRYBjxc4g/dpVyeOL7b/n1hx4ANgt1lljPg0vUeA5ffVVggkErxNHBMsw==","shasum":"5468da098f1bf02cd14cb3616e38ea7174faac82","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.29.tgz","fileCount":46,"unpackedSize":499140,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDj5lupUPMkuUxE2fW9ngTKoreGcszpPmTm1Ehz81l11wIgYCtWwL/vSTHGrhGhJqc8EDdL7n9Nrjc+Ptpragklq9Y="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.29_1633038575203_0.18445377262918217"},"_hasShrinkwrap":false},"2.5.0-alpha.30":{"name":"@synvox/core-client","version":"2.5.0-alpha.30","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"67c57f00fbd1048196211ecffc9505a45b02a4d3","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.30","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-N++VmwiPKnPmCQn6g8uxJod3l0SVqYP4bw4esPg9lWIwnMV5DlT1AuWcwT5gzggxA+Tet2AambEAUW5qfX69yw==","shasum":"d12a1d749b86390a405bf7593ee6b4432c638dcb","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.30.tgz","fileCount":46,"unpackedSize":504529,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC3lDQd9fQUDmS24mElO6ifdlo6q8MMzrf0A6++G8ppzAiBZ3J90OjCC6/PnieSP0o3lRzRiYsXBoj9SBLSu1MB8nA=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.30_1633041168609_0.3443669461556511"},"_hasShrinkwrap":false},"2.5.0-alpha.32":{"name":"@synvox/core-client","version":"2.5.0-alpha.32","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"7918d070b0afb43ab81e08001a9fa0b04c391fa4","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.32","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-7lgZTlzxOwJIkRcSJveuN/2/a7FehEbrQ60fA1obX9xgK0gBaOIle3aDwo6bi86hzE9VgHNaxZQ3ImlnWLAmmA==","shasum":"409ba1dd2a246d8ea29962fcb74a0ea2c17a28c0","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.32.tgz","fileCount":46,"unpackedSize":505350,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDy5ZIr/zBLu74Gq8/KEt0LAj8fOFuaAtD/VtW9nLqUjAIhANJxoZ+6knTUSi89LhpMpGuaOuI01+afodiNpqdyPxkj"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.32_1633220478406_0.1970995864574352"},"_hasShrinkwrap":false},"2.5.0-alpha.33":{"name":"@synvox/core-client","version":"2.5.0-alpha.33","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"220c4113ebe49357e26cb69cd2a0679e9c802c55","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.33","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-ItVUXWPp1wkve3Z34j0D9NzCMHjvZ5P2w05jD7n6g/xJtnkooUHCo2CYXjCqiDuixQi5sy9Qki6v8X3/tdvXGQ==","shasum":"eebc309d901ec80194b8210d6bfbfadb608a803a","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.33.tgz","fileCount":46,"unpackedSize":512272,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBZ3G60cO1iobgpVPao5eJkXfx2iKKpiwRRc1fQuRRxtAiEAxEkT86R8fcGoC1PJp8KhV2xjynfZ+3CZUoeHr8Vg16M="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.33_1633223678325_0.3340596916797747"},"_hasShrinkwrap":false},"2.5.0-alpha.34":{"name":"@synvox/core-client","version":"2.5.0-alpha.34","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"7ab0e94ca8062ddaf1b1b2491decf004a0753edf","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.34","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-MJvr6CSpRcV+U9k8u2vn0L2mpdh0lIExS17aP9nXmylpt0ThZu37MCzs1VdRlCfzRC8HYl3j6MMv4DpqsKwpqg==","shasum":"63e540cf1115e072bdbca8bbc27a50c6874e0ba6","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.34.tgz","fileCount":46,"unpackedSize":620309,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDhLFwEdodgTBxQZ0s31wvSwjLf7bQcSw3cCYpcx3nfKQIgN0WUNj0J9ovVCWNPDp+Hv/GbUDxeFV2coaygOY25IzM="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.34_1633223854100_0.5282609022633256"},"_hasShrinkwrap":false},"2.5.0-alpha.35":{"name":"@synvox/core-client","version":"2.5.0-alpha.35","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"14d29488c2f43f124e079a696b645456b11b646b","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.35","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-j2qGCC+Y8QIBIjYJKrXnuOqDs/powBL2hghoEbovWGdAM7TrWoGgsqZR/9XIaqv5kwH9IK91v48kyeBE07qT+w==","shasum":"308005d31df5c9d6ed328f14bf828b3cd4ece3e1","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.35.tgz","fileCount":46,"unpackedSize":620309,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDNqFYQtIyWGP5yxfgYb0dJ9VesDDcWgsRSP2EFDKEiDgIhAMA1ZzD3fMe+JbqCwKHJOv3E1RLp0JbqRS4j0BNFHbrY"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.35_1633224129833_0.19567439177907975"},"_hasShrinkwrap":false},"2.5.0-alpha.36":{"name":"@synvox/core-client","version":"2.5.0-alpha.36","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"ac0c7de7dbfe58be3347f94a6153ab82177bc7ed","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.36","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-HkK4yMv7cZJJBg+xt1kjCQrs9uOZy2g9ejoAyAJ+H6gLailN0SoFbNRwU3HKuES3YtC24ipzpte4xAbyrN97ew==","shasum":"e5d0b94f5a9d2c2e596bcd63ed63d41b714395de","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.36.tgz","fileCount":46,"unpackedSize":502077,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDuwvZrRk7il4asq49TGRK/t77lW6mHIXy/O6Oe0ysCkwIhALfdwVTIZzM16TLAYZ4up+v1YbKHLkugP16AF+sENXEm"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.36_1633234108664_0.1311713659333711"},"_hasShrinkwrap":false},"2.5.0-alpha.37":{"name":"@synvox/core-client","version":"2.5.0-alpha.37","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"6921458811199a91b8d6bd6345e32ad3616da61c","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.37","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-6ha6Towt8RKlg+8qu0f1lI6Uskzt0mncoetcBrJT5sQyhepGa27HuxXbswNXHOIY4H6fAYaveZHPKSTVSVrNCg==","shasum":"b9f0a77b31dc7b6db5f52229b461e321122ec4fe","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.37.tgz","fileCount":46,"unpackedSize":641379,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHX4whYi2sz1hBp+AOhyqEUGbwdqYsXZKThcnxpv6SEfAiEAi51B8W77kZ4THvZIndZ/QlskLvSDebQ1tvhdj8Z1ZiM="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.37_1633234219546_0.6534005344383755"},"_hasShrinkwrap":false},"2.5.0-alpha.38":{"name":"@synvox/core-client","version":"2.5.0-alpha.38","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"a7f71f70cf1f72cfb9adcba098dfb10963d237d9","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.38","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-TXEAqOK046men1FAhR00OHKFpATMJPbFUXd2IEGWfJjRhQtjRy15KWBS7fO9/SSjAFYzGZL/LUBOejVqo+m6TQ==","shasum":"5cdbbf7c0cab0dfe1ef8d5f6d0693c462361f105","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.38.tgz","fileCount":46,"unpackedSize":642004,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC4RP6H8tkkZdyuRFZnKzn2AdIikCWsK9G+Qyy64s4nEAIhAJtw/JCF5J1HvfB9QMD18agzcycuSUNd0AWV6yoSUXe2"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.38_1633234952783_0.7130656864970213"},"_hasShrinkwrap":false},"2.5.0-alpha.39":{"name":"@synvox/core-client","version":"2.5.0-alpha.39","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"ace545468776a77f40ba2a77fd711a852824555c","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.39","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-boA07HBnhCkVDdIMKYlr0ndEYD4JbAWV574OhenOmw2DgGpECmcl70g/RsmPnpysu/gPT9eJt0/eoNqAUK43Yw==","shasum":"f37ad43f4a240986e9c6f0d42b74663bae893286","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.39.tgz","fileCount":46,"unpackedSize":642109,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCfmJ/sNyHJ386vwdHzuMxQ0llSgBDuaSLDdGPzrNwGuAIgThOzl42q9UaC19czlC5TG3BpUxSE4B27NzP0Rl0JZSw="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.39_1633235511299_0.7625728445047508"},"_hasShrinkwrap":false},"2.5.0-alpha.40":{"name":"@synvox/core-client","version":"2.5.0-alpha.40","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"185a0e4035bf1dc265bfbecd1387e446cc6822de","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.40","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-5xMHdsWVsNAiH2naX2MmV+PmQx0bVSVPgjSCzB1zw5pI22axrmEUfrCdESEzj/SxB0nS/DQ3K4PIpAPg7IzCDA==","shasum":"21b48dc860195aac2f61dd796bc09bb008d13d7f","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.40.tgz","fileCount":46,"unpackedSize":640837,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFV0M60I9sANi45SfySTPlaZv+t+0ZfGnjPDDH4KIcGXAiEA6+XcsNUOU4pqhpxDHE2HAlh4K+WWRNWcF/r9LyX0HnI="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.40_1633376763789_0.09067865810697784"},"_hasShrinkwrap":false},"2.5.0-alpha.42":{"name":"@synvox/core-client","version":"2.5.0-alpha.42","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"e6f0a2fdc671f9a44cb9066c6ecb0104938f89fe","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.42","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-GrxA2CcipKR56ztziVORJwuGJWZEA24eNO0tLk7IfUqoms0pcfV3HbsaPU+sU+1sdgtXUua5gVB2/8/Y5mfeUw==","shasum":"7e7b1b2085aceb9271f4438504e754c236b5c1fd","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.42.tgz","fileCount":46,"unpackedSize":652531,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIANpvhuwCGZc783nJS9L9/So4KNpgiKSbfKZ5CHgu4a5AiEAnlNVwmstWX6SNygIh1+sL7ytUJnY1mCE6Dq4dOVtrkI="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.42_1633545303642_0.257419659729357"},"_hasShrinkwrap":false},"2.5.0-alpha.43":{"name":"@synvox/core-client","version":"2.5.0-alpha.43","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"05bc622cbcd423d44a07d53477fb7ed337d94a95","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.43","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-Xhdw1w3Iw4x/DZtS9i6Ub1JSESZDlZAYMBlkNfAveHY8NYnKyIzUkAVlEtSukAsskGpErykXE7UuD8BM6iKpNQ==","shasum":"5ec1923c40d130ae1535b726370cb5201c3ddd1b","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.43.tgz","fileCount":46,"unpackedSize":651975,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCK1F9QeSkFOC9KwnC3WmwIc/3U3JNs1TUfcAr1bk1d7QIhALHg33Kj4P+kSOXdm78gmfQ4XlHpPAuRWH0rtZr3RbrK"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.43_1633548230340_0.8451583233381978"},"_hasShrinkwrap":false},"2.5.0-alpha.44":{"name":"@synvox/core-client","version":"2.5.0-alpha.44","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"cb49a1a3fa477c4ab578c0663a6c000760f61801","readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.44","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-Qxrs9QCmB6wBzRrSBPyVS+b/rXByrZ3KR12Z87bLaNSSZnxsjR3l3NpFXoIh0SJ05YNUOiXlZMGVPZh5yHvjjg==","shasum":"b5b4f838f7611236f9e6de870d4b0a5a597b67a8","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.44.tgz","fileCount":46,"unpackedSize":652726,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDg2EseIsC1ievt3CZtib4iwYnSHhjNi4ELMe4KX1CSJAiA6jSiE1QDh90Mx7uVIGjnqUtGs0q0n2E3BB0M3kMj+iA=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.44_1633548627204_0.7815121277593549"},"_hasShrinkwrap":false},"2.5.0-alpha.46":{"name":"@synvox/core-client","version":"2.5.0-alpha.46","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"f28ff55269c46f9a147626e1858df442673d5fdb","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.46","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-HGf7cQ6yLR6CCtZNPSgxzALbrccSFT55lBZ2L8UN3ISqBZ8r7xUuxHyJTfbESsIDUJHlLaIzAWl2gtR/I4lhfA==","shasum":"c9f9819c0d6e7a722e515868f62cbbe701f110ef","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.46.tgz","fileCount":46,"unpackedSize":664500,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCPConm179h5Ie9H0uykW1IYqThDcnP7Vpq0YZqQtb3rQIgUXTcToDN97N1jjrfTfGE14dvLiJYabvQ58jH7JaoPbg="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.46_1633549932014_0.057072210616291974"},"_hasShrinkwrap":false},"2.5.0-alpha.47":{"name":"@synvox/core-client","version":"2.5.0-alpha.47","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"27bb01aeb5fa99a2ef761bad5673862f1a35a767","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.47","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-PlgqKDvQnV3DQK/RbjLBmjYoSlL5zPyOw6gECGisp1ikfepeuzMjrl5tCmVCh2+sKZmhP65a9uzOWSTlHnnvNw==","shasum":"a743912310d0b045b28cc3655fe8e9123b27ff12","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.47.tgz","fileCount":46,"unpackedSize":664551,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEj61/0PZ7Cm8t0X7X3oX8AkTKG3f49mDETKXqnF8dAqAiEAorDhNkYXeU6KHNlvqFaMMRAZykqiavvc39U4gd4btBU="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.47_1633555893512_0.21199325521993062"},"_hasShrinkwrap":false},"2.5.0-alpha.48":{"name":"@synvox/core-client","version":"2.5.0-alpha.48","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"6944caeaf98d88f3710815c742c534a65e86b6c4","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.48","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-zxHXVewVq8NbG60JS0eg9LDoUApkSEvhM5aa9U1Onhyy47ZlaHI0V81jzYiGAc0T4kyJbqwb6Y5hdCBD9qQF1A==","shasum":"424150c52a7ba931b8f40f9a4aa6cda6bc59bc15","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.48.tgz","fileCount":46,"unpackedSize":664835,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDKc3hm+JiiW4V/mPyhvwVwM7I+AA8vppZYw0R7yUk/2gIhAN+N2oQEX2sc3foh8skjyDIJ4A+mjlhr9N7QwQ4ZCdUo"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.48_1633557606106_0.7790024407744001"},"_hasShrinkwrap":false},"2.5.0-alpha.49":{"name":"@synvox/core-client","version":"2.5.0-alpha.49","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"53e8b8852b016c2a191ce3ed476c6db57fc385e9","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.49","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-//QhKnVraziMv5K44zqjEZYJM5+xUOVdbZdKkhEC7OFDgeAykN7lmNaMhRU70iu1kJk4sWd8jWjps02oDuzf4w==","shasum":"3f79bb0f1dad57eb782be6285d3cf63eeb730922","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.49.tgz","fileCount":46,"unpackedSize":663895,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCrCXI9pYBjD2/VgkKJ7JuhahMr3OW6vH9ydUtiLUBaKgIhAMeaZU2O6F3XcOOfW3a6cPTmrPRri7cmtVN/KFYN5F3g"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.49_1633558307163_0.6060487080759531"},"_hasShrinkwrap":false},"2.5.0-alpha.50":{"name":"@synvox/core-client","version":"2.5.0-alpha.50","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"microbundle --jsx React.createElement --no-compress","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"26eeb37b0d18a8ecc4d889b64591e801c20d802a","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.50","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-jdGTNLIUWJ8VCtl9syCd4UOhKG+zYfZcH49GtqlspSDs2zgiYfbGJPj59UA4BMimflEMZ3nVqgVHEtVshCqq4Q==","shasum":"1f2f7f0f3f9e24e39f977376f5c7679456dbd36e","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.50.tgz","fileCount":46,"unpackedSize":665224,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHenDltn6EVMu5kMyOCVSOkcHrYIRMjrS3j+Kqs8V3/nAiAjNsxnckDhE1YI6kHORxmuaOQcv0SNGfTq3+bJuUgsTg=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.50_1633558514299_0.9065396861914121"},"_hasShrinkwrap":false},"2.5.0-alpha.51":{"name":"@synvox/core-client","version":"2.5.0-alpha.51","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"d2f2157a2c7730556f949ac0c435382e27d61ce0","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.51","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-WE80rQJmQKvznW6S3Y4dpxYXHEy1WHQxvJTGsyf56hGOlHDaG/mEheIAGbwIgeF2jHbPk/bCdSGzf4Jgw7PGrg==","shasum":"594dbf8258a032000f89c58309e62fcfd3270490","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.51.tgz","fileCount":50,"unpackedSize":397246,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC4cOOIUrdPpDLRN7sle4JjM4DGlUONhTaHiX0NTC1kJAIgJZb9YyzjnXWF4TO4P0uDAVRZqT48PDpyH2y7BHiqs80="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.51_1633559467945_0.4812966424978342"},"_hasShrinkwrap":false},"2.5.0-alpha.52":{"name":"@synvox/core-client","version":"2.5.0-alpha.52","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"10a7787d480672e4f609b973e5de5dd1e8eb5c36","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.52","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-bOxS9IKl8j5UTSqG82OKKCEuJxUrYkMTSgTW7UFyU7kZJ2P0I5X5C++Dn+I5Jc7QlDmWCyXpTw14Nlbb4K3f8A==","shasum":"49f808f50acfe7e6b419152969b6ab4aa7ee0e4d","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.52.tgz","fileCount":50,"unpackedSize":397299,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCR8py8CMErXaaQubshg6CSpUi3ouLeB0P78dGY3601DAIgI2gZ6NFO10OO+40B51fOt2nW6EHau3Oh6HLpCpF2HrE="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.52_1633559723942_0.6797666121706394"},"_hasShrinkwrap":false},"2.5.0-alpha.53":{"name":"@synvox/core-client","version":"2.5.0-alpha.53","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"0e6b493df71b3d6ebd8d228897e8f633dd97891e","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.53","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-xp6aIa6Dq08YC2pmcH/D/UrEKbkyugZ7moKaEj5uT0uTpjKU24jl9ByQXtkOEIeTD+cI7fc1WJiTp0Rbgx3SfA==","shasum":"3b218c50ca2b84b71fa221f7e2c5d47c65d13c90","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.53.tgz","fileCount":50,"unpackedSize":398432,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDrb09ao5ecU74BGjb8gyQfUaqX9UsqedqZbd/ESF0dtQIgd3nCMJH3SFSpKmkN4ly9RDB1B0jAROlL9q/LlAtm0Ek="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.53_1636744094116_0.15883654113200096"},"_hasShrinkwrap":false},"2.5.0-alpha.54":{"name":"@synvox/core-client","version":"2.5.0-alpha.54","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"c4de704481490886c6b7dad996cf18cdd2658764","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.54","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-DTuzunG3dOBbOg383Fv5K2Z6/6tNBIn4h0GyK5cgbKzgRCqPalgo36ajjC+J6Kt3Mx3jVTkZ0Ioli9fxIjZ7YA==","shasum":"8c606a3a4d8bd57b1c277acb293661bed309e6c7","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.54.tgz","fileCount":50,"unpackedSize":398406,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDdsG3dv1vI2D2BRdS6rKaoUhxPOGgCVxAIHi4cEwh57QIhAO1Gie0nlXGixvt1tGR/0iOknDZWx9hKaOQhFeSehHU/"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.54_1636744131122_0.5095687934051476"},"_hasShrinkwrap":false},"2.5.0-alpha.61":{"name":"@synvox/core-client","version":"2.5.0-alpha.61","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"3b61822daa7d78ddc08e8ebb4744871ee06aec83","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.61","_nodeVersion":"15.13.0","_npmVersion":"lerna/4.0.0/node@v15.13.0+arm64 (darwin)","dist":{"integrity":"sha512-z5cEaVv2wNYGUyt2BHipaWj+Lw9BCTW3GPpn3ZYGeRPSM6zYCT4aZDbTdcRLWA594i5jast88BHPENDVQ17kCA==","shasum":"6b800dec28d913ebfe6a08bc966f0879bf0b57ef","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.61.tgz","fileCount":50,"unpackedSize":404974,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhu67DCRA9TVsSAnZWagAAHWgP/2fbLhOmqpEpoEzzcQT8\nfsrVmIghsaF8/zIambRxhrdA9wX07J6sV5wjCfMyS9iwC+PlQxIQnGMiYnrS\n6gul/LJkzqN6JKV55rUoi/nsM0NQuejuKrL+MTrLGa0p3/ltKBl9EILINa2g\nd6ifcpQDh7VYUIz9du0B2BDBKxhnAibzXhDMmk8JIwaTYGdxVgr10S8YI9WY\nN5v9+JgHE224MK/He0g6VNlTjJBWFYlDo+KsqLozl+bALGCN22d2Nu79FB8G\ntkjs65QnK1XbOx8yF0yPn90VwjodcYv/s3Ma9mjoz6ZEH1y0J4bv7ArlTv5+\nLvigg0/q3KhRoo//QyzreS5X9pPd3tdXdBGEBs0ADpcHJ5aSOxmOdGproTMQ\nJiQDx12tn3fCM/GAH44m43KHkga0D0UmOd+PooAl/9uJVLd1AEinrjD3+O5p\nVYqjqN3ThrGe2RNlQJtjtOMSrKepZ1x6nvRN+K1yOf/zVpY+bgjRGQW5mnX7\nJse6lMf3FVslWh8yEaJpKP3nEFaMcoNXYMCNZMQQZZOXlemj/c+EVopXbmMT\nay/Rf2j3H/GAFX5dkmOnlQmnxQnrG18eQWZ2fKuuH93saSqJA/FGHDraHHDI\ngYEyJDmG/x43QKKa8yTRrF5om2qTTkK8uNIYfSPl2zyNKYyG1hdH6tS6m9kb\nVRCt\r\n=MpX0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDNlETaV4wfYrw0mKKRenzDeI1ZfKYtKiuXMDGZgQUjcgIhALZe9xzEfilWPWjngqETtS2algN79HY9NWYn90o0HVGB"}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.61_1639689923427_0.11458415944828126"},"_hasShrinkwrap":false},"2.5.0-alpha.62":{"name":"@synvox/core-client","version":"2.5.0-alpha.62","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"f61299bf9e5f36377a2b66266a4f9b56e029a696","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.62","_nodeVersion":"17.3.0","_npmVersion":"lerna/4.0.0/node@v17.3.0+arm64 (darwin)","dist":{"integrity":"sha512-x3B3+apwOVn6pbSnIz15/ZQdqfXw75KHWbQvSIXOt+y/bgGBSNq02Xmx4gBVO79dYVj+sj96+5h/s2f5uofPPw==","shasum":"5d2c1b916c36ce27bcb087ea33d1a1aed2ea18b5","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.62.tgz","fileCount":50,"unpackedSize":405787,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh4HV7CRA9TVsSAnZWagAACe8P/20qGSSkqTq+MvfDF4YM\njWTYo4gTRPFz8EdYesqgoB15vWp8rHIKC7G9S+vCXqxC5JBsdWFZtdesriom\nlKNa1FF/cSxCOxVNdZ49rtcafISOUpU+XCeu6Q5IPXrX05meg20GrJXUYmrG\nIZX1OkU+Hv4J2WWgDjsi+pETjUudPGN68fY9SHv1tgZ0/9921VfI+uczy+Qp\nWwsMNkHA5zc7QWU1rm2tk22M7PLHgjBzUIrzs0RAuiUIKjIUEIL2FuE+/P9x\nC0nfmCIa4w8K6vkcwQCbzZYA2O6y0XxPjhAOMsuUf5BKlIGaSfqaU1Ag3UO+\nMaQOHoWunz9CcXBbmAQWPBQa+LSPBN1uJhEzJljRz5tRTpOiCHxC4hEat+BP\nQ+hnjJ0jiYKQ7aWSEK6mHK4zj7r+UCzuEb73IP443XboE2pS5R8FfZpF4Dhn\nfOIiT+KxE59LkwdDV6aT3mTu6TvQMBUG9Va84LeBCIsa9sh3DRt1YD49JGsl\nu62GyJfBqOcF2n0+4x5omwMvpLneT0141+I7HqhxmBx6mQ8POKJn2mjELpGB\nOpIwZeN2lYC6gS+XcjazikHbo737TQ6j2TBnkD7YvSBWRL7/bhL2zPpcuzHl\nNIfAm79sVM77MURoTnJb6W3VBbPhb5r4GUpc6PJt0n0XAZfEdrILh56lYm0f\nyhkh\r\n=7+KG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHRQzUrMRuSyT1XdUkG3F5WNABdmtVanmBmpEU/Bmn/eAiA3AFyyps4k7YyB8gNirEqujJ0Ri6dTDs8+oUs/1GvZJg=="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.62_1642100091436_0.0433835196264567"},"_hasShrinkwrap":false},"2.5.0-alpha.64":{"name":"@synvox/core-client","version":"2.5.0-alpha.64","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"036f6777f8b74874ef898692c6d677a89d7472e8","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeLinks: false,\n        includeRelations: true,\n        includeParams: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.64","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+arm64 (darwin)","dist":{"integrity":"sha512-EetEVDazu4eP9ZeD4tRSHIJCAykb4RwEf54jjZ6+U7px0x5DA4eT8r7hLOjomPU8k2MPTYLK/lL6LWE0N5bu1g==","shasum":"abfeea327cf01a5d9e030c623fddb5c9ec34c630","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.64.tgz","fileCount":50,"unpackedSize":405789,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiPd+4ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpaUw//czQhTaWYMLGC9DUVZzjI8wsML5zwq3/etGhkfYsogHCRuHHx\r\nKcjclXiLTUR71d8yadds++q06JMiYfQrNl6sRFU6JeCeurd8FSF8L3K1pNvP\r\npKhI5xtkMXQuu4cuV04j4Ikje8snh+38Q2ZJLayDnrJus/EihFkF/XMkjXwO\r\nnjUK6tiZCv7+/LBh4n3IcuxaXpOMAzCCnP4RI/YifmvQhcT7jDPKwl1z6SfR\r\nONoZU6o8G6+slXIjpDYSXiDKI+4JnZ7/T36xJHp+ljEpIx6tWrYsUwC4ex/k\r\nmID59KfIP3JkpyqH5hn4lio6sEqHGEQpGm2wK79Ry2sHwRn+hadYzHAEXu2w\r\nsCXuqTHGRE0z38cLlozH23eSjgD6mP/PjRVVd69I9ZWgPlCji+yVOABISQk9\r\noLw7pb7Tb6MUgZOn0srLppRBHzUy72dWf8e7ZHXX/YuVN/FYRPu+jdeBUfpp\r\njfh1ud3L116X6KmmvfUl2kC91CmGAo0/fCGI9UXhqk82BzTU4JmpD/qpWIDK\r\nVgDIt955Myv93A98Lfa+wUOo+vmsSer775Qgo706nDoGBOpUjrq2jYDH3eOM\r\n6q9cR/TH6TtAhpwCqS03XBJicj9uicnU3sKhJpsIAf/9/1ufoOpDwEdM0wzf\r\nV7vUgGkjHX3k/5Uc/1q5bHpu6T9N1W/EMAQ=\r\n=Nl8s\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC23uFv9giAan+bqqbDfjPTuMhCsyT9YXwFURC8GoAMjgIgFQG0VCpQZ7qju0HBqDyRTtGMEfkHZhV3iZMMUHnL+DI="}]},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.64_1648222136116_0.6053038514282971"},"_hasShrinkwrap":false},"2.5.0-alpha.65":{"name":"@synvox/core-client","version":"2.5.0-alpha.65","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"dd3ed5394833e030f34049a91206b378f4ebbd46","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeRelations: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.65","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+arm64 (darwin)","dist":{"integrity":"sha512-ByMfjoKx98uzntjeSY5Vl/xcBH9wTRGaMXmTvmbwBjX3PWkWUm+in+C0DxSt8kFcAxSEtU3Rc16enHNN0tt+tg==","shasum":"e49a9886f1c7c5aff359db103da7a297b7ae8731","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.65.tgz","fileCount":50,"unpackedSize":405731,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCdjRpSxflWvHyP+1PwHYcOU4iUGsc61nz8OLIGwaxh3wIgCMi6ShDrgCA/dId1VLadwHKyYcehrn8pfFEsYCWjkaA="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiTSBOACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoNtw/8Dg7869M9uxZGaXnBc3hLvhVkSkAuZa9LbhUa9mOEDE1hCf+0\r\nm79il8B/PPJBXKCMSENXB8aRzL+sj4v8gD1xJWkrK6NGp6aJk/1sefhk7Fpi\r\nNirsTHOHd8NbFyBLG6IEP5qmS7X5BhlR/oE/OxkgntvEV4lTop5NNyBgjfzz\r\nRQr3WMyZGyl/BC+GB+2+HjMoUo1UFYEIw4C1XNOpiJoRyjn9jqwAOKBKWdng\r\nchPgGyi2yv95Pfa62mgRXabrEPyq1C6hXTsqnc3co1Z73eNrn9N6RM979KrA\r\nPr2kj/ewl3sB4a1jWnYPpktvcjeXymrKkxfzsRGBnHEzMjU8+ID5stDS3dkb\r\n/m0/x93mIW5dXHK2geG9tCOT71xtKxVhSqZkuBddFM0fRzN7aU2MNc3wNnsm\r\niSZXTqFR0UqPBnLUfXY+a/so0h0PRrPMhbZX0Q7jyz/tyeMkI+XsLBNl6ywB\r\nI4YIctGLc8wL1L0wRo/jGl2lh7PCZeP4gzpSkqJm+Zg73fEbv2j1ccftFHSd\r\nW6E+4f2x88LfIILuri4yj1brO27w5iuL2SZAT0rBWF0f5/B1q/qCoTU3SfdA\r\nHyNlOL2/ldjjS6QIrK4YhvajNUa0+YTmFuGJxgxrVZjnPAIIvjmYpfCXqF+e\r\nFSpObv5KkhNG15DS2bIL7BmgvoOUZguOTuQ=\r\n=FTqp\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.65_1649221709875_0.8554502512470592"},"_hasShrinkwrap":false},"2.5.0-alpha.67":{"name":"@synvox/core-client","version":"2.5.0-alpha.67","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"c207d4f072e1fdd5ae31c7f6b22b58e9b4faa973","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeRelations: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.67","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+arm64 (darwin)","dist":{"integrity":"sha512-6zUVil6zuSqkgMbx1M70/SRwWP6Ud0z/0e41/L9LOR9HKb4Qb2XtX9v8YJ0JQF4k0uapEfo6+JE/V6xvJKajDA==","shasum":"11a0d2a322b22326ab86281411ac92b12c8fe4dd","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.67.tgz","fileCount":50,"unpackedSize":405776,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC9nHZf5EU1lpdwXHbC170IhIc40KdDsqa/HOB6Huf/sAiB5D2kKH4kjvIKNdfmqY+2jD0QBRzyMLLF0+OZzhNtt4w=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiTSNLACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrhxQ/+K/Hl0Y1UhaofhnKKLb/lMTrxMVKNnx5omXtiTksiF13I+Woc\r\nLha6XCnRPOwddn6sln8zXrNCnVegjU+u5i1qbVeUOoGFrkMzKYzLi93+pxlD\r\n1i7ygbiJoMC0z3KYbwMxcMLA9upN7w3z5zyPSssCAT6QiGeoWuVDPSIw+0qW\r\nKi3ER9QUauBzVRq0xyHjc7fnmqUE/6vgJDUKK0xiLUtr3nFurj2kwBfl8hnx\r\nIKXXh/HNFvMpdfSWTD68lT8RU5SpZIfK2iRT34Hx4sB/feP95UwyTB7YVKq5\r\n2Ak+v6TvGvknU4q+QQQqsSJIQmSWBEV8AAU2KkD8y3dltN8ASbjVgxQ33gIG\r\nTova3iW8lKk7uShzUDgniJyBH2RnJx8/KzhHbdIDwt7hcmvk9re/B6RKkSFC\r\n+tK0y85ksVzNjzs4+xC7Yp0UPwSsfH5dC7TIXU5MZ7nT7heDAmTL0PG/VPPN\r\n3Gp0f8Q5DM1pOx6fBHPqSSg0EfIYBkw4qJGF53Xixsh/yDgdl006SsOY6KUI\r\n7NyT5ine+LunWtwJM/4+p9jkzdcoGQJakSvgb3kpbLKBCRln8QaK3uH/upcl\r\nOLZNkPxHFS37uCWWriGT8IrLslOYS0l8XhRbxscLVSBfAgUl60t+mKUm7Gy+\r\nBf0TT2tGLY5reiljFAN6XQvZD54EQpJ0ZYw=\r\n=i339\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.67_1649222475158_0.5921614269016531"},"_hasShrinkwrap":false},"2.5.0-alpha.68":{"name":"@synvox/core-client","version":"2.5.0-alpha.68","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"7e269a51eca256a27db12cd3f313008188f423f4","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeRelations: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.68","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+arm64 (darwin)","dist":{"integrity":"sha512-pIKUlCbz2xLd+i6VPUxcjYPmBPmftUBYigI+cLSl5Fjrq87056RBT9Q15Xf25QIOOKWq7rs7NAHSzUD7B1sdJQ==","shasum":"b90eb98807741791e846ba3d1edebfec5d7bfe1e","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.68.tgz","fileCount":50,"unpackedSize":405776,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC/Z2Yg+KAdHEy7b5jzFFEVJ0iA6Li0H3ghKb8si25vvAiADUX92N960T4br+ePJIWtdvfeTEc3yfXyiITAUJNXgHA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiTSRrACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoxYhAAnnYjsIf6iCKAcRtiiQOcqc5Ut49ApLxyF0fs2pR2lLCTXMi6\r\nI1nkicRBBV7OueZ7GncZxbCdg0ZCwgQpwaHAtVQMJxz4JEPPjVA3MV4F5tTg\r\nKdad7/U9dDqZBCx99sVqR5rKQric5Iz9aJqjnnVTNfdtPEt1t8/n7FjmiRkN\r\nQp1qTm8E3Oi9d7sNvYtC3W27n3jTFMT9BEz8KQqlLPSIzk1YShE8Sa6/St+3\r\nM8F2LEY/Gwq6XmWmDfopDWcJbBthAAgc54+6B4lKxrrYTcAo0mPF8DzZiAUn\r\nFuN6Get+4wntiYcFzVPCS06m8pukTu8EiLPHefnIImpOsEl8Z/pUk+xqc4H6\r\niyt28K5pxzgTx2EH/jbSfV2LuTuAx0J1W6MGls3stLibifO/iH6iLSXPuraO\r\n4W6eBU+r/eIfed3MYCCGAAjy12W06FXkPnntT9I5O1nL7hyiUBfn37fZ9ww1\r\n7l4OK+GUGT21S5KjJbzDimy2Jbb/VVwnuDqfLOGVn/uqZtGs5xo1PNiCdizm\r\nLGFj+4xIcn/qvIPUMtJV8KTJDn8YI1JAdZL26KqR8xTb79Kk/+KoGMU3eSbE\r\nT3l3kFdGAvtGEwv4FRLnPxHuNZY4fyuBCmn1NvIgu48mG7m+kMDRUGvwrJYR\r\n6H69JB4IgrRJUeP/vrNfe4b39yaDzlQWxXI=\r\n=Hyn7\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.68_1649222762984_0.03696555164701443"},"_hasShrinkwrap":false},"2.5.0-alpha.73":{"name":"@synvox/core-client","version":"2.5.0-alpha.73","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"066455cfde3c5ab3bdc491e3b2fdd924a842b3dd","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeRelations: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.73","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+arm64 (darwin)","dist":{"integrity":"sha512-fT61X317G9PezGa1enM8bHSHh9JXt1+u6MfzGLaMosHnNSw+OZrMUYHlHqLv/AmsIuQ6f68y/WljLXoFHVfhBw==","shasum":"a45c3c62679e38d1ff42347e77c0ff986cb96e84","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.73.tgz","fileCount":50,"unpackedSize":405776,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIANpA9wWMy7Ly9mKcrgFa6Qma/X/j0aL71l3PVWpxmxDAiEA3DfzYj8gyqw4s0ZFrg52mnH9vvIWRPKTYVpxxk2MZI4="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJii72TACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrWuA//Tll7HsAH1caVtZ9O2cM8+hb+r9u0tytOr00cj7vxyzX1+jIO\r\nbdR+AkWC9p48wJTxfmlAsCvSiW/Kbf4dRc51c0k66rVOoQblkWKXyM8lr2V/\r\naDUL7pVvxrNIvpNouZkNAU/WG7yEAa3iIydZAapA4/YxJZA32o+ZPJ5ZD3nb\r\nooiqCyXgmosecajeISpEnHMcdtDwK0G6joicNTi2dOo1IclXy/If/sSX40DM\r\nUNVyi49wa/EdRezbH8ux51EoDFbbH41bw3tzc/oDn+icovCE1ua02cCFMnjq\r\nvw3ZVDtnkSF1ydoaMngMFoov8F/nBJgu19EmQWIlwDVGi/I6WvracUIh6nVz\r\n7D83nC0WYWmcBe8usNfmIofbXMfYx+vLEoVKkE+cXzNoAMMUk1RB2f7+O6vu\r\nqSaXW4tPL9t2W7f+JpI1fyXX4Ykq6KVx+beEvdVVTeinEeyY13fbzkXc6PHR\r\nYIpK9rXc+4HvuHQ2yluihajP4BdjQagg2obgDEtJw8qQEdnMu3xY0xj1XIC3\r\nBsGDSlQjzrvqGcQUfhSbKY+MBzXY85SQLrHg/j/PP+DPg0Rax+4/ZKtS1PAL\r\nT7ZBnhAH7QE79a3tEqlyFNML71ZxzLakut0BYq6oGbHA6Nk506hXm1g1pNtw\r\nSOAowrEdcUM8+IgRcmMBcHfifUdPeBaiOFM=\r\n=bwqa\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.73_1653325202637_0.9207059303425438"},"_hasShrinkwrap":false},"2.5.0-alpha.74":{"name":"@synvox/core-client","version":"2.5.0-alpha.74","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"2142840b2e97684fe48292d8a93d2dcbf492e6bf","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeRelations: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.74","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+arm64 (darwin)","dist":{"integrity":"sha512-+9PZXjqQto4MGhR8z8nJqPzsWSJ+VgDTA1q9LJVvJ5qmH/hJt5p3Oo+azD6tgHaZIYpP2NIldE2j9iFsp/RTPQ==","shasum":"9e620bf2cb9c5149a1eb15f4606dc03b0cf45968","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.74.tgz","fileCount":50,"unpackedSize":405626,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA990L5EWomju0BJ/ib3BSglNGUdaXwBEtvDogYzyw8AAiBAsNDaSDT50gg+UrI/1kJV40rwl5WZE2QGpMPv8+BYBg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJii7+AACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpy2w/+OH36g3qmlLK6J3TaviFkRK3pOnfJp7T8XSl0ZVcBTN0I4JZ0\r\nicMTWU2PPzj6DaDcu0uAHVtvXPAMYH8+JfXIKJsaCHRVj+8tV3eKAuIM5js+\r\nV2qFCV5a2ypNnKAXMbnnAvUbC6GARzdoj+6ZZbh1RGQ1GNFsbAluzfn3MqnA\r\n1uEewCHj5UjZO0E73Jovqrn7JT7FFcS7rUYA55WlWt1i7KhY/P/izoP4SwbC\r\nbEsUDyeHhkhuNAvRKvSB1qqb9alJ9hJjreKvCoq5icjgegR/KWIObLDDBEot\r\nn5gSwyAmeWsCkEBM9/HsbP3KgP5LFFNDIJYLrAmCfEppu6jwmtYD3FSYCdfi\r\njtdLWEHC/JJDKOtQjfBst6CAJ91STA2NJwUP5uxq9BYGg83Nll4Lnkswr41w\r\nx8QsRbHXE27F6cZk9y2HK1ti20MiW7ybNeT4B9qWal6rvKqAXfo7wDulZ4rM\r\n7FaquRANKxN2KrGPRi9qMc1uGV0BCCSnQN7bMmJ7/uqVS+yEWCXdprz9thEF\r\nmoHUrALmdx2PE6nF4NPi/+jAeGqU19swXvL73kG7dVwJ+N3E0LIiKFlLQWxi\r\n7A9tEVi8FkcPad8BMhS0abFPp+74mbcXGX88Mh35tmWC4HgAkWbxuB7B3367\r\nTFEe1gGe6hqeGn5AZ8kfU4wS/ysL8q+29Qs=\r\n=MAfk\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.74_1653325696094_0.7220313449854232"},"_hasShrinkwrap":false},"2.5.0-alpha.75":{"name":"@synvox/core-client","version":"2.5.0-alpha.75","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"^0.21.1","react":"^17.0.2","react-dom":"^17.0.2"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"c773d63c598112b8e5690d517a93a5af73682fbb","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeRelations: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.75","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+arm64 (darwin)","dist":{"integrity":"sha512-JnAEbbJSTZla+5OZlGIzV0iV3e6pQdWh0ahndJUCW2kpkTEUF1lCHLIqU/22QF5kYBDttg+3yyUps9yUuhvpfg==","shasum":"b9847076bdb42937c14e3d6330aa6b9197b8ea66","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.75.tgz","fileCount":50,"unpackedSize":395219,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCBZHIduwLUcRVmRtA6fFoBa5ocgVp7sjy/nyPaRHvrgQIhAIZ+/nU1WxBWEjnGvdpaY9krvCck5QUurAGs9St1LKzO"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJii8QFACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo0rA/6A1rH0pb382FyN6YBUCPHOyC45cw5IBmBWz/3Ko2mgFZiDEM5\r\n9Tq0xPxpcUBoZCumdiet1TQ6d/6kxeKhB5OaK0r13vCM355XyPEkf2ezSju8\r\nIfq9Qvm9zeGkqe5rm5hBcxSTyaSdEjb9CpvvdJ/Sqq6LHOqBobmf7gmbiUKD\r\n8jYH3JBBXhfzt06QRA+DvkMLaYdCgOoUyovI5wbrQh2pcKeFYsbOLPQ21q2X\r\nfby8+uInioZumMFf/hskVlt6WxiyUQFgp7fi4wipin+qSF31Y0TNklZPE7Hz\r\nVx58sBmasv90c81nesOOX3X/kG8jS04s8fyIJpYKzKQ1vS76xlhhcUkI7dH3\r\nYtT1jeir/YnjEPZABvCZiFPGp+DJFuT/M9asG++U3kMyxql90KfIZ83D1yD4\r\noFuwjOQTDzSi9xUFXruEYvqLGqhg9vz60kTHkrsXGCP5Fi3vMGm161n5ULqP\r\nA5m7Zfp3LRC+9I9fQDV1KQxyJAKHxZV8MCE1NZ0NHYmP2ItRSwKWSRzRvupi\r\n41+BiLOMOmUSRNzlMuwkKLl29DG/aCpBXRxBKnEbmwEhtB//tZ3M8poxg6y/\r\njdgtrN2AizDaEAYVqWE6+aZGyBZ7AB/Q8/Ooud5resGlyUHkgV0ThP3oH/d8\r\nJcSnGAubkHyb7TcfM8AefuBHSD2OvG0kK7o=\r\n=3EQK\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.75_1653326853729_0.5092732744670616"},"_hasShrinkwrap":false},"2.5.0-alpha.76":{"name":"@synvox/core-client","version":"2.5.0-alpha.76","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"*","react":"17.x || 18.x","react-dom":"17.x || 18.x"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"d6d52b4ef4152db3468619fb1f2c1568e4ca9000","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeRelations: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.76","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+arm64 (darwin)","dist":{"integrity":"sha512-urkzfnkxBQd5/g/izSySldhGzN6x7C5QJsun+efThZE9d5LN00aVJGU2aWhqh60i1ZLzSsbY+OsJWBgPgKfLwQ==","shasum":"a23856b7e9b31f28db91dfc3204fb10486db3565","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.76.tgz","fileCount":50,"unpackedSize":395223,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEob5w/qLR+8QPW45aS7ehethsYLwkB1i4jpuQuet6HFAiBhAse03gBjvqQbKWhXP2fsJUATnbFOQRAuTmTZeGHsDA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi6UIOACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo+jhAAgpGMxeP67tLrTYSgcMZSwShVSv5Pg7s98KeuQ3+cwxNs6rSF\r\nUwPQmvp2A7ruMF1of9/WfZOp3Chu9zZaDUfcnQNIqNXjRe0Dm9I9C1WmsYzR\r\nNCQiJ7Ejn+zJdPpRWP1Hqd4/+FAUW1CqDEXiXVqLIw+BKc+ajhwNSMfDo02T\r\nZD4suovQunNsKKKwY9tDDDBy5vbG/sj/3flilGpC3CdqZun4G3lVjCrqYloX\r\nTTipUQJkwi68HvIfsgZLiQO5mUuKiogiA31cYVj8OR74aPckesaZkrCXJnlg\r\nB97RiF1/C1FpMSG3n4XmJz4crQIx4Kkql4XP58CnPt7VRYkOd3lrnOlTc9Ui\r\nzUThW9/iArcIAGEYs3z1ueOvK1SA7L9I8ZvH5C9sHx25LeMkX74JRpygtJCK\r\n2U5t7d5Ykgz7E9AS5vY3CvErcjmLOAgcjPL0TBqr3uNEK+nHvWdfWKDZ+Dkn\r\nhv7KCGD8a1Ch1sDVXO194WkpENsqs5S45Jm0EovfssgxZH0w41R0FSZyytqe\r\ngrl1za2z6nwpBd1Gse5XC4ExUEjZF0A++sU6vBkAuJufo4XRXPz3ztpuOyVZ\r\n73JL4iMPxhAiSVe1zLju1Wps9knhlGQohxGewodDr9gw00/LleJTC686Stbh\r\n+5MI3jiZFIqDJ6VLbrGc2jWM66Lf5lostfs=\r\n=uMr6\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.76_1659453966719_0.23972684497589491"},"_hasShrinkwrap":false},"2.5.0-alpha.82":{"name":"@synvox/core-client","version":"2.5.0-alpha.82","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"*","react":"*","react-dom":"*"},"dependencies":{"debug":"^4.3.1","qs":"^6.5.2"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"9ca12fb592c8ff6b388dbf77055d7e67a0222b3a","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeRelations: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.82","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+arm64 (darwin)","dist":{"integrity":"sha512-JkoWyI9Y6xZg8zb4NtLqvWgs4MHZ/q4JkS4VbUfYCpvmbfpSDLFN2mnTvyeeyzfoFr4+oV5ugRpfERHFYNF09Q==","shasum":"86798dcdf993b9c5a26ec524847e57cc49fbb95a","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.82.tgz","fileCount":50,"unpackedSize":395201,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCjgfGDmvk3HncA607cV/m8jyeSYvLRytR/SHyk5w2mDQIgVKEV9E7IJVo7QOuz3uHvW6XGFIC9K2HTQZ4Xmeb6ROw="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjvuFHACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqzMQ//c51UwLfcauiaRaDB8SAubPjtsxHfabLAYPoLVjeNC/bJKvp1\r\nORGaac2SO2Y4xfcga/LMOxhMHzgfXBeZOXzxeYK7q17uR3ZstATeH9D+DPWD\r\nH7QmQqGc/QVc93rF5lu7q1ZPZSfEouisrGUT/kGqCf/j1ekF5eR2UXgQrHQ2\r\nuqmcCwUIWQU+nX1LZLG6JIfPH4vNQ1QH348T82+lhFW2LXM83FFucMBe/FvG\r\nUjtXWxichYEWtyn6CSZnrgvbke54Nv5Gjdo/leE2Hw0lW1ZW2BDv9B/1kAjR\r\naCuNjkb/ZorUZc/4cSSKsPwjrq7ZHlepOTT7hVZA/k/FTe0cw8ceALT3P0/7\r\nOO2sVVRB139laFerqy7XT+sUvZw7hRWV0bo7cmwoB0a9wU6opY+fkKHz2YhY\r\nuGqtau3EzEbek9wHgjU1WaMTik/iH2SEueyJ2NPg1A8T8/oYMiCra5sOlhGa\r\njotgLwb2EBXmq8DPubJmro1YQnCAto4NZzECgXadhJ0Y0Hx2fhCb0Sx8p5AF\r\nTfm0zDiT6lKXw2gV/KeQyMczLbhX7WDEjkVeOzV0bWWEEMd4tc8Fo2tlcMmX\r\nzasxwgHkN2iiaTMzyaRhu2c7ogvSSZ2TL0QO9p/rSwimUSB5tAnrUkdR43RE\r\nLCJja5lam+mpnq1iLB5zIc5sEWIIdVW3MsM=\r\n=1uT3\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.82_1673453895087_0.7905268953429048"},"_hasShrinkwrap":false},"2.5.0-alpha.83":{"name":"@synvox/core-client","version":"2.5.0-alpha.83","license":"MIT","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","unpkg":"dist/index.umd.js","types":"dist/index.d.ts","scripts":{"build":"rm -rf dist && tsc","test":"jest","prepublishOnly":"npm run build"},"keywords":[],"author":{"name":"Ryan Allred"},"jest":{"setupFilesAfterEnv":[],"preset":"ts-jest","testEnvironment":"jsdom","coverageDirectory":"./coverage/","collectCoverage":true,"testMatch":["<rootDir>/test/**/*.(test|spec).ts?(x)"],"moduleFileExtensions":["ts","tsx","js","jsx"]},"peerDependencies":{"axios":"*","react":"*","react-dom":"*"},"dependencies":{"debug":"^4.3.1","qs":"^6.11.0"},"repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"np":{"yarn":false,"contents":"dist"},"gitHead":"94b1d3b627643c11762ac0b112add18a582a47b7","devDependencies":{"@types/debug":"^4.1.7"},"readme":"# `@synvox/core-client`\n\nCore client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.\n\n## Using types\n\nIn your Core server, you may save TypeScript types for your database schema. like this:\n\n```js\n// on your server\nif (process.env.NODE_ENV !== \"production\") {\n  core.init().then(async () => {\n    await core.saveTsTypes(\n      path.resolve(__dirname, \"/project/client/types.ts\"),\n      {\n        includeRelations: true,\n      }\n    );\n  });\n}\n```\n\n`includeLinks: false` will tell Core server not to save `_links` and `_url` properties.\n\n`includeRelations: true` will tell Core to save related tables as properties. For example, if you have a `posts` and a `comments` table, core might output something like:\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n```\n\n`includeParams: true` will tell Core to save the query parameter options for a table.\n\n```ts\ntype Post = {\n  id: number;\n  title: string;\n  comments: Comment[];\n};\n\ntype PostParams = {\n  id: number;\n  title: string;\n  // more not shown\n};\n\ntype Comment = {\n  id: number;\n  body: string;\n  post: Post;\n};\n\ntype CommentParams = {\n  id: number;\n  body: string;\n  // more not shown\n};\n```\n\n## Quick Start\n\nUsing the post and comments example, define your core schema and the routes each resource may be on.\n\n```ts\nimport { core, table } from \"@synvox/core-client\";\nimport Axios from \"axios\";\n\nconst axios = Axios.create({ baseURL: \"/api\" });\n\nconst { useCore } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\nexport { useCore };\n```\n\nThen in your component:\n\n```tsx\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // `post` will be of type `Post`\n  // `postId` must be of type `PostParams['id']`\n\n  return <>{post.name}</>;\n}\n```\n\n_🎉 and Core will load that post into your component_. Internally this works similar to `React.lazy`. Core will manage an in-memory cache and suspend for data it needs.\n\nCore provides hypermedia links (like `_url`, and `_links`). When core requests a collection like `/posts`, core will also cache the embedded rows like `/posts/1` and `/posts/2`. So if you have a component that does this:\n\n```tsx\nfunction Posts() {\n  const core = useCore();\n\n  const posts = core.posts();\n  // posts will be assigned type `Post[]`\n\n  return posts.map((post) => <Post key={post.id} postId={post.id} />);\n}\n\nfunction Post({ postId }: { postId: number }) {\n  const core = useCore();\n\n  const post = core.posts(postId);\n  // post will be assigned type`Post`\n\n  return <>{post.name}</>;\n}\n```\n\nThen there will not be a separate request to get `/post/:id`. Core already has it in the cache from `/posts`. There's no need to load it a second time.\n\n## The `useCore` hook\n\nThe `useCore` hook has suspending and non-suspending methods.\n\n```tsx\nconst core = useCore()\n// suspending\ncore.posts.get(id: PostParams['id'], params?: PostParams) // => Post\ncore.posts.get(params?: PostParams) // => Post[]\ncore.posts() // same as core.posts.get\ncore.first(params?: PostParams) // => Post\ncore.ids(params?: PostParams) // => Array<PostParams['id']>\ncore.count(params?: PostParams) // => number\n\n// async\ncore.posts.post(data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\ncore.posts.put(id: PostParams['id'], data: Partial<Post>, params?: Params) // => ChangeTo<Post>\ncore.posts.delete(id: PostParams['id'], params?: Params) // => ChangeTo<Post[]>\ncore.posts.post(url:string, data: Partial<Post> | Partial<Post>[], params?: Params) // => ChangeTo<Post[]>\n// useful when calling something like `POST /users/:method`\n```\n\n## Resolving changes\n\nThe `ChangeTo` type includes an `update` method. After sending a request, call `update` to update all components that may have been changed by the request.\n\n```tsx\nasync function saveComment() {\n  const { update } = await core.comments.post({\n    body: newPostBody,\n  });\n\n  await update();\n}\n```\n\nCore will not automatically call update for you so you in case you need to change something before the components are updated, like redirect.\n\n## Preloading\n\nIf you have a waterfall request that you would like to avoid, you can preload.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  preload(() => core.items(1));\n  preload(() => core.items(2));\n}\n```\n\nThis will load both `/items/1` and `/items/2`. Each `preload` call will return an async function that resolves the return value once it exists in the cache.\n\n## Deferring\n\nThis is similar to preloading but instead of returning a promise, it will return `{data: T[] | undefined, isLoading: boolean}`. This makes it useful for sending requests that should not suspend.\n\n```tsx\nimport { preload } from \"@synvox/core-client\";\n\nconst { useCore } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\nfunction Component() {\n  const core = useCore();\n\n  const { data: user, isLoading } = suspend(() => {\n    return core.users(\"me\");\n  });\n}\n```\n\n## Cache Invalidation\n\nIn the case you need to invalidate cached urls, you can use the `touch` method.\n\n```ts\nconst { useCore, touch } = core(axios, {\n  posts: table<Post, PostParams>(\"/posts\"),\n  comments: table<Comment, CommentParams>(\"/comments\"),\n});\n\n// then elsewhere...\n\nawait touch((url) => {\n  // return true if you want to invalidate this url\n  return url.startsWith(\"/posts\") || url.startsWith(\"/comments\");\n});\n```\n\nCore will rerun the request that loaded that url and once all urls are loaded again, Core will update the components.\n\n## Loading raw URLs\n\nIf you need to load a url into the cache manually, use the `useGetUrl` hook\n\n```ts\nconst { useGetUrl } = core(axios, {\n  item: table<Item, ItemParams>(\"/items\"),\n});\n\n// then elsewhere...\nconst item = useGetUrl(\"/items/1\");\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/synvox/core/issues"},"homepage":"https://github.com/synvox/core#readme","_id":"@synvox/core-client@2.5.0-alpha.83","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+arm64 (darwin)","dist":{"integrity":"sha512-vf69nNUP3LhbrwYWmcIv8czjNsbXoB49L/sNTqIQwn+cKZNV9jX4BeRjFFlGoEdR+NcPhyNGt2sn4SYc4XY9Pg==","shasum":"65b5a90abef115f7960fbc01b3c454b55d2cac9e","tarball":"https://registry.npmjs.org/@synvox/core-client/-/core-client-2.5.0-alpha.83.tgz","fileCount":50,"unpackedSize":395202,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCdmpXcN/zJjMV37KsZE1BwBPJGqTrdAi/Ydym44nEaKAIhAMwsC6pGBhbA5LfT8Y4zOztduVOSJcD2hR3z1FT/RPAE"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjwEGjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoiGg/+KmfctOHEHCHN4WKPBNWeJKvQRljXrvO/hn/yaaHRgnYl4dR8\r\n2tpA2gsPA9ae41W53+K8yFWD7dWYjhtvoU9+HNK2wOeMUUN3RtiB+Ot/Ast6\r\n9gsf6KoppUOtogq2GWkRA8ECW4bfaKnclK5HEBD1U/kh1+DApIAnAn4ASX9W\r\n3pU6pHlxZ+5CfW7obFz+VmFCpAn75GAdg+Y8/t1HKf4tuIjUE6iLPkUobbzr\r\nsmhooJqGpapPAjv6M8OXepdB48naSieHQp82/KGMU340bYeP8Hr4FQaUHDXC\r\nFVoLzvhDZ2wy8+M+9pZkdz0FPQvN0iol1lpIQty5IuX0/cloM+OPSOIzr4Uk\r\nFw0caGwtxQnCNkvoxXZ8LcxrdgxsS8rp7evCXnToGuicv1UfeS4pfTj+ca0/\r\nCM+cewStwDiNTik3vNaqoIfCfLuCElNw7XGo5La1pTUljJYG5B2Ne6k+vbcf\r\nXbVxJ3mWCEyW/ge4DyO+Ju4ViY9hghepEiCYDyDauXFkvpfbD+6S08T+m8Rt\r\n1hu9zHAa+nOoIYk/QXms25p+e0vGspj0kNd1zRmZCSgBmVmag9lK1jBOqVPd\r\nzvqmY9/Ij6XaD0wk5bmJwAZqxv79Kb6idkOU9j9w7wVzmVjk8alsB+aSD/t6\r\nRP7UHi+AwAefBpNvC4617tIV02RM0Fw+aL4=\r\n=z5Hy\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synvox","email":"ryan@allred.xyz"},"directories":{},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/core-client_2.5.0-alpha.83_1673544099220_0.7861901381911458"},"_hasShrinkwrap":false}},"time":{"created":"2021-04-04T05:35:11.006Z","1.0.0":"2021-04-04T05:35:11.253Z","modified":"2023-01-12T17:21:39.489Z","2.0.0-0":"2021-04-05T04:53:35.182Z","2.0.0-1":"2021-04-06T01:27:10.252Z","2.0.0-2":"2021-04-06T01:37:46.991Z","2.0.0-3":"2021-04-06T04:31:58.327Z","2.0.0-4":"2021-04-06T04:39:51.755Z","2.0.0-5":"2021-04-06T04:45:11.702Z","2.0.0-6":"2021-04-06T05:03:03.933Z","2.0.0-7":"2021-04-07T03:43:29.108Z","2.0.0-8":"2021-04-09T04:13:54.026Z","2.0.0-9":"2021-04-09T04:35:27.871Z","2.0.0-10":"2021-04-09T05:27:25.262Z","2.0.0-11":"2021-04-10T23:58:08.415Z","2.0.0-12":"2021-04-11T01:11:26.111Z","2.0.0-13":"2021-04-11T04:01:21.504Z","2.0.0-14":"2021-04-11T18:55:52.871Z","2.0.0-15":"2021-04-13T04:02:10.261Z","2.0.0-16":"2021-04-13T23:06:15.675Z","2.0.0-17":"2021-04-14T03:07:38.298Z","2.0.0-18":"2021-04-14T03:28:29.140Z","2.0.0-19":"2021-04-14T04:52:03.715Z","2.0.0-20":"2021-04-15T23:52:15.038Z","2.0.0":"2021-04-16T23:30:40.273Z","2.1.0":"2021-04-21T04:48:28.586Z","2.3.1-alpha.0":"2021-04-30T05:03:06.075Z","2.3.1-alpha.1":"2021-05-01T03:03:08.683Z","2.3.1-alpha.2":"2021-05-01T03:15:24.358Z","2.3.1-alpha.3":"2021-05-01T17:20:56.687Z","2.3.1-alpha.4":"2021-05-01T20:07:41.815Z","2.3.1-alpha.5":"2021-05-02T04:35:43.859Z","2.3.1-alpha.6":"2021-05-02T18:12:57.802Z","2.3.1-alpha.7":"2021-05-06T02:54:33.295Z","2.3.1":"2021-05-17T03:40:18.739Z","2.3.2":"2021-05-26T04:08:38.265Z","2.4.0":"2021-06-08T19:20:21.764Z","2.5.0-alpha.0":"2021-06-15T00:50:20.465Z","2.5.0-alpha.3":"2021-06-17T04:00:59.707Z","2.5.0-alpha.6":"2021-06-20T03:34:54.274Z","2.5.0-alpha.7":"2021-06-21T01:16:55.108Z","2.5.0-alpha.8":"2021-06-23T16:00:03.834Z","2.5.0-alpha.9":"2021-06-23T16:33:42.047Z","2.5.0-alpha.14":"2021-07-25T22:55:53.940Z","2.5.0-alpha.15":"2021-07-25T23:15:32.161Z","2.5.0-alpha.25":"2021-09-21T15:33:24.541Z","2.5.0-alpha.26":"2021-09-22T21:24:29.022Z","2.5.0-alpha.27":"2021-09-28T18:11:19.058Z","2.5.0-alpha.28":"2021-09-30T21:35:54.193Z","2.5.0-alpha.29":"2021-09-30T21:49:35.401Z","2.5.0-alpha.30":"2021-09-30T22:32:48.837Z","2.5.0-alpha.32":"2021-10-03T00:21:18.544Z","2.5.0-alpha.33":"2021-10-03T01:14:38.483Z","2.5.0-alpha.34":"2021-10-03T01:17:34.243Z","2.5.0-alpha.35":"2021-10-03T01:22:10.009Z","2.5.0-alpha.36":"2021-10-03T04:08:28.870Z","2.5.0-alpha.37":"2021-10-03T04:10:19.669Z","2.5.0-alpha.38":"2021-10-03T04:22:32.924Z","2.5.0-alpha.39":"2021-10-03T04:31:51.679Z","2.5.0-alpha.40":"2021-10-04T19:46:03.967Z","2.5.0-alpha.42":"2021-10-06T18:35:03.862Z","2.5.0-alpha.43":"2021-10-06T19:23:50.519Z","2.5.0-alpha.44":"2021-10-06T19:30:27.341Z","2.5.0-alpha.46":"2021-10-06T19:52:12.235Z","2.5.0-alpha.47":"2021-10-06T21:31:33.621Z","2.5.0-alpha.48":"2021-10-06T22:00:06.282Z","2.5.0-alpha.49":"2021-10-06T22:11:47.401Z","2.5.0-alpha.50":"2021-10-06T22:15:14.464Z","2.5.0-alpha.51":"2021-10-06T22:31:08.116Z","2.5.0-alpha.52":"2021-10-06T22:35:24.161Z","2.5.0-alpha.53":"2021-11-12T19:08:14.294Z","2.5.0-alpha.54":"2021-11-12T19:08:51.418Z","2.5.0-alpha.61":"2021-12-16T21:25:23.592Z","2.5.0-alpha.62":"2022-01-13T18:54:51.692Z","2.5.0-alpha.64":"2022-03-25T15:28:56.516Z","2.5.0-alpha.65":"2022-04-06T05:08:30.283Z","2.5.0-alpha.67":"2022-04-06T05:21:15.288Z","2.5.0-alpha.68":"2022-04-06T05:26:03.139Z","2.5.0-alpha.73":"2022-05-23T17:00:03.111Z","2.5.0-alpha.74":"2022-05-23T17:08:16.367Z","2.5.0-alpha.75":"2022-05-23T17:27:33.870Z","2.5.0-alpha.76":"2022-08-02T15:26:06.924Z","2.5.0-alpha.82":"2023-01-11T16:18:15.270Z","2.5.0-alpha.83":"2023-01-12T17:21:39.407Z"},"maintainers":[{"name":"synvox","email":"ryan@allred.xyz"}],"keywords":[],"author":{"name":"Ryan Allred"},"license":"MIT","readme":"","readmeFilename":"","description":"Core client provides an ergonomic interface for working with `@synvox/core`. It is not required when using `@synvox/core`.","homepage":"https://github.com/synvox/core#readme","repository":{"type":"git","url":"git+https://github.com/synvox/core.git","directory":"client"},"bugs":{"url":"https://github.com/synvox/core/issues"}}